2956 lines
76 KiB
C
2956 lines
76 KiB
C
/****************************** 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 <winsprlp.h>
|
|
#include "msgalias.h"
|
|
#include "stringid.h"
|
|
#include "strings.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <shellapi.h>
|
|
#include <regapi.h>
|
|
#include <dsgetdc.h>
|
|
#include <lm.h>
|
|
#include "helpmsg.h" // for HelpMessageBox
|
|
|
|
/****************************************************************************
|
|
IsTSAppCompatOn()
|
|
Purpose:
|
|
Checks if TS application compatibility is enabled.
|
|
returns TRUE if enabled, FALSE - if not enabled or on case of error.
|
|
Comments:
|
|
This function goes to the registry only once.
|
|
All other times it just returnes the value.
|
|
****************************************************************************/
|
|
BOOL IsTSAppCompatOn();
|
|
|
|
//
|
|
// 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")
|
|
#define GPO_SCRIPT_TYPE_VARIABLE TEXT("UserInitGPOScriptType")
|
|
#define OPTIMIZED_LOGON_VARIABLE TEXT("UserInitOptimizedLogon")
|
|
#define EVENT_SOURCE_NAME TEXT("UserInit")
|
|
#define USERDOMAIN_VARIABLE TEXT("USERDOMAIN")
|
|
#define UNC_LOGON_SERVER_VARIABLE TEXT("LOGONSERVER")
|
|
#define AUTOENROLL_VARIABLE TEXT("UserInitAutoEnroll")
|
|
#define AUTOENROLL_NONEXCLUSIVE TEXT("1")
|
|
#define AUTOENROLL_EXCLUSIVE TEXT("2")
|
|
#define AUTOENROLLMODE_VARIABLE TEXT("UserInitAutoEnrollMode")
|
|
#define AUTOENROLL_STARTUP TEXT("1")
|
|
#define AUTOENROLL_WAKEUP TEXT("2")
|
|
#define SCRIPT_ZONE_CHECK_VARIABLE TEXT("SEE_MASK_NOZONECHECKS")
|
|
#define SCRIPT_ZONE_CHECK_DISABLE TEXT("1")
|
|
|
|
//
|
|
// Define path separator
|
|
//
|
|
|
|
#define PATH_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_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
|
|
#define WINLOGON_POLICY_KEY TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System")
|
|
#define GPO_SCRIPTS_KEY TEXT("Software\\Policies\\Microsoft\\Windows\\System\\Scripts")
|
|
#define SYNC_LOGON_SCRIPT TEXT("RunLogonScriptSync")
|
|
#define SYNC_STARTUP_SCRIPT TEXT("RunStartupScriptSync")
|
|
#define GRPCONV_REG_VALUE_NAME TEXT("RunGrpConv")
|
|
|
|
//
|
|
// We cache user preference to run logon scripts synchronously
|
|
// in the machine hive so it can be checked to determine if we
|
|
// can do cached logon without having to load the user's hive.
|
|
//
|
|
|
|
#define PROFILE_LIST_PATH L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"
|
|
|
|
|
|
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");
|
|
|
|
|
|
//
|
|
// Handle to a thread that may be created to deal with autoenrollment goo.
|
|
// If this is non-null, we will wait on this thread to complete before
|
|
// terminating the process.
|
|
//
|
|
HANDLE AutoEnrollThread ;
|
|
|
|
//
|
|
// Timeout in miliseconds to wait for AddMessageAlias to complete
|
|
//
|
|
|
|
#define TIMEOUT_VALUE (5L * 60L * 1000L)
|
|
#define MAX_STRING_BYTES 512
|
|
|
|
BOOL SetupHotKeyForKeyboardLayout ();
|
|
|
|
LPTSTR
|
|
AllocAndGetEnvironmentVariable(
|
|
LPTSTR lpName
|
|
);
|
|
|
|
BOOL
|
|
RunScriptHidden(HKEY hKeyRoot, LPTSTR lpValue, BOOL bDefault);
|
|
|
|
BOOL
|
|
RunLogonScriptSync(VOID);
|
|
|
|
BOOL
|
|
RunStartupScriptSync(VOID);
|
|
|
|
BOOL
|
|
UpdateUserEnvironment(VOID);
|
|
|
|
LPWSTR
|
|
GetSidString(HANDLE UserToken);
|
|
|
|
VOID
|
|
DeleteSidString(LPWSTR SidString);
|
|
|
|
VOID
|
|
UpdateUserSyncLogonScriptsCache(BOOL bSync);
|
|
|
|
VOID
|
|
NewLogonNotify(VOID);
|
|
|
|
BOOL
|
|
RunGPOScripts(
|
|
LPTSTR lpGPOScriptType
|
|
);
|
|
|
|
void
|
|
PathUnquoteSpaces(LPTSTR lpsz);
|
|
|
|
BOOL
|
|
PrependToPath(
|
|
IN LPTSTR lpLogonPath,
|
|
OUT LPTSTR *lpOldPath
|
|
);
|
|
|
|
typedef BOOL (*PFNSHELLEXECUTEEX)(LPSHELLEXECUTEINFO lpExecInfo);
|
|
PFNSHELLEXECUTEEX g_pfnShellExecuteEx=NULL;
|
|
|
|
// If a path is contained in quotes then remove them.
|
|
void PathUnquoteSpaces(LPTSTR lpsz)
|
|
{
|
|
int cch;
|
|
|
|
cch = lstrlen(lpsz);
|
|
|
|
// Are the first and last chars quotes?
|
|
if (lpsz[0] == TEXT('"') && lpsz[cch-1] == TEXT('"'))
|
|
{
|
|
// Yep, remove them.
|
|
lpsz[cch-1] = 0;
|
|
MoveMemory(lpsz, lpsz+1, (cch-1) * sizeof(TCHAR));
|
|
}
|
|
}
|
|
|
|
// Following function determines if the machine is a Pro or Personal machine
|
|
BOOL IsPerOrProTerminalServer()
|
|
{
|
|
OSVERSIONINFOEX osVersion = {0};
|
|
|
|
osVersion.dwOSVersionInfoSize = sizeof(osVersion);
|
|
return(GetVersionEx((OSVERSIONINFO*)&osVersion) &&
|
|
(osVersion.wProductType == VER_NT_WORKSTATION) &&
|
|
(osVersion.wSuiteMask & VER_SUITE_SINGLEUSERTS));
|
|
}
|
|
|
|
//
|
|
// The 3 functions below are duplicated in gptext as well
|
|
// for running GPO scripts
|
|
//
|
|
|
|
/***************************************************************************\
|
|
* 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 = (LPTSTR) Alloc(BytesRequired);
|
|
if (Buffer == NULL) {
|
|
VerbosePrint(("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) {
|
|
VerbosePrint(("Unexpected result from GetEnvironmentVariable. Length passed = %d, length used = %d (expected %d)", LengthRequired, LengthUsed, LengthRequired - 1));
|
|
Free(Buffer);
|
|
return(NULL);
|
|
}
|
|
|
|
return(Buffer);
|
|
}
|
|
|
|
//
|
|
// Directory separator in environment strings
|
|
//
|
|
|
|
#define DIRECTORY_SEPARATOR TEXT(";")
|
|
|
|
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) {
|
|
VerbosePrint(("PrependToPath: 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);
|
|
}
|
|
|
|
//
|
|
// Volatile Environment
|
|
//
|
|
|
|
#define VOLATILE_ENVIRONMENT TEXT("Volatile Environment")
|
|
|
|
FILETIME g_LastWrite = {0,0};
|
|
|
|
typedef BOOL (WINAPI *PFNREGENERATEUSERENVIRONMENT) (
|
|
PVOID pPrevEnv, BOOL bSetCurrentEnv);
|
|
|
|
|
|
//
|
|
// 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) {
|
|
HINSTANCE hInst;
|
|
PFNREGENERATEUSERENVIRONMENT pRegUserEnv;
|
|
|
|
hInst = LoadLibrary (TEXT("shell32.dll"));
|
|
|
|
if (hInst) {
|
|
pRegUserEnv = (PFNREGENERATEUSERENVIRONMENT) GetProcAddress(hInst, "RegenerateUserEnvironment");
|
|
|
|
if (pRegUserEnv) {
|
|
(*pRegUserEnv) (&pEnv, TRUE);
|
|
}
|
|
|
|
FreeLibrary (hInst);
|
|
}
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// returns a pointer to the arguments in a cmd type path or pointer to
|
|
// NULL if no args exist
|
|
//
|
|
// foo.exe bar.txt -> bar.txt
|
|
// foo.exe -> ""
|
|
//
|
|
// Spaces in filenames must be quoted.
|
|
// "A long name.txt" bar.txt -> bar.txt
|
|
|
|
LPTSTR GetArgs(LPCTSTR pszPath)
|
|
{
|
|
BOOL fInQuotes = FALSE;
|
|
|
|
if (!pszPath)
|
|
return NULL;
|
|
|
|
while (*pszPath)
|
|
{
|
|
if (*pszPath == TEXT('"'))
|
|
fInQuotes = !fInQuotes;
|
|
else if (!fInQuotes && *pszPath == TEXT(' '))
|
|
return (LPTSTR)pszPath;
|
|
pszPath = CharNext(pszPath);
|
|
}
|
|
|
|
return (LPTSTR)pszPath;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ExecApplication
|
|
*
|
|
* Execs an application
|
|
*
|
|
* Returns TRUE on success, FALSE on failure.
|
|
*
|
|
* 21-Aug-92 Davidc Created.
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
ExecApplication(
|
|
LPTSTR pch,
|
|
BOOL bFileNameOnly,
|
|
BOOL bSyncApp,
|
|
BOOL bShellExec,
|
|
USHORT ShowState
|
|
)
|
|
{
|
|
BOOL Result;
|
|
WCHAR Localpch[ MAX_PATH+1 ];
|
|
BOOL IsProcessExplorer = FALSE;
|
|
|
|
if ( (_wcsicmp( pch, L"explorer" ) == 0) ||
|
|
(_wcsicmp( pch, L"explorer.exe" ) == 0 ) )
|
|
{
|
|
//
|
|
// Explorer.exe might not be in the right spot on the path. Let's wire
|
|
// it to the right spot.
|
|
//
|
|
|
|
IsProcessExplorer = TRUE ;
|
|
if ( ExpandEnvironmentStrings( L"%SystemRoot%\\Explorer.EXE", Localpch, MAX_PATH ) )
|
|
{
|
|
pch = Localpch ;
|
|
}
|
|
WriteLog( TEXT("Changed explorer.exe to") );
|
|
WriteLog( pch );
|
|
}
|
|
else
|
|
{
|
|
if ( ExpandEnvironmentStrings( pch, Localpch, MAX_PATH ) )
|
|
{
|
|
pch = Localpch;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Applications can be launched via ShellExecuteEx or CreateProcess
|
|
//
|
|
|
|
if (bShellExec)
|
|
{
|
|
SHELLEXECUTEINFO ExecInfo;
|
|
LPTSTR lpArgs = NULL;
|
|
LPTSTR lpTemp;
|
|
HINSTANCE hShell32;
|
|
|
|
if (!g_pfnShellExecuteEx) {
|
|
|
|
Result = FALSE;
|
|
|
|
hShell32 = LoadLibrary(TEXT("shell32.dll"));
|
|
// this handle is not closed..
|
|
|
|
if (hShell32) {
|
|
#ifdef UNICODE
|
|
g_pfnShellExecuteEx = (PFNSHELLEXECUTEEX)GetProcAddress(hShell32, "ShellExecuteExW");
|
|
#else
|
|
g_pfnShellExecuteEx = (PFNSHELLEXECUTEEX)GetProcAddress(hShell32, "ShellExecuteExA");
|
|
#endif
|
|
|
|
if (g_pfnShellExecuteEx) {
|
|
Result = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Result = TRUE;
|
|
}
|
|
|
|
if (Result) {
|
|
lpTemp = LocalAlloc (LPTR, (lstrlen(pch) + 1) * sizeof(TCHAR));
|
|
|
|
if (!lpTemp) {
|
|
return FALSE;
|
|
}
|
|
|
|
lstrcpy (lpTemp, pch);
|
|
|
|
if (!bFileNameOnly) {
|
|
lpArgs = GetArgs (lpTemp);
|
|
|
|
if (lpArgs) {
|
|
if (*lpArgs) {
|
|
*lpArgs = TEXT('\0');
|
|
lpArgs++;
|
|
} else {
|
|
lpArgs = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
PathUnquoteSpaces(lpTemp);
|
|
|
|
ZeroMemory(&ExecInfo, sizeof(ExecInfo));
|
|
ExecInfo.cbSize = sizeof(ExecInfo);
|
|
ExecInfo.fMask = SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI |
|
|
SEE_MASK_NOCLOSEPROCESS;
|
|
ExecInfo.lpFile = lpTemp;
|
|
ExecInfo.lpParameters = lpArgs;
|
|
ExecInfo.nShow = ShowState;
|
|
ExecInfo.lpVerb = TEXT("open");
|
|
|
|
|
|
|
|
Result = g_pfnShellExecuteEx (&ExecInfo);
|
|
|
|
if (Result) {
|
|
|
|
//
|
|
// If we are running this app synchronously, wait
|
|
// for it to terminate.
|
|
//
|
|
|
|
if (bSyncApp) {
|
|
WaitForSingleObject(ExecInfo.hProcess, INFINITE);
|
|
}
|
|
|
|
//
|
|
// Close our handles to the process and thread
|
|
//
|
|
|
|
CloseHandle(ExecInfo.hProcess);
|
|
|
|
}
|
|
|
|
LocalFree (lpTemp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION ProcessInformation;
|
|
|
|
|
|
//
|
|
// 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 = STARTF_USESHOWWINDOW;
|
|
si.wShowWindow = ShowState;
|
|
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()));
|
|
// TS : For non console sessions, a app restriting process like AppSec or SAFER might not allow explorer.exe for remote session
|
|
// In this case we cannot leave a Blue screen hanging around - so we should log-off in this case
|
|
// Also we want this only for Server or Advanced Server where this scenario is relevant
|
|
if ( IsPerOrProTerminalServer() == FALSE) {
|
|
if ((NtCurrentPeb()->SessionId != 0) && (IsProcessExplorer == TRUE)) {
|
|
TCHAR Title[MAX_STRING_BYTES];
|
|
TCHAR Message[MAX_STRING_BYTES];
|
|
|
|
#if DBG
|
|
DbgPrint("Userinit : TS : Failed to launch explorer.exe for a Remote Session. Doing ExitWindowsEx to logoff. \n");
|
|
#endif
|
|
|
|
// Display a MessageBox saying why we log off
|
|
LoadString( NULL, IDS_LOGON_FAILED, Title, MAX_STRING_BYTES );
|
|
LoadString(NULL, IDS_ERROR_SHELL_FAILED, Message, MAX_STRING_BYTES );
|
|
MessageBox(NULL, Message, Title, MB_OK);
|
|
ExitWindowsEx(EWX_LOGOFF, 0);
|
|
}
|
|
}
|
|
} 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 the registry for a list of system processes and start them up.
|
|
*
|
|
* Returns number of processes successfully started.
|
|
*
|
|
* 3-Mar-97 Eric Flo Rewrote
|
|
\***************************************************************************/
|
|
|
|
DWORD
|
|
ExecProcesses(
|
|
LPTSTR pszKeyName,
|
|
LPTSTR pszDefault,
|
|
BOOL bMachine,
|
|
BOOL bSync, // Should we wait until the process finish?
|
|
BOOL bMinimize // Should we use the SW_SHOWMINNOACTIVE flag
|
|
)
|
|
{
|
|
LPTSTR pchData, pchCmdLine, pchT;
|
|
DWORD cbCopied;
|
|
DWORD dwExecuted = 0 ;
|
|
HKEY hKey;
|
|
DWORD dwType, dwSize = (MAX_PATH * sizeof(TCHAR));
|
|
USHORT showstate = (UINT) (bMinimize ? SW_SHOWMINNOACTIVE : SW_SHOWNORMAL);
|
|
|
|
//
|
|
// Alloc a buffer to work with
|
|
//
|
|
|
|
pchData = LocalAlloc (LPTR, dwSize);
|
|
|
|
if (!pchData) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Set the default value
|
|
//
|
|
|
|
if (pszDefault) {
|
|
lstrcpy (pchData, pszDefault);
|
|
}
|
|
|
|
|
|
//
|
|
// Check for the requested value in the registry.
|
|
//
|
|
|
|
if (RegOpenKeyEx ((bMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER),
|
|
WINLOGON_KEY,
|
|
0, KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
RegQueryValueEx (hKey, pszKeyName, NULL, &dwType, (LPBYTE) pchData, &dwSize);
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// Check for policy override if this is a user action
|
|
//
|
|
|
|
if (!bMachine)
|
|
{
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER, WINLOGON_POLICY_KEY,
|
|
0, KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
RegQueryValueEx (hKey, pszKeyName, NULL, &dwType, (LPBYTE) pchData, &dwSize);
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If the command line(s) is still null, exit now.
|
|
//
|
|
|
|
if (*pchData == TEXT('\0')) {
|
|
LocalFree(pchData);
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Walk through the command line(s) executing the app(s)
|
|
//
|
|
|
|
pchCmdLine = pchT = pchData;
|
|
|
|
while (*pchT) {
|
|
|
|
while (*pchT && *pchT != TEXT(',')) {
|
|
pchT++;
|
|
}
|
|
|
|
if (*pchT == ',') {
|
|
*pchT = TEXT('\0');
|
|
pchT++;
|
|
}
|
|
|
|
//
|
|
// Skip any leading spaces.
|
|
//
|
|
|
|
while (*pchCmdLine == TEXT(' ')) {
|
|
pchCmdLine++;
|
|
}
|
|
|
|
|
|
//
|
|
// We have something... exec this application.
|
|
//
|
|
|
|
if (ExecApplication(pchCmdLine, FALSE, bSync, FALSE, showstate)) {
|
|
dwExecuted++;
|
|
}
|
|
|
|
pchCmdLine = pchT;
|
|
}
|
|
|
|
LocalFree(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);
|
|
}
|
|
|
|
BOOL
|
|
DisableScriptZoneSecurityCheck()
|
|
{
|
|
BOOL bSucceeded;
|
|
|
|
//
|
|
// To make the shell skip the zone security check for launching scripts, we use
|
|
// a special environment variable honored by the shell for this purpose and
|
|
// set it to a specific value
|
|
//
|
|
bSucceeded = SetEnvironmentVariable(SCRIPT_ZONE_CHECK_VARIABLE, SCRIPT_ZONE_CHECK_DISABLE);
|
|
|
|
return bSucceeded;
|
|
}
|
|
|
|
BOOL
|
|
EnableScriptZoneSecurityCheck()
|
|
{
|
|
BOOL bSucceeded;
|
|
|
|
//
|
|
// Clear the environment variable that disables the security check
|
|
//
|
|
bSucceeded = SetEnvironmentVariable(SCRIPT_ZONE_CHECK_VARIABLE, NULL);
|
|
|
|
if ( ! bSucceeded )
|
|
{
|
|
//
|
|
// If we failed to clear it, it may be that this is because the
|
|
// environment variable wasn't set in the first place, in which
|
|
// case we can ignore the error since we are in the desired state
|
|
//
|
|
LONG Status = GetLastError();
|
|
|
|
if ( ERROR_ENVVAR_NOT_FOUND == Status )
|
|
{
|
|
bSucceeded = TRUE;
|
|
}
|
|
}
|
|
|
|
return bSucceeded;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* 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 bShellExec
|
|
)
|
|
{
|
|
BOOL Result;
|
|
DWORD i;
|
|
USHORT uFlags;
|
|
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;
|
|
}
|
|
|
|
|
|
uFlags = SW_SHOWNORMAL;
|
|
|
|
if (!bSyncApp) {
|
|
uFlags |= SW_SHOWMINNOACTIVE;
|
|
}
|
|
|
|
if (RunScriptHidden(HKEY_CURRENT_USER, TEXT("HideLegacyLogonScripts"), FALSE)) {
|
|
uFlags = SW_HIDE;
|
|
}
|
|
|
|
//
|
|
// Let CreateProcess have a hack at the raw script path and name.
|
|
//
|
|
|
|
Result = ExecApplication(lpFullName, FALSE, bSyncApp, bShellExec, uFlags);
|
|
|
|
|
|
//
|
|
// 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, bShellExec, uFlags);
|
|
|
|
//
|
|
// Free the full path buffer
|
|
//
|
|
|
|
Free(lpFullName);
|
|
|
|
return(Result);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return(Result);
|
|
}
|
|
|
|
BOOL RunScriptHidden(HKEY hKeyRoot, LPTSTR lpValue, BOOL bDefault)
|
|
{
|
|
BOOL bResult;
|
|
HKEY hKey;
|
|
DWORD dwType, dwSize;
|
|
|
|
|
|
//
|
|
// Set the default
|
|
//
|
|
|
|
bResult = bDefault;
|
|
|
|
|
|
//
|
|
// Check for a preference
|
|
//
|
|
|
|
if (RegOpenKeyEx (hKeyRoot, WINLOGON_KEY, 0,
|
|
KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof(bResult);
|
|
RegQueryValueEx (hKey, lpValue, NULL, &dwType,
|
|
(LPBYTE) &bResult, &dwSize);
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// Check for a policy
|
|
//
|
|
|
|
if (RegOpenKeyEx (hKeyRoot, WINLOGON_POLICY_KEY, 0,
|
|
KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof(bResult);
|
|
RegQueryValueEx (hKey, lpValue, NULL, &dwType,
|
|
(LPBYTE) &bResult, &dwSize);
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* 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,
|
|
BOOL bShellExec
|
|
)
|
|
{
|
|
LPTSTR lpLogonPath;
|
|
LPTSTR lpOldPath;
|
|
DWORD BytesRequired;
|
|
BOOL Result;
|
|
WIN32_FILE_ATTRIBUTE_DATA fad;
|
|
|
|
|
|
if (!lpLogonScript) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
|
|
if (GetFileAttributesEx (lpLogonPath, GetFileExInfoStandard, &fad)) {
|
|
|
|
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, bShellExec);
|
|
|
|
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);
|
|
|
|
} else {
|
|
Result = FALSE;
|
|
}
|
|
|
|
//
|
|
// 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) {
|
|
|
|
if (bSyncApp) {
|
|
//
|
|
// 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, bShellExec);
|
|
|
|
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 && bSyncApp) {
|
|
UpdateUserEnvironment();
|
|
}
|
|
|
|
return(Result);
|
|
}
|
|
|
|
#define SCR_STARTUP L"Startup"
|
|
#define SCR_SHUTDOWN L"Shutdown"
|
|
#define SCR_LOGON L"Logon"
|
|
#define SCR_LOGOFF L"Logoff"
|
|
|
|
DWORD
|
|
ScrExecGPOListFromReg( LPWSTR szType,
|
|
BOOL bMachine,
|
|
BOOL bSync,
|
|
BOOL bHidden,
|
|
BOOL bRunMin,
|
|
HANDLE hEventLog );
|
|
|
|
BOOL
|
|
RunGPOScripts(
|
|
LPTSTR lpGPOScriptType
|
|
)
|
|
{
|
|
HKEY hKeyScripts;
|
|
HKEY hKeyRoot;
|
|
BOOL bSync = TRUE;
|
|
BOOL bRunMin = TRUE;
|
|
BOOL bHide;
|
|
HANDLE hEventLog = NULL;
|
|
BOOL bMachine;
|
|
BOOL bResult;
|
|
DWORD dwError;
|
|
|
|
//
|
|
// Ensure that the shell's checks for ie zones are disabled
|
|
// since this script is trusted by an administrator to execute
|
|
//
|
|
bResult = DisableScriptZoneSecurityCheck();
|
|
|
|
if ( ! bResult )
|
|
{
|
|
goto RunGPOScripts_exit;
|
|
}
|
|
|
|
//
|
|
// Register with Event Log
|
|
//
|
|
hEventLog = RegisterEventSource( 0, EVENT_SOURCE_NAME );
|
|
|
|
//
|
|
// Preliminary work to see if the scripts should be
|
|
// run sync or async and to decide what the appropriate
|
|
// root key is
|
|
//
|
|
|
|
if (!lstrcmpi (lpGPOScriptType, SCR_LOGON ))
|
|
{
|
|
hKeyRoot = HKEY_CURRENT_USER;
|
|
bHide = RunScriptHidden(hKeyRoot, TEXT("HideLogonScripts"), TRUE);
|
|
bSync = RunLogonScriptSync();
|
|
bMachine = FALSE;
|
|
if (bSync && !bHide)
|
|
{
|
|
bRunMin = FALSE;
|
|
}
|
|
}
|
|
else if (!lstrcmpi (lpGPOScriptType, SCR_LOGOFF ))
|
|
{
|
|
hKeyRoot = HKEY_CURRENT_USER;
|
|
bHide = RunScriptHidden(hKeyRoot, TEXT("HideLogoffScripts"), TRUE);
|
|
bMachine = FALSE;
|
|
if (!bHide)
|
|
{
|
|
bRunMin = FALSE;
|
|
}
|
|
}
|
|
else if (!lstrcmpi (lpGPOScriptType, SCR_STARTUP ))
|
|
{
|
|
hKeyRoot = HKEY_LOCAL_MACHINE;
|
|
bHide = RunScriptHidden(hKeyRoot, TEXT("HideStartupScripts"), TRUE);
|
|
bSync = RunStartupScriptSync();
|
|
bMachine = TRUE;
|
|
if (bSync && !bHide)
|
|
{
|
|
bRunMin = FALSE;
|
|
}
|
|
}
|
|
else if (!lstrcmpi (lpGPOScriptType, SCR_SHUTDOWN ))
|
|
{
|
|
hKeyRoot = HKEY_LOCAL_MACHINE;
|
|
bHide = RunScriptHidden(hKeyRoot, TEXT("HideShutdownScripts"), TRUE);
|
|
bMachine = TRUE;
|
|
if (!bHide)
|
|
{
|
|
bRunMin = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
dwError = ScrExecGPOListFromReg(lpGPOScriptType,
|
|
bMachine,
|
|
bSync,
|
|
bHide,
|
|
bRunMin,
|
|
hEventLog );
|
|
|
|
bResult = ( dwError == ERROR_SUCCESS );
|
|
|
|
RunGPOScripts_exit:
|
|
|
|
if (hEventLog)
|
|
{
|
|
DeregisterEventSource(hEventLog);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* 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, FALSE);
|
|
|
|
if (Result) {
|
|
VerbosePrint(("Successfully executed mpr logon script <%S>", lpLogonScripts));
|
|
|
|
if (bSyncApp) {
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* 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;
|
|
|
|
if ( NtCurrentPeb()->SessionId != 0 ) {
|
|
// Only do this for Console
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// 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) / sizeof( TCHAR ));
|
|
|
|
ExecApplication(achExec, FALSE, TRUE, FALSE, SW_SHOWNORMAL);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* InitializeMisc
|
|
*
|
|
* History:
|
|
* 14-Jul-95 EricFlo Created.
|
|
\***************************************************************************/
|
|
|
|
void InitializeMisc (HINSTANCE hInstance)
|
|
{
|
|
HKEY hkeyMM;
|
|
DWORD dwTempFile, cbTempFile, dwType;
|
|
TCHAR achExec[MAX_PATH];
|
|
|
|
//
|
|
// 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) / sizeof( TCHAR ));
|
|
ExecProcesses(TEXT("vmapplet"), achExec, TRUE, FALSE, TRUE);
|
|
}
|
|
|
|
|
|
//
|
|
// Tell the user if he has an invalid video selection.
|
|
//
|
|
|
|
CheckVideoSelection(hInstance);
|
|
|
|
|
|
//
|
|
// Notify other system components that a new
|
|
// user has logged into the workstation.
|
|
//
|
|
NewLogonNotify();
|
|
|
|
}
|
|
|
|
|
|
#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 params
|
|
)
|
|
/***************************************************************************\
|
|
* AddToMessageAlias
|
|
*
|
|
* History:
|
|
* 10-Apr-93 Robertre Created.
|
|
\***************************************************************************/
|
|
{
|
|
HANDLE hShellReadyEvent;
|
|
|
|
WCHAR UserName[MAX_PATH + 1];
|
|
DWORD UserNameLength = sizeof(UserName) / sizeof(*UserName);
|
|
DWORD dwCount;
|
|
|
|
BOOL standardShellWasStarted = *(BOOL *)params;
|
|
|
|
//
|
|
// 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"));
|
|
|
|
if (standardShellWasStarted )
|
|
{
|
|
dwCount = 0;
|
|
while (TRUE) {
|
|
|
|
hShellReadyEvent = OpenEvent(EVENT_ALL_ACCESS,FALSE,L"ShellReadyEvent");
|
|
|
|
if (hShellReadyEvent == NULL)
|
|
{
|
|
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
|
|
|
if (dwCount < 5) {
|
|
Sleep (3000);
|
|
dwCount++;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WaitForSingleObject(hShellReadyEvent, INFINITE);
|
|
Sleep(20000);
|
|
CloseHandle(hShellReadyEvent);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SpoolerInit();
|
|
|
|
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
BOOL
|
|
StartTheShell(
|
|
void
|
|
)
|
|
/***************************************************************************\
|
|
* StartTheShell
|
|
*
|
|
* Starts the shell, either explorer, the shell value specified in
|
|
* the registry for winlogon, or the alternate shell that is specified
|
|
* by the safeboot procedure.
|
|
*
|
|
* retrun
|
|
* TRUE if the standard shell was executed
|
|
* FALSE if a non-standard shell was executed.
|
|
*
|
|
* 14-Jan-98 WesW Created.
|
|
\***************************************************************************/
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwSize, dwType;
|
|
WCHAR ShellCmdLine[MAX_PATH];
|
|
DWORD UseAlternateShell = 0;
|
|
|
|
|
|
//
|
|
// get the safeboot mode
|
|
//
|
|
|
|
if (RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
TEXT("system\\currentcontrolset\\control\\safeboot\\option"),
|
|
0,
|
|
KEY_READ,
|
|
&hKey
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
dwSize = sizeof(DWORD);
|
|
RegQueryValueEx (
|
|
hKey,
|
|
TEXT("UseAlternateShell"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &UseAlternateShell,
|
|
&dwSize
|
|
);
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
if (UseAlternateShell) {
|
|
|
|
if (RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
TEXT("system\\currentcontrolset\\control\\safeboot"),
|
|
0,
|
|
KEY_READ,
|
|
&hKey
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
dwSize = sizeof(ShellCmdLine);
|
|
if (RegQueryValueEx (
|
|
hKey,
|
|
TEXT("AlternateShell"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) ShellCmdLine,
|
|
&dwSize
|
|
) != ERROR_SUCCESS || ShellCmdLine[0] == 0)
|
|
{
|
|
UseAlternateShell = 0;
|
|
}
|
|
RegCloseKey( hKey );
|
|
} else {
|
|
UseAlternateShell = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Before we start the shell, we must re-enable the shell's script
|
|
// zone security checks -- if we can't do this, it is not safe
|
|
// to start the shell since it may allow the user to run
|
|
// unsafe code without notification.
|
|
//
|
|
if ( ! EnableScriptZoneSecurityCheck() )
|
|
{
|
|
//
|
|
// We have to exit, and return TRUE which means that we failed to start
|
|
// the standard shell. We do this even if an alternate shell was desired since
|
|
// whenever the alternate shell fails to launch for some other reason,
|
|
// we try to launch explorer.exe and would return TRUE in that case.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
if (IsTSAppCompatOn()) {
|
|
if ( !ExecProcesses(TEXT("AppSetup"), NULL, FALSE, TRUE, TRUE ) ) {
|
|
ExecProcesses(TEXT("AppSetup"), NULL, TRUE, TRUE, TRUE);
|
|
}
|
|
}
|
|
|
|
if (UseAlternateShell) {
|
|
if (ExecApplication(ShellCmdLine, FALSE, FALSE, FALSE, SW_MAXIMIZE)) {
|
|
return FALSE; // an alt-shell was executed
|
|
}
|
|
} else if (NtCurrentPeb()->SessionId != 0) {
|
|
|
|
//
|
|
// Terminal Server: For remote sessions query the Terminal Server service
|
|
// to see if this session has specified a initial program other than
|
|
// explorer.exe.
|
|
//
|
|
|
|
BOOLEAN bExecOk = TRUE;
|
|
BOOLEAN IsWorkingDirWrong = FALSE;
|
|
UINT ErrorStringId;
|
|
LPTSTR psz = NULL;
|
|
LPTSTR pszerr;
|
|
ULONG Length;
|
|
BOOLEAN Result;
|
|
HANDLE dllHandle;
|
|
|
|
|
|
|
|
//
|
|
// Load winsta.dll
|
|
//
|
|
dllHandle = LoadLibraryW(L"winsta.dll");
|
|
|
|
if (dllHandle) {
|
|
|
|
WINSTATIONCONFIG *pConfigData = LocalAlloc(LPTR, sizeof(WINSTATIONCONFIG));
|
|
|
|
if (pConfigData) {
|
|
|
|
PWINSTATION_QUERY_INFORMATION pfnWinstationQueryInformation;
|
|
|
|
pfnWinstationQueryInformation = (PWINSTATION_QUERY_INFORMATION) GetProcAddress(
|
|
dllHandle,
|
|
"WinStationQueryInformationW"
|
|
);
|
|
if (pfnWinstationQueryInformation) {
|
|
|
|
|
|
|
|
|
|
Result = pfnWinstationQueryInformation( SERVERNAME_CURRENT,
|
|
LOGONID_CURRENT,
|
|
WinStationConfiguration,
|
|
pConfigData,
|
|
sizeof(WINSTATIONCONFIG),
|
|
&Length );
|
|
|
|
if (Result && pConfigData->User.InitialProgram[0] ) {
|
|
|
|
//BUGID - 342176
|
|
|
|
if( !ExpandEnvironmentStrings( pConfigData->User.InitialProgram, ShellCmdLine, MAX_PATH ) )
|
|
{
|
|
wcscpy( ShellCmdLine, pConfigData->User.InitialProgram );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// If a working directory is specified,
|
|
// then attempt to change the current directory to it.
|
|
//
|
|
|
|
if ( pConfigData->User.WorkDirectory[0] ) {
|
|
|
|
WCHAR WorkDirectory[ DIRECTORY_LENGTH + 1 ];
|
|
|
|
if ( !ExpandEnvironmentStrings( pConfigData->User.WorkDirectory, WorkDirectory, DIRECTORY_LENGTH + 1 ) ) {
|
|
wcscpy( WorkDirectory, pConfigData->User.WorkDirectory );
|
|
}
|
|
|
|
bExecOk = (BYTE) SetCurrentDirectory( WorkDirectory );
|
|
}
|
|
|
|
pszerr = pConfigData->User.WorkDirectory;
|
|
|
|
if ( !bExecOk ) {
|
|
|
|
DbgPrint( "USERINIT: Failed to set working directory %ws for SessionId %u\n",
|
|
pConfigData->User.WorkDirectory, NtCurrentPeb()->SessionId );
|
|
|
|
IsWorkingDirWrong = TRUE;
|
|
goto badexec;
|
|
|
|
}
|
|
|
|
bExecOk = (BYTE)ExecApplication( ShellCmdLine, FALSE, FALSE,
|
|
FALSE,(USHORT)(pConfigData->User.fMaximize ? SW_SHOWMAXIMIZED : SW_SHOW) );
|
|
pszerr = ShellCmdLine;
|
|
|
|
badexec:
|
|
|
|
if ( !bExecOk ) {
|
|
DWORD rc;
|
|
BOOL bGotString;
|
|
#define PSZ_MAX 256
|
|
WCHAR pszTemplate[PSZ_MAX];
|
|
LPTSTR errbuf = NULL;
|
|
|
|
rc = GetLastError();
|
|
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
|
NULL,
|
|
rc,
|
|
0,
|
|
(LPTSTR) (&psz),
|
|
1,
|
|
NULL);
|
|
|
|
if (psz) {
|
|
if (IsWorkingDirWrong == TRUE)
|
|
{
|
|
ErrorStringId = IDS_FAILING_WORKINGDIR;
|
|
}
|
|
else
|
|
{
|
|
ErrorStringId = IDS_FAILING_SHELLCOMMAND;
|
|
}
|
|
bGotString = LoadString(NULL,ErrorStringId,pszTemplate,PSZ_MAX);
|
|
if (bGotString) {
|
|
errbuf = LocalAlloc(LPTR, 512 * sizeof(TCHAR));
|
|
if (errbuf) {
|
|
wsprintf( errbuf, pszTemplate, psz, pszerr );
|
|
}
|
|
|
|
}
|
|
LocalFree(psz);
|
|
}
|
|
else {
|
|
if (IsWorkingDirWrong == TRUE)
|
|
{
|
|
ErrorStringId = IDS_ERROR_WORKINGDIR;
|
|
}
|
|
else
|
|
{
|
|
ErrorStringId = IDS_ERROR_SHELLCOMMAND;
|
|
}
|
|
bGotString = LoadString(NULL,ErrorStringId,pszTemplate,PSZ_MAX);
|
|
if (bGotString) {
|
|
errbuf = LocalAlloc(LPTR, 512 * sizeof(WCHAR));
|
|
if (errbuf) {
|
|
wsprintf( errbuf, pszTemplate, rc, pszerr );
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bGotString && errbuf) {
|
|
|
|
HelpMessageBox(NULL, NULL, errbuf, NULL, MB_OK | MB_ICONSTOP | MB_HELP, TEXT("MS-ITS:rdesktop.chm::/rdesktop_troubleshoot.htm"));
|
|
LocalFree(errbuf);
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
LocalFree(pConfigData);
|
|
FreeLibrary(dllHandle);
|
|
|
|
// an alt shell/program was executed
|
|
return FALSE ;
|
|
}
|
|
|
|
}
|
|
|
|
LocalFree(pConfigData);
|
|
|
|
} // if pConfigData
|
|
|
|
FreeLibrary(dllHandle);
|
|
}
|
|
}
|
|
|
|
|
|
if (!ExecProcesses(TEXT("shell"), NULL, FALSE, FALSE, FALSE)) {
|
|
ExecProcesses(TEXT("shell"), TEXT("explorer"), TRUE, FALSE, FALSE);
|
|
}
|
|
|
|
return TRUE; // standard shell/explorer was executed
|
|
}
|
|
|
|
VOID
|
|
DoAutoEnrollment(
|
|
LPTSTR Param
|
|
)
|
|
{
|
|
if (0==wcscmp(Param, AUTOENROLL_STARTUP)) {
|
|
AutoEnrollThread = CertAutoEnrollment( GetDesktopWindow(), CERT_AUTO_ENROLLMENT_START_UP );
|
|
} else {
|
|
AutoEnrollThread = CertAutoEnrollment( GetDesktopWindow(), CERT_AUTO_ENROLLMENT_WAKE_UP );
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* WinMain
|
|
*
|
|
* History:
|
|
* 20-Aug-92 Davidc Created.
|
|
\***************************************************************************/
|
|
typedef BOOL (WINAPI * PFNIMMDISABLEIME)( DWORD );
|
|
|
|
int
|
|
WINAPI
|
|
WinMain(
|
|
HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpszCmdParam,
|
|
int nCmdShow
|
|
)
|
|
{
|
|
LPTSTR lpLogonServer;
|
|
LPTSTR lpOriginalUNCLogonServer;
|
|
LPTSTR lpLogonScript;
|
|
LPTSTR lpMprLogonScripts;
|
|
LPTSTR lpGPOScriptType;
|
|
LPTSTR lpAutoEnroll;
|
|
LPTSTR lpAutoEnrollMode;
|
|
DWORD ThreadId;
|
|
DWORD WaitResult;
|
|
HANDLE ThreadHandle;
|
|
BOOL bRunLogonScriptsSync;
|
|
BOOL bRunGrpConv = FALSE;
|
|
HKEY hKey;
|
|
DWORD dwType, dwSize, dwTemp;
|
|
TCHAR szCmdLine[50];
|
|
BOOL standardShellWasStarted;
|
|
HANDLE hImm = 0;
|
|
PFNIMMDISABLEIME pfnImmDisableIME = 0;
|
|
BOOL OptimizedLogon;
|
|
LPTSTR OptimizedLogonStatus;
|
|
|
|
WriteLog(TEXT("Userinit: Starting"));
|
|
if ( GetSystemMetrics( SM_IMMENABLED ) )
|
|
{
|
|
hImm = LoadLibrary( L"imm32.dll");
|
|
if ( hImm )
|
|
{
|
|
pfnImmDisableIME = (PFNIMMDISABLEIME) GetProcAddress( hImm,
|
|
"ImmDisableIME" );
|
|
if ( pfnImmDisableIME )
|
|
{
|
|
pfnImmDisableIME( -1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Determine if we did an optimized logon. By default assume we did not.
|
|
//
|
|
|
|
OptimizedLogon = FALSE;
|
|
|
|
OptimizedLogonStatus = AllocAndGetEnvironmentVariable(OPTIMIZED_LOGON_VARIABLE);
|
|
if (OptimizedLogonStatus) {
|
|
if (lstrcmp(OptimizedLogonStatus, TEXT("1")) == 0) {
|
|
OptimizedLogon = TRUE;
|
|
}
|
|
Free(OptimizedLogonStatus);
|
|
}
|
|
SetEnvironmentVariable(OPTIMIZED_LOGON_VARIABLE, NULL);
|
|
|
|
//
|
|
// Check if userinit is being started to just run GPO scripts
|
|
//
|
|
|
|
lpGPOScriptType = AllocAndGetEnvironmentVariable(GPO_SCRIPT_TYPE_VARIABLE);
|
|
|
|
//
|
|
// Check if userinit.exe is being run just for auto enrollment
|
|
//
|
|
|
|
lpAutoEnroll = AllocAndGetEnvironmentVariable( AUTOENROLL_VARIABLE );
|
|
lpAutoEnrollMode = AllocAndGetEnvironmentVariable( AUTOENROLLMODE_VARIABLE );
|
|
|
|
SetEnvironmentVariable(AUTOENROLL_VARIABLE, NULL);
|
|
|
|
if (lpGPOScriptType) {
|
|
|
|
//
|
|
// Userinit was started to execute GPO scripts only
|
|
//
|
|
// Clean up the environment block
|
|
//
|
|
|
|
SetEnvironmentVariable(GPO_SCRIPT_TYPE_VARIABLE, NULL);
|
|
|
|
|
|
//
|
|
// Execute the scripts and clean up
|
|
//
|
|
|
|
RunGPOScripts (lpGPOScriptType);
|
|
|
|
Free(lpGPOScriptType);
|
|
|
|
|
|
//
|
|
// We're finished. Exit now.
|
|
//
|
|
|
|
if ( lpAutoEnroll == NULL )
|
|
{
|
|
goto Exit ;
|
|
}
|
|
}
|
|
|
|
if ( lpAutoEnroll )
|
|
{
|
|
if ( ( wcscmp( lpAutoEnroll, AUTOENROLL_NONEXCLUSIVE ) == 0 ) ||
|
|
( wcscmp( lpAutoEnroll, AUTOENROLL_EXCLUSIVE ) == 0 ) )
|
|
{
|
|
DoAutoEnrollment( lpAutoEnrollMode );
|
|
|
|
if ( wcscmp( lpAutoEnroll, AUTOENROLL_EXCLUSIVE ) == 0 )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
}
|
|
}
|
|
//
|
|
// Check if grpconv.exe needs to be run
|
|
//
|
|
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER, WINLOGON_KEY, 0,
|
|
KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Check for the sync flag.
|
|
//
|
|
|
|
dwSize = sizeof(bRunGrpConv);
|
|
RegQueryValueEx (hKey, GRPCONV_REG_VALUE_NAME, NULL, &dwType,
|
|
(LPBYTE) &bRunGrpConv, &dwSize);
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// Run grpconv.exe if requested
|
|
//
|
|
|
|
if (bRunGrpConv) {
|
|
WriteLog(TEXT("Userinit: Running grpconv.exe"));
|
|
ExecApplication(g_szGrpConvExe, FALSE, TRUE, FALSE, SW_SHOWNORMAL);
|
|
}
|
|
|
|
|
|
//
|
|
// Get the logon script environment variables
|
|
//
|
|
|
|
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);
|
|
|
|
//
|
|
// See if logon scripts are to be run sync or async
|
|
//
|
|
|
|
bRunLogonScriptsSync = RunLogonScriptSync();
|
|
|
|
SetupHotKeyForKeyboardLayout();
|
|
|
|
//
|
|
// For application server see if we hve any .ini file/registry sync'ing to do
|
|
//We should do it before we start running logon scripts!
|
|
//
|
|
//First Check if Application compatibility is on
|
|
//
|
|
if (IsTSAppCompatOn())
|
|
{
|
|
HANDLE dllHandle;
|
|
|
|
if (lpMprLogonScripts) {
|
|
//Force to run logon script sync when a provider logon script exists when the system
|
|
//is a terminal server. This is because of the global flag on the registry
|
|
// doesn't work when two interactive users logon at the same time.
|
|
bRunLogonScriptsSync = TRUE;
|
|
}
|
|
|
|
//
|
|
// Load tsappcmp.dll
|
|
//
|
|
dllHandle = LoadLibrary (TEXT("tsappcmp.dll"));
|
|
|
|
if (dllHandle) {
|
|
|
|
PTERMSRCHECKNEWINIFILES pfnTermsrvCheckNewIniFiles;
|
|
|
|
pfnTermsrvCheckNewIniFiles = (PTERMSRCHECKNEWINIFILES) GetProcAddress(
|
|
dllHandle,
|
|
"TermsrvCheckNewIniFiles"
|
|
);
|
|
if (pfnTermsrvCheckNewIniFiles) {
|
|
|
|
pfnTermsrvCheckNewIniFiles();
|
|
}
|
|
|
|
FreeLibrary(dllHandle);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If logon scripts can be run async then start the shell first.
|
|
//
|
|
|
|
if (bRunLogonScriptsSync) {
|
|
|
|
//
|
|
// Disable the shell's ie zone checking for the processes we
|
|
// are starting along with all their child processes
|
|
//
|
|
(void) DisableScriptZoneSecurityCheck();
|
|
|
|
RunLogonScript(lpLogonServer, lpLogonScript, bRunLogonScriptsSync, TRUE);
|
|
RunMprLogonScripts(lpMprLogonScripts, bRunLogonScriptsSync);
|
|
standardShellWasStarted = StartTheShell();
|
|
|
|
} else {
|
|
|
|
WriteLog(TEXT("Userinit: Starting the shell"));
|
|
standardShellWasStarted = StartTheShell();
|
|
|
|
(void) DisableScriptZoneSecurityCheck();
|
|
|
|
RunLogonScript(lpLogonServer, lpLogonScript, bRunLogonScriptsSync, TRUE);
|
|
RunMprLogonScripts(lpMprLogonScripts, bRunLogonScriptsSync);
|
|
}
|
|
|
|
UpdateUserSyncLogonScriptsCache(bRunLogonScriptsSync);
|
|
|
|
//
|
|
// Free up the buffers
|
|
//
|
|
|
|
Free(lpLogonServer);
|
|
Free(lpLogonScript);
|
|
Free(lpMprLogonScripts);
|
|
|
|
|
|
//
|
|
// Lower our priority so the shell can start faster
|
|
//
|
|
|
|
SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_LOWEST);
|
|
|
|
//
|
|
// Load remote fonts
|
|
//
|
|
|
|
|
|
LoadRemoteFonts();
|
|
|
|
//
|
|
// Initialize misc stuff
|
|
//
|
|
|
|
InitializeMisc (hInstance);
|
|
|
|
|
|
ThreadHandle = CreateThread(
|
|
NULL,
|
|
0,
|
|
AddToMessageAlias,
|
|
&standardShellWasStarted,
|
|
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"));
|
|
}
|
|
|
|
CloseHandle( ThreadHandle );
|
|
|
|
|
|
//
|
|
// If appropriate, start proquota.exe
|
|
//
|
|
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"),
|
|
0, KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
|
|
dwTemp = 0;
|
|
dwSize = sizeof(dwTemp);
|
|
|
|
RegQueryValueEx (hKey, TEXT("EnableProfileQuota"), NULL, &dwType,
|
|
(LPBYTE) &dwTemp, &dwSize);
|
|
|
|
if (dwTemp) {
|
|
lstrcpy (szCmdLine, TEXT("proquota.exe"));
|
|
ExecApplication(szCmdLine, FALSE, FALSE, FALSE, SW_SHOWNORMAL);
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
Exit:
|
|
|
|
if ( AutoEnrollThread )
|
|
{
|
|
WaitResult = WaitForSingleObject( AutoEnrollThread, INFINITE );
|
|
|
|
CloseHandle( AutoEnrollThread );
|
|
|
|
AutoEnrollThread = NULL ;
|
|
|
|
}
|
|
Free(lpAutoEnroll);
|
|
Free(lpAutoEnrollMode);
|
|
|
|
if ( hImm )
|
|
{
|
|
FreeLibrary( hImm );
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
//
|
|
// Determines if logon scripts should be executed sync or async
|
|
//
|
|
|
|
BOOL RunLogonScriptSync()
|
|
{
|
|
BOOL bSync = FALSE;
|
|
HKEY hKey;
|
|
DWORD dwType, dwSize;
|
|
|
|
//
|
|
// Check for a user preference
|
|
//
|
|
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER, WINLOGON_KEY, 0,
|
|
KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Check for the sync flag.
|
|
//
|
|
|
|
dwSize = sizeof(bSync);
|
|
RegQueryValueEx (hKey, SYNC_LOGON_SCRIPT, NULL, &dwType,
|
|
(LPBYTE) &bSync, &dwSize);
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// Check for a machine preference
|
|
//
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0,
|
|
KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Check for the sync flag.
|
|
//
|
|
|
|
dwSize = sizeof(bSync);
|
|
RegQueryValueEx (hKey, SYNC_LOGON_SCRIPT, NULL, &dwType,
|
|
(LPBYTE) &bSync, &dwSize);
|
|
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// Check for a user policy
|
|
//
|
|
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER, WINLOGON_POLICY_KEY, 0,
|
|
KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Check for the sync flag.
|
|
//
|
|
|
|
dwSize = sizeof(bSync);
|
|
RegQueryValueEx (hKey, SYNC_LOGON_SCRIPT, NULL, &dwType,
|
|
(LPBYTE) &bSync, &dwSize);
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// Check for a machine policy
|
|
//
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_POLICY_KEY, 0,
|
|
KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Check for the sync flag.
|
|
//
|
|
|
|
dwSize = sizeof(bSync);
|
|
RegQueryValueEx (hKey, SYNC_LOGON_SCRIPT, NULL, &dwType,
|
|
(LPBYTE) &bSync, &dwSize);
|
|
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
return bSync;
|
|
}
|
|
|
|
//
|
|
// Determines if startup scripts should be executed sync or async
|
|
//
|
|
|
|
BOOL RunStartupScriptSync()
|
|
{
|
|
BOOL bSync = TRUE;
|
|
HKEY hKey;
|
|
DWORD dwType, dwSize;
|
|
|
|
|
|
//
|
|
// Check for a machine preference
|
|
//
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0,
|
|
KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Check for the sync flag.
|
|
//
|
|
|
|
dwSize = sizeof(bSync);
|
|
RegQueryValueEx (hKey, SYNC_STARTUP_SCRIPT, NULL, &dwType,
|
|
(LPBYTE) &bSync, &dwSize);
|
|
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// Check for a machine policy
|
|
//
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_POLICY_KEY, 0,
|
|
KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Check for the sync flag.
|
|
//
|
|
|
|
dwSize = sizeof(bSync);
|
|
RegQueryValueEx (hKey, SYNC_STARTUP_SCRIPT, NULL, &dwType,
|
|
(LPBYTE) &bSync, &dwSize);
|
|
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
return bSync;
|
|
}
|
|
|
|
//
|
|
// Notify various components that a new user
|
|
// has logged into the workstation.
|
|
//
|
|
|
|
VOID
|
|
NewLogonNotify(
|
|
VOID
|
|
)
|
|
{
|
|
FARPROC lpProc;
|
|
HMODULE hLib;
|
|
HANDLE hEvent;
|
|
|
|
|
|
//
|
|
// Load the client-side user-mode PnP manager DLL
|
|
//
|
|
|
|
hLib = LoadLibrary(TEXT("setupapi.dll"));
|
|
|
|
if (hLib) {
|
|
|
|
lpProc = GetProcAddress(hLib, "CMP_Report_LogOn");
|
|
|
|
if (lpProc) {
|
|
|
|
//
|
|
// Ping the user-mode pnp manager -
|
|
// pass the private id as a parameter
|
|
//
|
|
|
|
(lpProc)(0x07020420, GetCurrentProcessId());
|
|
}
|
|
|
|
FreeLibrary(hLib);
|
|
}
|
|
|
|
|
|
//
|
|
// Notify DPAPI that a new user has just logged in. DPAPI will take
|
|
// this opportunity to re-synchronize its master keys if necessary.
|
|
//
|
|
|
|
{
|
|
BYTE BufferIn[8] = {0};
|
|
DATA_BLOB DataIn;
|
|
DATA_BLOB DataOut;
|
|
|
|
DataIn.pbData = BufferIn;
|
|
DataIn.cbData = sizeof(BufferIn);
|
|
|
|
CryptProtectData(&DataIn,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
CRYPTPROTECT_CRED_SYNC,
|
|
&DataOut);
|
|
}
|
|
|
|
|
|
//
|
|
// Only do this for Console session
|
|
//
|
|
|
|
if ( NtCurrentPeb()->SessionId != 0 ) {
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Notify RAS Autodial service that a new
|
|
// user has logged in.
|
|
//
|
|
|
|
hEvent = OpenEvent(SYNCHRONIZE|EVENT_MODIFY_STATE, FALSE, L"RasAutodialNewLogonUser");
|
|
|
|
if (hEvent) {
|
|
SetEvent(hEvent);
|
|
CloseHandle(hEvent);
|
|
}
|
|
}
|
|
|
|
BOOL SetupHotKeyForKeyboardLayout ()
|
|
{
|
|
if (!GetSystemMetrics(SM_REMOTESESSION)) {
|
|
|
|
//
|
|
// we dont care about local sessions.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
if (GetUserDefaultLangID() != LOWORD(GetKeyboardLayout(0))) {
|
|
|
|
//
|
|
// we are in a remote session, and we have different keyboard layouts for client and this users settings.
|
|
// the user should be allowed to switch the keyboard layout even if there is only 1 kbd layout available in his settings.
|
|
// since the current kbd layout is different that the one in his profile.
|
|
//
|
|
|
|
WCHAR szCtfmon[] = L"ctfmon.exe";
|
|
WCHAR szCtfmonCmd[] = L"ctfmon.exe /n";
|
|
HKEY hRunOnce;
|
|
DWORD dw;
|
|
|
|
//
|
|
// Lets put this in RunOnce.
|
|
//
|
|
if (RegCreateKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Runonce",
|
|
0, REG_NONE, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
|
|
NULL, &hRunOnce, &dw) == ERROR_SUCCESS) {
|
|
|
|
WCHAR *szHotKeyReg = L"Keyboard Layout\\Toggle";
|
|
HKEY hHotKey;
|
|
WCHAR szHotKeylAltShft[] = L"1";
|
|
WCHAR szNoHotKey[] = L"3";
|
|
|
|
RegSetValueEx(hRunOnce, szCtfmon, 0, REG_SZ, (PBYTE)szCtfmonCmd, sizeof(szCtfmonCmd));
|
|
RegCloseKey(hRunOnce);
|
|
|
|
if (RegCreateKeyEx(HKEY_CURRENT_USER, szHotKeyReg, 0, REG_NONE, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
|
|
NULL, &hHotKey, &dw) == ERROR_SUCCESS) {
|
|
|
|
DWORD dwType;
|
|
WCHAR szHotKey[3];
|
|
DWORD dwLen = sizeof(szHotKey);
|
|
BOOL bResetHotkey = FALSE;
|
|
|
|
if (RegQueryValueEx(hHotKey, L"Hotkey", NULL, &dwType,
|
|
(PBYTE)szHotKey, &dwLen) != ERROR_SUCCESS) {
|
|
|
|
bResetHotkey = TRUE;
|
|
}
|
|
|
|
if (bResetHotkey || !wcscmp(szHotKey, szNoHotKey))
|
|
{
|
|
|
|
//
|
|
// setup the registry for Hotkey.
|
|
//
|
|
if (RegSetValueEx(hHotKey, L"Hotkey", 0, REG_SZ,
|
|
(const BYTE *)szHotKeylAltShft, sizeof(szHotKeylAltShft)) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// now make call to read this registry and set the hotkey appropriately.
|
|
//
|
|
SystemParametersInfo( SPI_SETLANGTOGGLE, 0, NULL, 0);
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hHotKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/****************************************************************************
|
|
IsTSAppCompatOn()
|
|
Purpose:
|
|
Checks if TS application compatibility is enabled.
|
|
returns TRUE if enabled, FALSE - if not enabled or on case of error.
|
|
Comments:
|
|
This function goes to the registry only once.
|
|
All other times it just returnes the value.
|
|
****************************************************************************/
|
|
BOOL
|
|
IsTSAppCompatOn()
|
|
{
|
|
|
|
static BOOL bAppCompatOn = FALSE;
|
|
static BOOL bFirst = TRUE;
|
|
|
|
if(bFirst)
|
|
{
|
|
HKEY hKey;
|
|
if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0,
|
|
KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS )
|
|
{
|
|
DWORD dwValue = 0;
|
|
DWORD dwType;
|
|
DWORD dwSize = sizeof(dwValue);
|
|
|
|
if( RegQueryValueEx(hKey, REG_TERMSRV_APPCOMPAT,
|
|
NULL, &dwType, (LPBYTE) &dwValue, &dwSize) == ERROR_SUCCESS )
|
|
{
|
|
bAppCompatOn = (dwValue != 0);
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
bFirst = FALSE;
|
|
}
|
|
|
|
return bAppCompatOn;
|
|
}
|
|
|
|
/****************************************************************************
|
|
UpdateUserSyncLogonScriptsCache()
|
|
Purpose:
|
|
Update user's sync-logon-scripts setting cache in profile list.
|
|
****************************************************************************/
|
|
VOID
|
|
UpdateUserSyncLogonScriptsCache(BOOL bSync)
|
|
{
|
|
HANDLE UserToken;
|
|
HKEY UserKey;
|
|
PWCHAR UserSidString;
|
|
PWCHAR KeyPath;
|
|
ULONG Length;
|
|
|
|
//
|
|
// Update user's sync-logon-scripts setting cache in profile list.
|
|
//
|
|
|
|
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &UserToken)) {
|
|
|
|
UserSidString = GetSidString(UserToken);
|
|
|
|
if (UserSidString) {
|
|
|
|
Length = 0;
|
|
Length += wcslen(PROFILE_LIST_PATH);
|
|
Length += wcslen(L"\\");
|
|
Length += wcslen(UserSidString);
|
|
|
|
KeyPath = Alloc((Length + 1) * sizeof(WCHAR));
|
|
|
|
if (KeyPath) {
|
|
|
|
wcscpy(KeyPath, PROFILE_LIST_PATH);
|
|
wcscat(KeyPath, L"\\");
|
|
wcscat(KeyPath, UserSidString);
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, KeyPath, 0,
|
|
KEY_SET_VALUE, &UserKey) == ERROR_SUCCESS) {
|
|
|
|
RegSetValueEx(UserKey, SYNC_LOGON_SCRIPT, 0, REG_DWORD,
|
|
(BYTE *) &bSync, sizeof(bSync));
|
|
|
|
RegCloseKey(UserKey);
|
|
}
|
|
|
|
Free(KeyPath);
|
|
}
|
|
|
|
DeleteSidString(UserSidString);
|
|
}
|
|
|
|
CloseHandle(UserToken);
|
|
}
|
|
|
|
return;
|
|
}
|