Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1891 lines
45 KiB

/****************************** Module Header ******************************\
* Module Name: userinit.c
*
* Copyright (c) 1991, Microsoft Corporation
*
* Userinit main module
*
* Userinit is an app executed by winlogon at user logon.
* It executes in the security context of the user and on the user desktop.
* Its purpose is to complete any user initialization that may take an
* indeterminate time. e.g. code that interacts with the user.
* This process may be terminated at any time if a shutdown is initiated
* or if the user logs off by some other means.
*
* History:
* 20-Aug-92 Davidc Created.
\***************************************************************************/
#include "userinit.h"
#include "winuserp.h"
#include <mpr.h>
#include <winnetp.h>
#include <winspool.h>
#include "winsplrp.h"
#include "msgalias.h"
#include "stringid.h"
#include "strings.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#ifdef DBCS_IME // by eichim, 10-Jul-92
#include <winnls32.h>
#include <ime.h>
#include <winnls3p.h>
#endif // DBCS_IME
//
// Define this to enable verbose output for this module
//
// #define DEBUG_USERINIT
#ifdef DEBUG_USERINIT
#define VerbosePrint(s) UIPrint(s)
#else
#define VerbosePrint(s)
#endif
//
// Define this to enable timing of userinit
//
// #define LOGGING
#ifdef LOGGING
void _WriteLog(LPCTSTR LogString);
#define WriteLog(s) _WriteLog(s)
#else
#define WriteLog(s)
#endif
//
// Define the environment variable names used to pass the logon
// server and script name from winlogon
//
#define LOGON_SERVER_VARIABLE TEXT("UserInitLogonServer")
#define LOGON_SCRIPT_VARIABLE TEXT("UserInitLogonScript")
#define MPR_LOGON_SCRIPT_VARIABLE TEXT("UserInitMprLogonScript")
//
// Volatile Environment
//
#define VOLATILE_ENVIRONMENT TEXT("Volatile Environment")
FILETIME g_LastWrite = {0,0};
BOOL RegenerateUserEnvironment(PVOID *pPrevEnv, BOOL bSetCurrentEnv);
//
// Define the path environment variable
//
#define PATH TEXT("PATH")
//
// Define path separator
//
#define PATH_SEPARATOR TEXT("\\")
//
// Directory separator in environment strings
//
#define DIRECTORY_SEPARATOR TEXT(";")
//
// Define filename extension separator
//
#define EXTENSION_SEPARATOR_CHAR TEXT('.')
//
// Define server name prefix
//
#define SERVER_PREFIX TEXT("\\\\")
//
// Define Logon script paths.
//
#define SERVER_SCRIPT_PATH TEXT("\\NETLOGON")
#define LOCAL_SCRIPT_PATH TEXT("\\repl\\import\\scripts")
#define WINLOGON_REG_PATH TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
#define SYNC_REG_VALUE_NAME TEXT("RunLogonScriptSync")
#define GRPCONV_REG_VALUE_NAME TEXT("RunGrpConv")
#define SYNCAPP_REG_VALUE_NAME TEXT("RunSyncApp")
TCHAR g_szSyncAppExe[] = TEXT("syncapp.exe");
TCHAR g_szGrpConvExe[] = TEXT("grpconv.exe -p");
//
// Define extensions that should be added to scripts without extensions
// when we go search for them. Basically this list includes those extensions
// that CreateProcess handles when they are present in the executable file
// name but must be provided by the caller (us)
// We search for a script file with these extensions in this order and
// execute the first one we find.
//
static LPTSTR ScriptExtensions[] = { TEXT(".bat"), TEXT(".cmd") };
//
// Name of registry key and value to check for temp page file.
//
TCHAR szMemMan[] =
TEXT("System\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
TCHAR szNoPageFile[] = TEXT("TempPageFile");
//
// Timeout in miliseconds to wait for AddMessageAlias to complete
//
#define TIMEOUT_VALUE (5L * 60L * 1000L)
LPTSTR
AllocAndGetEnvironmentVariable(
LPTSTR lpName
);
BOOL
ReadRegistry(
BOOL *bSync, BOOL *bConvertGrp, BOOL *bSyncApp
);
VOID
CheckControlPanelCache();
BOOL
UpdateUserEnvironment();
VOID
NewLogonNotify(VOID);
/***************************************************************************\
* ExecApplication
*
* Execs an application
*
* Returns TRUE on success, FALSE on failure.
*
* 21-Aug-92 Davidc Created.
\***************************************************************************/
BOOL
ExecApplication(
LPTSTR pch,
BOOL bFileNameOnly,
BOOL bSyncApp
)
{
STARTUPINFO si;
PROCESS_INFORMATION ProcessInformation;
BOOL Result;
//
// Initialize process startup info
//
si.cb = sizeof(STARTUPINFO);
si.lpReserved = pch; // This tells progman it's the shell!
si.lpTitle = pch;
si.lpDesktop = NULL; // Not used
si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L;
si.dwFlags = 0;
si.wShowWindow = SW_SHOW; // at least let the guy see it
si.lpReserved2 = NULL;
si.cbReserved2 = 0;
//
// Start the app
//
Result = CreateProcess(
bFileNameOnly ? pch : NULL, // Image name
bFileNameOnly ? NULL : pch, // Command line
NULL, // Default process protection
NULL, // Default thread protection
FALSE, // Don't inherit handles
NORMAL_PRIORITY_CLASS,
NULL, // Inherit environment
NULL, // Inherit current directory
&si,
&ProcessInformation
);
if (!Result) {
VerbosePrint(("Failed to execute <%S>, error = %d", pch, GetLastError()));
} else {
//
// If we are running this app synchronously, wait
// for it to terminate.
//
if (bSyncApp) {
WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
}
//
// Close our handles to the process and thread
//
CloseHandle(ProcessInformation.hProcess);
CloseHandle(ProcessInformation.hThread);
}
return(Result);
}
/***************************************************************************\
* ExecProcesses
*
* Read win.ini for a list of system processes and start them up.
*
* Returns number of processes successfully started.
*
* 21-Aug-92 Davidc Created
\***************************************************************************/
#if DEVL
BOOL bDebugProgMan;
BOOL bDebugWowExec;
#endif // DEVL
DWORD
ExecProcesses(
LPTSTR pszKeyName,
LPTSTR pszDefault
)
{
PTCHAR pchData, pchCmdLine, pchT;
DWORD cb, cbCopied;
DWORD dwExecuted = 0 ;
#if DEVL
BOOL bDebug;
TCHAR chDebugCmdLine[ MAX_PATH ];
#endif
//
// Read win.ini for the list of processes to startup
//
cb = 128;
if ((pchData = (PTCHAR)Alloc( cb * sizeof (TCHAR) )) == NULL)
return(0);
while (TRUE) {
/*
* Grab a buffer and load up the keydata under the keyname currently
* pointed to by pchKeyNames.
*/
if ((cbCopied = GetProfileString(TEXT("winlogon"), pszKeyName, pszDefault, // LATER put in res file
(LPTSTR)pchData, cb)) == 0) {
LocalFree((HLOCAL)pchData);
return(0);
}
/*
* If the returned value is our passed size - 1 (weird way for error)
* then our buffer is too small. Make it bigger and start over again.
*/
if (cbCopied == cb - 1) {
cb += 128;
if ((pchData = (PTCHAR)ReAlloc(pchData, cb * sizeof (TCHAR) )) == NULL) {
return(0);
}
continue;
}
break;
}
pchCmdLine = pchData;
while (TRUE) {
/*
* Exec all applications separated by commas.
*/
for (pchT = pchCmdLine; pchT < pchData + cbCopied; pchT++) {
if (*pchT == 0)
break;
if (*pchT == ',') {
*pchT = 0;
break;
}
}
if (*pchT != 0) {
// We've reached the end of the buffer
break;
}
/*
* Skip any leading spaces.
*/
while (*pchCmdLine == ' ') {
pchCmdLine++;
}
#if DEVL
bDebug = FALSE;
if (bDebugProgMan && !_wcsicmp( pchCmdLine, TEXT("progman") )) {
bDebug = TRUE;
}
else
if (bDebugWowExec && !_wcsicmp( pchCmdLine, TEXT("wowexec") )) {
bDebug = TRUE;
}
if (bDebug) {
wsprintf( chDebugCmdLine, TEXT("ntsd -d %S%S"),
bDebug == 2 ? TEXT("-g -G ") : TEXT(""),
pchCmdLine );
pchCmdLine = chDebugCmdLine;
}
#endif // DEVL
/*
* We have something... exec this application.
*/
if (ExecApplication(pchCmdLine, FALSE, FALSE)) {
dwExecuted++;
}
/*
* Advance to next name. Double 0 means end of names.
*/
pchCmdLine = pchT + 1;
if (*pchCmdLine == 0)
break;
}
Free(pchData);
return dwExecuted ;
}
/***************************************************************************\
* SearchAndAllocPath
*
* Version of SearchPath that allocates the return string.
*
* Returns pointer to full path of file or NULL if not found.
*
* The returned buffer should be free using Free()
*
* History:
* 09-Dec-92 Davidc Created
*
\***************************************************************************/
LPTSTR
SearchAndAllocPath(
LPTSTR lpPath,
LPTSTR lpFileName,
LPTSTR lpExtension,
LPTSTR *lpFilePart
)
{
LPTSTR Buffer;
DWORD LengthRequired;
DWORD LengthUsed;
DWORD BytesRequired;
//
// Allocate a buffer to hold the full filename
//
LengthRequired = MAX_PATH;
BytesRequired = (LengthRequired * sizeof(TCHAR));
Buffer = Alloc(BytesRequired);
if (Buffer == NULL) {
UIPrint(("SearchAndAllocPath: Failed to allocate %d bytes for file name", BytesRequired));
return(NULL);
}
//
// Go search for the file
//
LengthUsed = SearchPath(
lpPath,
lpFileName,
lpExtension,
LengthRequired,
Buffer,
lpFilePart);
if (LengthUsed == 0) {
VerbosePrint(("SearchAndAllocPath: Path <%S>, file <%S>, extension <%S> not found, error = %d", lpPath, lpFileName, lpExtension, GetLastError()));
Free(Buffer);
return(NULL);
}
if (LengthUsed > LengthRequired - 1) {
UIPrint(("SearchAndAllocPath: Unexpected result from SearchPath. Length passed = %d, length used = %d (expected %d)", LengthRequired, LengthUsed, LengthRequired - 1));
Free(Buffer);
return(NULL);
}
return(Buffer);
}
/***************************************************************************\
* ExecScript
*
* Attempts to run the command script or exe lpScript in the directory lpPath.
* If path is not specified then the default windows search path is used.
*
* This routine is basically a wrapper for CreateProcess. CreateProcess always
* assumes a .exe extension for files without extensions. It will run .cmd
* and .bat files but it keys off the .cmd and .bat extension. So we must go
* search for the file first and add the extension before calling CreateProcess.
*
* Returns TRUE if the script began executing successfully.
* Returns FALSE if we can't find the script in the path specified
* or something fails.
*
* History:
* 09-Dec-92 Davidc Created
*
\***************************************************************************/
BOOL
ExecScript(
LPTSTR lpPath OPTIONAL,
LPTSTR lpScript,
BOOL bSyncApp
)
{
BOOL Result;
DWORD i;
LPTSTR lpFullName;
DWORD BytesRequired;
//
// First try and execute the raw script file name
//
if (lpPath != NULL) {
BytesRequired = (lstrlen(lpPath) +
lstrlen(PATH_SEPARATOR) +
lstrlen(lpScript) +
1)
* sizeof(TCHAR);
lpFullName = Alloc(BytesRequired);
if (lpFullName == NULL) {
UIPrint(("ExecScript failed to allocate %d bytes for full script name", BytesRequired));
return(FALSE);
}
lstrcpy(lpFullName, lpPath);
lstrcat(lpFullName, PATH_SEPARATOR);
lstrcat(lpFullName, lpScript);
ASSERT(((lstrlen(lpFullName) + 1) * sizeof(TCHAR)) == BytesRequired);
} else {
lpFullName = lpScript;
}
//
// Let CreateProcess have a hack at the raw script path and name.
//
Result = ExecApplication(lpFullName, FALSE, bSyncApp);
//
// Free up the full name buffer
//
if (lpFullName != lpScript) {
Free(lpFullName);
}
if (!Result) {
//
// Create process couldn't find it so add each script extension in
// turn and try and execute the full script name.
//
// Only bother with this procedure if the script name doesn't
// already contain an extension
//
BOOL ExtensionPresent = FALSE;
LPTSTR p = lpScript;
while (*p) {
if (*p == EXTENSION_SEPARATOR_CHAR) {
ExtensionPresent = TRUE;
break;
}
p = CharNext(p);
}
if (ExtensionPresent) {
VerbosePrint(("ExecScript: Skipping search path because script name contains extension"));
} else {
for (i = 0; i < sizeof(ScriptExtensions)/sizeof(ScriptExtensions[0]); i++) {
lpFullName = SearchAndAllocPath(
lpPath,
lpScript,
ScriptExtensions[i],
NULL);
if (lpFullName != NULL) {
//
// We found the file, go execute it
//
Result = ExecApplication(lpFullName, FALSE, bSyncApp);
//
// Free the full path buffer
//
Free(lpFullName);
return(Result);
}
}
}
}
return(Result);
}
BOOL
PrependToPath(
IN LPTSTR lpLogonPath,
OUT LPTSTR *lpOldPath
)
{
DWORD BytesRequired;
LPTSTR lpNewPath;
//
// Prepend the address of the logon script to the path, so it can
// reference other files.
//
*lpOldPath = AllocAndGetEnvironmentVariable( PATH );
if (*lpOldPath == NULL) {
return(FALSE);
}
BytesRequired = ( lstrlen(lpLogonPath) +
lstrlen(*lpOldPath) +
2 // one for terminator, one for ';'
) * sizeof(TCHAR);
lpNewPath = (LPTSTR)Alloc(BytesRequired);
if (lpNewPath == NULL) {
UIPrint(("RunLogonScript: Failed to allocate %d bytes for modified path variable", BytesRequired));
return(FALSE);
}
lstrcpy(lpNewPath, lpLogonPath);
lstrcat(lpNewPath, DIRECTORY_SEPARATOR);
lstrcat(lpNewPath, *lpOldPath);
// Free( *lpOldPath );
ASSERT(((lstrlen(lpNewPath) + 1) * sizeof(TCHAR)) == BytesRequired);
SetEnvironmentVariable(PATH, lpNewPath);
Free(lpNewPath);
return(TRUE);
}
/***************************************************************************\
* RunLogonScript
*
* Starts the logon script
*
* Returns TRUE on success, FALSE on failure
*
* History:
* 21-Aug-92 Davidc Created
*
\***************************************************************************/
BOOL
RunLogonScript(
LPTSTR lpLogonServer OPTIONAL,
LPTSTR lpLogonScript,
BOOL bSyncApp
)
{
LPTSTR lpLogonPath;
LPTSTR lpOldPath;
DWORD BytesRequired;
BOOL Result;
//
// if the logon server exists, look for the logon scripts on
// \\<LogonServer>\NETLOGON\<ScriptName>
//
if ((lpLogonServer != NULL) && (lpLogonServer[0] != 0)) {
BytesRequired = ( lstrlen(SERVER_PREFIX) +
lstrlen(lpLogonServer) +
lstrlen(SERVER_SCRIPT_PATH) +
1
) * sizeof(TCHAR);
lpLogonPath = (LPTSTR)Alloc(BytesRequired);
if (lpLogonPath == NULL) {
UIPrint(("RunLogonScript: Failed to allocate %d bytes for remote logon script path", BytesRequired));
return(FALSE);
}
lstrcpy(lpLogonPath, SERVER_PREFIX);
lstrcat(lpLogonPath, lpLogonServer);
lstrcat(lpLogonPath, SERVER_SCRIPT_PATH);
ASSERT(((lstrlen(lpLogonPath) + 1) * sizeof(TCHAR)) == BytesRequired);
Result = PrependToPath( lpLogonPath, &lpOldPath );
if (Result) {
VerbosePrint(("Successfully prepended <%S> to path", lpLogonPath));
} else {
VerbosePrint(("Cannot prepend <%S> path.",lpLogonPath));
}
//
// Try and execute the app/script specified by lpLogonScript
// in the directory specified by lpLogonPath
//
Result = ExecScript(lpLogonPath, lpLogonScript, bSyncApp);
if (Result) {
VerbosePrint(("Successfully executed logon script <%S> in directory <%S>", lpLogonScript, lpLogonPath));
} else {
VerbosePrint(("Cannot start logon script <%S> on LogonServer <%S>. Trying local path.", lpLogonScript, lpLogonServer));
}
//
// Put the path back the way it was
//
SetEnvironmentVariable(PATH, lpOldPath);
Free(lpOldPath);
//
// Free up the buffer
//
Free(lpLogonPath);
//
// If the script started successfully we're done, otherwise
// drop through and try to find the script locally
//
if (Result) {
//
// Check that the volatile environment hasn't changed.
//
UpdateUserEnvironment();
return(TRUE);
}
}
//
// Try to find the scripts on <system dir>\repl\import\scripts\<scriptname>
//
BytesRequired = GetSystemDirectory(NULL, 0) * sizeof(TCHAR);
if (BytesRequired == 0) {
UIPrint(("RunLogonScript: GetSystemDirectory failed, error = %d", GetLastError()));
return(FALSE);
}
BytesRequired += ( lstrlen(LOCAL_SCRIPT_PATH)
// BytesRequired already includes space for terminator
) * sizeof(TCHAR);
lpLogonPath = (LPTSTR)Alloc(BytesRequired);
if (lpLogonPath == NULL) {
UIPrint(("RunLogonScript failed to allocate %d bytes for logon script path", BytesRequired));
return(FALSE);
}
Result = FALSE;
if (GetSystemDirectory(lpLogonPath, BytesRequired)) {
lstrcat(lpLogonPath, LOCAL_SCRIPT_PATH);
ASSERT(((lstrlen(lpLogonPath) + 1) * sizeof(TCHAR)) == BytesRequired);
Result = PrependToPath( lpLogonPath, &lpOldPath );
if (Result) {
VerbosePrint(("Successfully prepended <%S> to path", lpLogonPath));
} else {
VerbosePrint(("Cannot prepend <%S> path.",lpLogonPath));
}
//
// Try and execute the app/script specified by lpLogonScript
// in the directory specified by lpLogonPath
//
Result = ExecScript(lpLogonPath, lpLogonScript, bSyncApp);
if (Result) {
VerbosePrint(("Successfully executed logon script <%S> in directory <%S>", lpLogonScript, lpLogonPath));
} else {
VerbosePrint(("Cannot start logon script <%S> on local path <%S>.", lpLogonScript, lpLogonPath));
}
//
// Put the path back the way it was
//
SetEnvironmentVariable(PATH, lpOldPath);
Free(lpOldPath);
} else {
UIPrint(("RunLogonScript: GetSystemDirectory failed, error = %d", GetLastError()));
}
//
// Free up the buffer
//
Free(lpLogonPath);
//
// Check that the volatile environment hasn't changed.
//
if (Result) {
UpdateUserEnvironment();
}
return(Result);
}
/***************************************************************************\
* RunMprLogonScripts
*
* Starts the network provider logon scripts
* The passed string is a multi-sz - we exec each script in turn.
*
* Returns TRUE on success, FALSE on failure
*
* History:
* 21-Aug-92 Davidc Created
*
\***************************************************************************/
BOOL
RunMprLogonScripts(
LPTSTR lpLogonScripts,
BOOL bSyncApp
)
{
BOOL Result;
if (lpLogonScripts != NULL) {
DWORD Length;
do {
Length = lstrlen(lpLogonScripts);
if (Length != 0) {
Result = ExecScript(NULL, lpLogonScripts, bSyncApp);
if (Result) {
VerbosePrint(("Successfully executed mpr logon script <%S>", lpLogonScripts));
//
// Check that the volatile environment hasn't changed.
//
UpdateUserEnvironment();
} else {
VerbosePrint(("Cannot start mpr logon script <%S>", lpLogonScripts));
}
}
lpLogonScripts += (Length + 1);
} while (Length != 0);
}
return(TRUE);
}
/***************************************************************************\
* RestoreNetworkConnections
*
* Restores any saved network connections for the user.
*
* Returns TRUE on success, FALSE on failure.
*
* History:
* 21-Aug-92 Davidc Created
*
\***************************************************************************/
DWORD
RestoreNetworkConnections(
VOID
)
{
DWORD Error;
Error = WNetRestoreConnection(NULL, NULL);
//
// It is not an error to not be able to open the profile,
// it just means there are no saved connections
//
if (Error == ERROR_CANNOT_OPEN_PROFILE) {
Error = ERROR_SUCCESS;
}
return(Error);
}
/***************************************************************************\
* AllocAndGetEnvironmentVariable
*
* Version of GetEnvironmentVariable that allocates the return buffer.
*
* Returns pointer to environment variable or NULL on failure
*
* The returned buffer should be free using Free()
*
* History:
* 09-Dec-92 Davidc Created
*
\***************************************************************************/
LPTSTR
AllocAndGetEnvironmentVariable(
LPTSTR lpName
)
{
LPTSTR Buffer;
DWORD LengthRequired;
DWORD LengthUsed;
DWORD BytesRequired;
//
// Go search for the variable and find its length
//
LengthRequired = GetEnvironmentVariable(lpName, NULL, 0);
if (LengthRequired == 0) {
VerbosePrint(("Environment variable <%S> not found, error = %d", lpName, GetLastError()));
return(NULL);
}
//
// Allocate a buffer to hold the variable
//
BytesRequired = LengthRequired * sizeof(TCHAR);
Buffer = Alloc(BytesRequired);
if (Buffer == NULL) {
UIPrint(("Failed to allocate %d bytes for environment variable", BytesRequired));
return(NULL);
}
//
// Go get the variable and pass a buffer this time
//
LengthUsed = GetEnvironmentVariable(lpName, Buffer, LengthRequired);
if (LengthUsed == 0) {
VerbosePrint(("Environment variable <%S> not found (should have found it), error = %d", lpName, GetLastError()));
Free(Buffer);
return(NULL);
}
if (LengthUsed != LengthRequired - 1) {
UIPrint(("Unexpected result from GetEnvironmentVariable. Length passed = %d, length used = %d (expected %d)", LengthRequired, LengthUsed, LengthRequired - 1));
Free(Buffer);
return(NULL);
}
return(Buffer);
}
/***************************************************************************\
* AllocAndGetEnvironmentMultiSz
*
* Gets an environment variable's value that's assumed to be an
* encoded multi-sz and decodes it into an allocated return buffer.
* Variable should have been written with SetEnvironmentMultiSz() (winlogon)
*
* Returns pointer to environment variable or NULL on failure
*
* The returned buffer should be free using Free()
*
* History:
* 01-15-93 Davidc Created
*
\***************************************************************************/
#define TERMINATOR_REPLACEMENT TEXT(',')
LPTSTR
AllocAndGetEnvironmentMultiSz(
LPTSTR lpName
)
{
LPTSTR Buffer;
LPTSTR p, q;
Buffer = AllocAndGetEnvironmentVariable(lpName);
if (Buffer == NULL) {
return(NULL);
}
//
// Now decode the string - we can do this in place since the string
// will always get smaller
//
p = Buffer;
q = Buffer;
while (*p) {
if (*p == TERMINATOR_REPLACEMENT) {
p ++;
if (*p != TERMINATOR_REPLACEMENT) {
p --;
*p = 0;
}
}
if (p != q) {
*q = *p;
}
p ++;
q ++;
}
ASSERT(q <= p);
//
// Copy terminator
//
if (q != p) {
*q = 0;
}
return(Buffer);
}
/***************************************************************************\
* CheckVideoSelection
*
* History:
* 15-Mar-93 Andreva Created.
\***************************************************************************/
VOID
CheckVideoSelection(
HINSTANCE hInstance
)
{
//
// First check if we are in a detection mode.
// If we are, spawn the applet and let the user pick the mode.
//
// Otherwise, check to see if the display was initialized properly.
// We may want to move this to a more appropriate place at a later date.
//
// Andreva
//
NTSTATUS Status;
HANDLE HkRegistry;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
TCHAR achDispMode[512];
TCHAR achDisp[512];
TCHAR achExec[MAX_PATH];
DWORD Mesg = 0;
LPTSTR psz = NULL;
DWORD cb, dwType;
DWORD data;
//
// Check for a new driver installation
//
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet"
L"\\Control\\GraphicsDrivers\\DetectDisplay");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenKey(&HkRegistry,
GENERIC_READ | GENERIC_WRITE | DELETE,
&ObjectAttributes);
if (!NT_SUCCESS(Status)) {
//
// Check for a new driver installation
//
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet"
L"\\Control\\GraphicsDrivers\\NewDisplay");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenKey(&HkRegistry,
GENERIC_READ | GENERIC_WRITE | DELETE,
&ObjectAttributes);
if (!NT_SUCCESS(Status)) {
//
// Check for an invalid driver (like a 3.51 driver) or a badly
// configured driver.
//
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet"
L"\\Control\\GraphicsDrivers\\InvalidDisplay");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenKey(&HkRegistry,
GENERIC_READ | GENERIC_WRITE | DELETE,
&ObjectAttributes);
}
}
//
// If any of the the error keys were opened successfully, then close the
// key and spawn the applet (we only delete the invalid display key, not
// the DetectDisplay key !)
//
if (NT_SUCCESS(Status)) {
NtClose(HkRegistry);
LoadString(hInstance,
IDS_DISPLAYAPPLET,
achExec, sizeof(achExec));
ExecApplication(achExec, FALSE, TRUE);
}
}
/***************************************************************************\
* InitializeMisc
*
* History:
* 14-Jul-95 EricFlo Created.
\***************************************************************************/
void InitializeMisc (HINSTANCE hInstance)
{
HKEY hkeyMM;
DWORD dwTempFile, cbTempFile, dwType;
TCHAR achExec[MAX_PATH];
//
// Check the control panel cache
//
CheckControlPanelCache();
//
// check the page file. If there is not one, then spawn the vm applet
//
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szMemMan, 0, KEY_READ,
&hkeyMM) == ERROR_SUCCESS) {
cbTempFile = sizeof(dwTempFile);
if (RegQueryValueEx (hkeyMM, szNoPageFile, NULL, &dwType,
(LPBYTE) &dwTempFile, &cbTempFile) != ERROR_SUCCESS ||
dwType != REG_DWORD || cbTempFile != sizeof(dwTempFile)) {
dwTempFile = 0;
}
RegCloseKey(hkeyMM);
} else
dwTempFile = 0;
if (dwTempFile == 1) {
LoadString(hInstance, IDS_VMAPPLET, achExec, sizeof(achExec));
ExecProcesses(TEXT("vmapplet"), achExec);
}
//
// Tell the user if he has an invalid video selection.
//
CheckVideoSelection(hInstance);
//
// Attempt to intialize the spooler. If the spooler isn't running,
// then it will initialize itself when it starts.
//
SpoolerInit();
//
// Notify other system components that a new
// user has logged into the workstation.
//
NewLogonNotify();
}
/***************************************************************************\
* HandleLogonScripts
*
* History:
* 14-Jul-95 EricFlo Created.
\***************************************************************************/
void HandleLogonScripts (BOOL bRunLogonScriptsSync)
{
LPTSTR lpLogonServer;
LPTSTR lpLogonScript;
LPTSTR lpMprLogonScripts;
//
// Execute the logon script
//
// Get the logon server and script name out of the environment
// variables, then delete these variables so child processes
// don't inherit them.
//
lpLogonServer = AllocAndGetEnvironmentVariable(LOGON_SERVER_VARIABLE);
lpLogonScript = AllocAndGetEnvironmentVariable(LOGON_SCRIPT_VARIABLE);
lpMprLogonScripts = AllocAndGetEnvironmentMultiSz(MPR_LOGON_SCRIPT_VARIABLE);
//
// Delete the logon script environment variables
//
SetEnvironmentVariable(LOGON_SERVER_VARIABLE, NULL);
SetEnvironmentVariable(LOGON_SCRIPT_VARIABLE, NULL);
SetEnvironmentVariable(MPR_LOGON_SCRIPT_VARIABLE, NULL);
//
// Run the script
//
if (lpLogonScript != NULL) {
WriteLog( TEXT("Userinit: Running logon script"));
RunLogonScript(lpLogonServer, lpLogonScript, bRunLogonScriptsSync);
}
//
// Run the provider scripts
//
if (lpMprLogonScripts != NULL) {
WriteLog( TEXT("Userinit: Running provider scripts"));
RunMprLogonScripts(lpMprLogonScripts, bRunLogonScriptsSync);
}
//
// Free up the buffers
//
Free(lpLogonServer);
Free(lpLogonScript);
Free(lpMprLogonScripts);
}
#ifdef LOGGING
#define DATEFORMAT TEXT("%d-%d %.2d:%.2d:%.2d:%.3d ")
/***************************************************************************\
* _WriteLog
*
* History:
* 22-Mar-93 Robertre Created.
\***************************************************************************/
void
_WriteLog(
LPCTSTR LogString
)
{
TCHAR Buffer[MAX_PATH];
SYSTEMTIME st;
TCHAR FormatString[MAX_PATH];
lstrcpy( FormatString, DATEFORMAT );
lstrcat( FormatString, LogString );
lstrcat( FormatString, TEXT("\r\n") );
GetLocalTime( &st );
//
// Construct the message
//
wsprintf( Buffer,
FormatString,
st.wMonth,
st.wDay,
st.wHour,
st.wMinute,
st.wSecond,
st.wMilliseconds
);
OutputDebugString (Buffer);
}
#endif
DWORD
WINAPI
AddToMessageAlias(
PVOID IgnoreParam
)
/***************************************************************************\
* AddToMessageAlias
*
* History:
* 10-Apr-93 Robertre Created.
\***************************************************************************/
{
WCHAR UserName[MAX_PATH + 1];
DWORD UserNameLength = sizeof(UserName) / sizeof(*UserName);
//
// Add the user's msg alias.
//
WriteLog(TEXT("Userinit: Adding MsgAlias"));
if (GetUserNameW(UserName, &UserNameLength)) {
AddMsgAlias(UserName);
} else {
UIPrint(("GetUserName failed, error = %d",GetLastError()));
}
WriteLog( TEXT("Userinit: Finished adding MsgAlias"));
return( NO_ERROR );
}
/***************************************************************************\
* WinMain
*
* History:
* 20-Aug-92 Davidc Created.
\***************************************************************************/
int
WINAPI
WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdParam,
int nCmdShow
)
{
DWORD Error;
DWORD ThreadId;
DWORD WaitResult;
HANDLE ThreadHandle;
HANDLE MiscThreadHandle;
BOOL bRunLogonScriptsSync;
BOOL bRunGrpConv;
BOOL bRunSyncApp;
WriteLog(TEXT("Userinit: Starting"));
//
// Read the registry settings.
//
ReadRegistry(&bRunLogonScriptsSync, &bRunGrpConv, &bRunSyncApp);
WriteLog(TEXT("Userinit: Finished reading the registry, restoring network connections"));
//
// Restore the user's network connections
//
Error = RestoreNetworkConnections();
if (Error != ERROR_SUCCESS) {
UIPrint(("Failed to restore network connections, error = %d", Error));
}
WriteLog( TEXT("Userinit: Finished restoring connections, loading fonts"));
//
// net connections have been restored, so we can reload fonts
// from the "Fonts" section of the registry that are on the net
//
LoadRemoteFonts();
WriteLog(TEXT("Userinit: Finished loading fonts, running grpconv"));
//
// Run grpconv.exe if requested
//
if (bRunGrpConv) {
WriteLog(TEXT("Userinit: Running grpconv.exe"));
ExecApplication(g_szGrpConvExe, FALSE, TRUE);
}
WriteLog(TEXT("Userinit: Finished running grpconv, running syncapp"));
//
// Run syncapp.exe if requested
//
if (bRunSyncApp) {
WriteLog(TEXT("Userinit: Running syncapp.exe"));
ExecApplication(g_szSyncAppExe, FALSE, FALSE);
}
WriteLog(TEXT("Userinit: Finished running syncapp, running logon scripts"));
//
// Take care of any logon scripts
//
HandleLogonScripts (bRunLogonScriptsSync);
WriteLog(TEXT("Userinit: Finished running logon scripts, initialize misc stuff"));
//
// Initialize misc stuff
//
MiscThreadHandle = CreateThread (NULL, 0,
(LPTHREAD_START_ROUTINE) InitializeMisc,
hInstance, 0, &ThreadId);
if (!MiscThreadHandle) {
InitializeMisc (hInstance);
}
WriteLog( TEXT("Userinit: Finished initializing misc stuff, starting shell"));
ExecProcesses(TEXT("shell"), TEXT("explorer"));
WriteLog( TEXT("Userinit: Shell started"));
#ifdef DBCS_IME
// Start MSIME process here. We cannot start it earlier because the
// HKEY_CURRENT_USER has not been determined and since MSIME is running
// at HIGH_PRIORITY_CLASS it quickly writes initialization data to the
// registry. If the HKEY_CURRENT_USER hasn't been setup then it defaults
// to writing to HKEY_USERS\.DEFAULT which is unacceptable.
{
IMEPRO ImePro;
if (IMPGetIME((HWND)-1, &ImePro)) {
IMPSetIME((HWND)-1, &ImePro);
}
}
#endif // DBCS_IME
ThreadHandle = CreateThread(
NULL,
0,
AddToMessageAlias,
0,
0,
&ThreadId
);
WaitResult = WaitForSingleObject( ThreadHandle, TIMEOUT_VALUE );
if ( WaitResult == WAIT_TIMEOUT ) {
//
// This may never come back, so kill it.
//
UIPrint(("UserInit: AddToMessageAlias timeout, terminating thread\n"));
TerminateThread( ThreadHandle, 0L );
}
CloseHandle( ThreadHandle );
if (MiscThreadHandle) {
WaitForSingleObject( MiscThreadHandle, INFINITE );
CloseHandle (MiscThreadHandle);
}
//
// We're finished
//
return(0);
}
VOID
CheckControlPanelCache()
{
WCHAR *pszRegCache;
WCHAR *pszCacheValid;
HKEY hkeyRCache = NULL;
DWORD j = 0;
DWORD dwSize;
DWORD dwType;
DWORD dwDisposition;
LONG Err;
pszRegCache = L"Control Panel\\Cache";
pszCacheValid = L"Cache Valid";
//
// Check "Cache Valid" flag
//
Err = RegCreateKeyExW(
HKEY_CURRENT_USER, // Root key
pszRegCache, // Subkey to open/create
0L, // Reserved
NULL, // Class string
0L, // Options
KEY_ALL_ACCESS, // SAM
NULL, // ptr to Security struct
&hkeyRCache, // return handle
&dwDisposition // return disposition
);
if (Err == ERROR_SUCCESS ) {
Err = RegQueryValueExW(hkeyRCache,pszCacheValid,0L,&dwType,(LPBYTE) &j,&dwSize);
if (Err != ERROR_SUCCESS) {
j = 0;
}
RegCloseKey(hkeyRCache);
}
else {
j = 0;
}
if ( !j ) {
ExecProcesses(TEXT("controlbuild"), TEXT("control /Build"));
}
}
BOOL ReadRegistry(BOOL *bSync, BOOL *bConvertGrp, BOOL *bSyncApp)
{
BOOL bSyncScript = FALSE;
BOOL bGrpConv = FALSE;
BOOL bRunSyncApp = FALSE;
BOOL bTemp = FALSE;
HKEY hKey;
DWORD dwDisp, dwType, dwSize;
//
// Open the winlogon registry key in HKEY_CURRENT_USER
//
if (RegCreateKeyEx (HKEY_CURRENT_USER,
WINLOGON_REG_PATH,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwDisp) == ERROR_SUCCESS) {
//
// Check for the sync flag.
//
dwSize = sizeof(BOOL);
if (RegQueryValueEx (hKey,
SYNC_REG_VALUE_NAME,
NULL,
&dwType,
(LPBYTE) &bSyncScript,
&dwSize) != ERROR_SUCCESS) {
//
// We were unable to get the value,
// set it for future reference.
//
RegSetValueEx (hKey,
SYNC_REG_VALUE_NAME,
0,
REG_DWORD,
(CONST BYTE *)&bSyncScript,
sizeof (bSyncScript));
}
//
// Check for the group conversion flag.
//
dwSize = sizeof(BOOL);
if (RegQueryValueEx (hKey,
GRPCONV_REG_VALUE_NAME,
NULL,
&dwType,
(LPBYTE) &bGrpConv,
&dwSize) == ERROR_SUCCESS) {
//
// Remove the flag if found.
//
RegDeleteValue (hKey, GRPCONV_REG_VALUE_NAME);
}
//
// Check for the SyncApp flag.
//
dwSize = sizeof(BOOL);
if (RegQueryValueEx (hKey,
SYNCAPP_REG_VALUE_NAME,
NULL,
&dwType,
(LPBYTE) &bRunSyncApp,
&dwSize) == ERROR_SUCCESS) {
//
// Remove the flag if found.
//
RegDeleteValue (hKey, SYNCAPP_REG_VALUE_NAME);
}
RegCloseKey (hKey);
}
*bSync = bSyncScript;
*bConvertGrp = bGrpConv;
*bSyncApp = bRunSyncApp;
//
// Now check if the run logon script sync flag is in the
// local machine registry. If so, then this overrides
// the value set in current user.
//
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
WINLOGON_REG_PATH,
0,
KEY_READ,
&hKey) == ERROR_SUCCESS) {
//
// Check for the sync flag.
//
dwSize = sizeof(BOOL);
if (RegQueryValueEx (hKey,
SYNC_REG_VALUE_NAME,
NULL,
&dwType,
(LPBYTE) &bSyncScript,
&dwSize) == ERROR_SUCCESS) {
//
// Save this value
//
*bSync = bSyncScript;
}
RegCloseKey (hKey);
}
return TRUE;
}
//
// This function checks if a volatile environment section
// exists in the registry, and if so does the environment
// need to be updated.
//
BOOL UpdateUserEnvironment (void)
{
PVOID pEnv;
HKEY hKey;
DWORD dwDisp, dwType, dwSize;
BOOL bRebuildEnv = FALSE;
TCHAR szClass[MAX_PATH];
DWORD cchClass, dwSubKeys, dwMaxSubKey, dwMaxClass,dwValues;
DWORD dwMaxValueName, dwMaxValueData, dwSecurityDescriptor;
FILETIME LastWrite;
//
// Attempt to open the Volatile Environment key
//
if (RegOpenKeyEx (HKEY_CURRENT_USER,
VOLATILE_ENVIRONMENT,
0,
KEY_READ,
&hKey) == ERROR_SUCCESS) {
//
// Query the key information for the LastWrite time.
// This way we can update the environment only when
// we really need to.
//
cchClass = MAX_PATH;
if (RegQueryInfoKey(hKey,
szClass,
&cchClass,
NULL,
&dwSubKeys,
&dwMaxSubKey,
&dwMaxClass,
&dwValues,
&dwMaxValueName,
&dwMaxValueData,
&dwSecurityDescriptor,
&LastWrite) == ERROR_SUCCESS) {
//
// If we haven't checked this key before,
// then just store the values for next time.
//
if (g_LastWrite.dwLowDateTime == 0) {
g_LastWrite.dwLowDateTime = LastWrite.dwLowDateTime;
g_LastWrite.dwHighDateTime = LastWrite.dwHighDateTime;
bRebuildEnv = TRUE;
} else {
//
// Compare the last write times.
//
if (CompareFileTime (&LastWrite, &g_LastWrite) == 1) {
g_LastWrite.dwLowDateTime = LastWrite.dwLowDateTime;
g_LastWrite.dwHighDateTime = LastWrite.dwHighDateTime;
bRebuildEnv = TRUE;
}
}
}
RegCloseKey (hKey);
}
//
// Check if we need to rebuild the environment
//
if (bRebuildEnv) {
RegenerateUserEnvironment(&pEnv, TRUE);
}
return TRUE;
}
//
// Notify various components that a new user
// has logged into the workstation. We need
// to make the method of registration more
// generic, like the the way mpr notifyees
// are done via the registry.
//
VOID
NewLogonNotify(
VOID
)
{
FARPROC lpProc;
HMODULE hLib = NULL;
BOOL Status = FALSE;
HANDLE hEvent;
//---------------------------------------------------------------------
// NOTE: This init routine is called before the HKEY_CURRENT_USER key
// is setup and before the shell is up. PaulaT
//---------------------------------------------------------------------
//
// load the client-side user-mode PnP manager DLL
//
hLib = LoadLibrary(TEXT("cfgmgr32.dll"));
if (hLib != NULL) {
lpProc = GetProcAddress(hLib, "CMP_Report_LogOn");
if (lpProc != NULL) {
//
// Ping the user-mode pnp manager -
// pass the private id as a parameter
//
Status = (lpProc)(0x07020420);
}
FreeLibrary(hLib);
}
//
// Notify RAS Autodial service that a new
// user has logged in.
//
hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, L"RasAutodialNewLogonUser");
if (hEvent != NULL) {
SetEvent(hEvent);
CloseHandle(hEvent);
}
} // NewLogonNotify