#include #include #include #include #include #include "SmartPtr.h" #include "strings.h" #include extern "C" { BOOL PrependToPath( LPWSTR, LPWSTR*); void PathUnquoteSpaces( LPWSTR ); void UpdateUserEnvironment(); LPWSTR GetSidString( HANDLE UserToken ); void DeleteSidString( LPWSTR SidString ); }; #define GPO_SCRIPTS_KEY L"Software\\Policies\\Microsoft\\Windows\\System\\Scripts" #define GP_STATE_KEY L"Software\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\State" #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) #define SCRIPT L"Script" #define PARAMETERS L"Parameters" #define EXECTIME L"ExecTime" #define GPOID L"GPO-ID" #define SOMID L"SOM-ID" #define FILESYSPATH L"FileSysPath" #define SCR_STARTUP L"Startup" #define SCR_SHUTDOWN L"Shutdown" #define SCR_LOGON L"Logon" #define SCR_LOGOFF L"Logoff" LPTSTR CheckSlash (LPTSTR lpDir) { LPTSTR lpEnd; lpEnd = lpDir + lstrlen(lpDir); if (*(lpEnd - 1) != TEXT('\\')) { *lpEnd = TEXT('\\'); lpEnd++; *lpEnd = TEXT('\0'); } return lpEnd; } PSID GetUserSid( HANDLE UserToken ) { PTOKEN_USER pUser, pTemp; PSID pSid; DWORD BytesRequired = 200; NTSTATUS status; // // Allocate space for the user info // pUser = (PTOKEN_USER)LocalAlloc(LMEM_FIXED, BytesRequired); if ( pUser == NULL ) { return NULL; } // // Read in the UserInfo // status = NtQueryInformationToken( UserToken, // Handle TokenUser, // TokenInformationClass pUser, // TokenInformation BytesRequired, // TokenInformationLength &BytesRequired // ReturnLength ); if ( status == STATUS_BUFFER_TOO_SMALL ) { // // Allocate a bigger buffer and try again. // pTemp = (PTOKEN_USER)LocalReAlloc(pUser, BytesRequired, LMEM_MOVEABLE); if ( pTemp == NULL ) { LocalFree (pUser); return NULL; } pUser = pTemp; status = NtQueryInformationToken( UserToken, // Handle TokenUser, // TokenInformationClass pUser, // TokenInformation BytesRequired, // TokenInformationLength &BytesRequired // ReturnLength ); } if ( !NT_SUCCESS(status) ) { LocalFree(pUser); return NULL; } BytesRequired = RtlLengthSid(pUser->User.Sid); pSid = (PSID)LocalAlloc(LMEM_FIXED, BytesRequired); if ( pSid == NULL ) { LocalFree(pUser); return NULL; } status = RtlCopySid(BytesRequired, pSid, pUser->User.Sid); LocalFree(pUser); if ( !NT_SUCCESS(status) ) { LocalFree(pSid); pSid = NULL; } return pSid; } LPWSTR GetSidString( HANDLE UserToken ) { NTSTATUS NtStatus; PSID UserSid; UNICODE_STRING UnicodeString; // // Get the user sid // UserSid = GetUserSid( UserToken ); if ( !UserSid ) { return 0; } // // Convert user SID to a string. // NtStatus = RtlConvertSidToUnicodeString(&UnicodeString, UserSid, (BOOLEAN)TRUE ); // Allocate LocalFree( UserSid ); if ( !NT_SUCCESS(NtStatus) ) { return 0; } return UnicodeString.Buffer ; } void DeleteSidString( LPWSTR SidString ) { UNICODE_STRING String; RtlInitUnicodeString( &String, SidString ); RtlFreeUnicodeString( &String ); } typedef BOOL (*PFNSHELLEXECUTEEX)(LPSHELLEXECUTEINFO lpExecInfo); DWORD ExecuteScript( LPWSTR szCmdLine, LPWSTR szArgs, LPWSTR szWorkingDir, BOOL bSync, BOOL bHide, BOOL bRunMin, LPWSTR szType, PFNSHELLEXECUTEEX pfnShellExecuteEx, HANDLE hEventLog ) { WCHAR szCmdLineEx[MAX_PATH]; WCHAR szArgsEx[3 * MAX_PATH]; WCHAR szCurDir[MAX_PATH]; LPWSTR szOldPath = 0; BOOL bResult; DWORD dwError = ERROR_SUCCESS;; SHELLEXECUTEINFO ExecInfo; if ( GetSystemDirectory( szCurDir, ARRAYSIZE( szCurDir ) ) ) { bResult = SetCurrentDirectory( szCurDir ); if ( ! bResult ) { dwError = GetLastError(); } } else { dwError = GetLastError(); } if ( ERROR_SUCCESS != dwError ) { goto ExecuteScript_Exit; } // // Expand the command line and args // DWORD cchExpanded; cchExpanded = ExpandEnvironmentStrings( szCmdLine, szCmdLineEx, ARRAYSIZE(szCmdLineEx ) ); if ( cchExpanded > 0 ) { cchExpanded = ExpandEnvironmentStrings( szArgs, szArgsEx, ARRAYSIZE(szArgsEx) ); } if ( 0 == cchExpanded ) { dwError = GetLastError(); goto ExecuteScript_Exit; } // // Put the working directory on the front of the PATH // environment variable // bResult = PrependToPath( szWorkingDir, &szOldPath ); if ( ! bResult ) { dwError = GetLastError(); goto ExecuteScript_Exit; } // // Run the script // PathUnquoteSpaces( szCmdLineEx ); ZeroMemory(&ExecInfo, sizeof(ExecInfo)); ExecInfo.cbSize = sizeof(ExecInfo); ExecInfo.fMask = SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOZONECHECKS | SEE_MASK_NOCLOSEPROCESS; ExecInfo.lpFile = szCmdLineEx; ExecInfo.lpParameters = !szArgsEx[0] ? 0 : szArgsEx; ExecInfo.lpDirectory = szWorkingDir; if ( bHide ) { ExecInfo.nShow = SW_HIDE; } else { ExecInfo.nShow = (bRunMin ? SW_SHOWMINNOACTIVE : SW_SHOWNORMAL ); } bResult = pfnShellExecuteEx( &ExecInfo ); dwError = GetLastError(); // // Try to put the PATH environment variable back the way it was // If this fails, we have to continue // if ( szOldPath ) { SetEnvironmentVariable( L"PATH", szOldPath ); LocalFree( szOldPath ); szOldPath = 0; } if ( bResult ) { dwError = 0; if (bSync) { WaitForSingleObject(ExecInfo.hProcess, INFINITE); UpdateUserEnvironment(); } CloseHandle(ExecInfo.hProcess); } else { if ( hEventLog != 0 ) { LPWSTR szMsgBuf[2] = { (LPTSTR) ExecInfo.lpFile, 0 }; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, dwError, 0, (LPTSTR) (&szMsgBuf[1]), 1, 0); ReportEvent(hEventLog, EVENTLOG_ERROR_TYPE, 0, SHELLEXEC_ERROR, 0, 2, 0, (LPCTSTR*) szMsgBuf, 0); if ( szMsgBuf[1] ) { LocalFree( szMsgBuf[1] ); } } } ExecuteScript_Exit: return dwError; } ScrExecGPOFromReg( HKEY hKeyGPO, HKEY hKeyStateGPO, BOOL bSync, BOOL bHidden, BOOL bRunMin, LPWSTR szType, PFNSHELLEXECUTEEX pfnShellExecuteEx, HANDLE hEventLog ) { DWORD dwError = ERROR_SUCCESS; DWORD cSubKeys = 0; WCHAR szFileSysPath[3*MAX_PATH]; DWORD dwType; DWORD dwSize; HRESULT hr = S_OK; // // FILESYSPATH // dwType = REG_SZ; dwSize = sizeof( szFileSysPath ); dwError = RegQueryValueEx( hKeyGPO, FILESYSPATH, 0, &dwType, (LPBYTE) szFileSysPath, &dwSize ); if ( dwError != ERROR_SUCCESS ) { return dwError; } hr = StringCchCat( szFileSysPath, sizeof(szFileSysPath)/sizeof(WCHAR), L"\\Scripts\\" ); if(FAILED(hr)){ SetLastError(HRESULT_CODE(hr)); return HRESULT_CODE(hr); } hr = StringCchCat( szFileSysPath, sizeof(szFileSysPath)/sizeof(WCHAR), szType ); if(FAILED(hr)){ SetLastError(HRESULT_CODE(hr)); return HRESULT_CODE(hr); } // // get the numer of Scripts // dwError = RegQueryInfoKey( hKeyGPO, 0, 0, 0, &cSubKeys, 0, 0, 0, 0, 0, 0, 0 ); if ( dwError == ERROR_SUCCESS ) { // // for every Script // for ( DWORD dwIndex = 0 ; dwIndex < cSubKeys ; dwIndex++ ) { XKey hKeyScript; XKey hKeyStateScript; WCHAR szTemp[32]; dwError = RegOpenKeyEx( hKeyStateGPO, _itow( dwIndex, szTemp, 16 ), 0, KEY_ALL_ACCESS, &hKeyStateScript ); if ( dwError != ERROR_SUCCESS ) { return dwError; } // // open the Script key (we need only read perms) // dwError = RegOpenKeyEx( hKeyGPO, szTemp, 0, KEY_READ, &hKeyScript ); if ( dwError != ERROR_SUCCESS ) { return dwError; } WCHAR szScript[MAX_PATH]; WCHAR szParameters[MAX_PATH]; SYSTEMTIME execTime; // // script // dwType = REG_SZ; dwSize = sizeof( szScript ); dwError = RegQueryValueEx( hKeyScript, SCRIPT, 0, &dwType, (LPBYTE) szScript, &dwSize ); if ( dwError != ERROR_SUCCESS ) { break; } // // parameters // dwType = REG_SZ; dwSize = sizeof( szParameters ); dwError = RegQueryValueEx( hKeyScript, PARAMETERS, 0, &dwType, (LPBYTE) szParameters, &dwSize ); if ( dwError != ERROR_SUCCESS ) { break; } // // execute script // GetSystemTime( &execTime ); dwError = ExecuteScript(szScript, szParameters, szFileSysPath, bSync, bHidden, bRunMin, szType, pfnShellExecuteEx, hEventLog ); if ( dwError != ERROR_SUCCESS ) { ZeroMemory( &execTime, sizeof( execTime ) ); } // // write exec time // RegSetValueEx( hKeyStateScript, EXECTIME, 0, REG_QWORD, (LPBYTE) &execTime, sizeof( execTime ) ); } } return dwError; } extern "C" DWORD ScrExecGPOListFromReg( LPWSTR szType, BOOL bMachine, BOOL bSync, BOOL bHidden, BOOL bRunMin, HANDLE hEventLog ) { DWORD dwError = ERROR_SUCCESS; WCHAR szBuffer[MAX_PATH]; XKey hKeyType; XKey hKeyState; XKey hKeyStateType; HRESULT hr = S_OK; // // create the following key // HKLM\Software\Microsoft\Windows\CurrentVersion\Group Policy\State\\Scripts\ // hr = StringCchCopy( szBuffer, sizeof(szBuffer)/sizeof(WCHAR), GP_STATE_KEY L"\\" ); if(FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); return HRESULT_CODE(hr); } if ( bMachine ) { hr = StringCchCat( szBuffer, sizeof(szBuffer)/sizeof(WCHAR), L"Machine\\Scripts" ); if(FAILED(hr)){ SetLastError(HRESULT_CODE(hr)); return HRESULT_CODE(hr); } } else { XHandle hToken; if ( !OpenProcessToken( GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken ) ) { return GetLastError(); } LPWSTR szSid = GetSidString( hToken ); if ( !szSid ) { return GetLastError(); } hr = StringCchCat( szBuffer, sizeof(szBuffer)/sizeof(WCHAR), szSid ); if(FAILED(hr)){ SetLastError(HRESULT_CODE(hr)); return HRESULT_CODE(hr); } hr = StringCchCat( szBuffer, sizeof(szBuffer)/sizeof(WCHAR), L"\\Scripts" ); if(FAILED(hr)){ SetLastError(HRESULT_CODE(hr)); return HRESULT_CODE(hr); } DeleteSidString( szSid ); } // // state // dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE, szBuffer, 0, KEY_ALL_ACCESS, &hKeyState ); if ( dwError != ERROR_SUCCESS ) { return dwError; } dwError = RegOpenKeyEx( hKeyState, szType, 0, KEY_ALL_ACCESS, &hKeyStateType ); if ( dwError != ERROR_SUCCESS ) { return dwError; } // // construct "Software\\Policies\\Microsoft\\Windows\\System\\Scripts\\ // hr = StringCchCopy( szBuffer, sizeof(szBuffer)/sizeof(WCHAR), GPO_SCRIPTS_KEY L"\\" ); if(FAILED(hr)){ SetLastError(HRESULT_CODE(hr)); return HRESULT_CODE(hr); } hr = StringCchCat( szBuffer, sizeof(szBuffer)/sizeof(WCHAR), szType ); if(FAILED(hr)){ SetLastError(HRESULT_CODE(hr)); return HRESULT_CODE(hr); } // // open the key // dwError = RegOpenKeyEx( bMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, szBuffer, 0, KEY_READ, &hKeyType ); if ( dwError != ERROR_SUCCESS ) { return dwError; } DWORD cSubKeys = 0; // // get the numer of GPOs // dwError = RegQueryInfoKey( hKeyType, 0, 0, 0, &cSubKeys, 0, 0, 0, 0, 0, 0, 0 ); if ( dwError != ERROR_SUCCESS ) { return dwError; } HINSTANCE hShell32; PFNSHELLEXECUTEEX pfnShellExecuteEx = NULL; hShell32 = LoadLibrary( L"shell32.dll" ); if ( hShell32 ) { pfnShellExecuteEx = (PFNSHELLEXECUTEEX) GetProcAddress( hShell32, "ShellExecuteExW" ); } if ( !pfnShellExecuteEx ) { return GetLastError(); } // // for every GPO // for ( DWORD dwIndex = 0 ; dwIndex < cSubKeys ; dwIndex++ ) { XKey hKeyGPO; XKey hKeyStateGPO; // // open the state GPO key // dwError = RegOpenKeyEx( hKeyStateType, _itow( dwIndex, szBuffer, 16 ), 0, KEY_ALL_ACCESS, &hKeyStateGPO ); if ( dwError != ERROR_SUCCESS ) { break; } // // open the policy GPO key (we need only read perms) // dwError = RegOpenKeyEx( hKeyType, szBuffer, 0, KEY_READ, &hKeyGPO ); if ( dwError != ERROR_SUCCESS ) { break; } // // execute all scripts in the GPO // DWORD dwExecError; dwExecError = ScrExecGPOFromReg(hKeyGPO, hKeyStateGPO, bSync, bHidden, bRunMin, szType, pfnShellExecuteEx, hEventLog ); if ( dwExecError != ERROR_SUCCESS ) { dwError = dwExecError; } } return dwError; }