711 lines
18 KiB
C++
711 lines
18 KiB
C++
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <shellapi.h>
|
|
#include "SmartPtr.h"
|
|
#include "strings.h"
|
|
|
|
extern "C"
|
|
{
|
|
void PrependToPath( LPWSTR, LPWSTR*);
|
|
void PathUnquoteSpaces( LPWSTR );
|
|
void UpdateUserEnvironment();
|
|
BOOL RegDelnode( HKEY, LPWSTR );
|
|
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;
|
|
}
|
|
|
|
BOOL
|
|
RegDelnodeRecurse (HKEY hKeyRoot, LPTSTR lpSubKey)
|
|
{
|
|
LPTSTR lpEnd;
|
|
LONG lResult;
|
|
DWORD dwSize;
|
|
TCHAR szName[MAX_PATH];
|
|
HKEY hKey;
|
|
FILETIME ftWrite;
|
|
|
|
//
|
|
// First, see if we can delete the key without having
|
|
// to recurse.
|
|
//
|
|
|
|
|
|
lResult = RegDeleteKey(hKeyRoot, lpSubKey);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
lResult = RegOpenKeyEx (hKeyRoot, lpSubKey, 0, KEY_READ, &hKey);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
lpEnd = CheckSlash(lpSubKey);
|
|
|
|
//
|
|
// Enumerate the keys
|
|
//
|
|
|
|
dwSize = MAX_PATH;
|
|
lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL,
|
|
NULL, NULL, &ftWrite);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
do {
|
|
|
|
lstrcpy (lpEnd, szName);
|
|
|
|
if (!RegDelnodeRecurse(hKeyRoot, lpSubKey)) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Enumerate again
|
|
//
|
|
|
|
dwSize = MAX_PATH;
|
|
|
|
lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL,
|
|
NULL, NULL, &ftWrite);
|
|
|
|
|
|
} while (lResult == ERROR_SUCCESS);
|
|
}
|
|
|
|
lpEnd--;
|
|
*lpEnd = TEXT('\0');
|
|
|
|
|
|
RegCloseKey (hKey);
|
|
|
|
|
|
//
|
|
// Try again to delete the key
|
|
//
|
|
|
|
lResult = RegDeleteKey(hKeyRoot, lpSubKey);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
RegDelnode (HKEY hKeyRoot, LPTSTR lpSubKey)
|
|
{
|
|
TCHAR szDelKey[2 * MAX_PATH];
|
|
|
|
|
|
lstrcpy (szDelKey, lpSubKey);
|
|
|
|
return RegDelnodeRecurse(hKeyRoot, szDelKey);
|
|
|
|
}
|
|
|
|
PSID
|
|
GetUserSid( HANDLE UserToken )
|
|
{
|
|
XPtrLF<TOKEN_USER> pUser;
|
|
PTOKEN_USER pTemp;
|
|
PSID pSid;
|
|
DWORD BytesRequired = 200;
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Allocate space for the user info
|
|
//
|
|
pUser = (PTOKEN_USER) LocalAlloc( LMEM_FIXED, BytesRequired );
|
|
if ( !pUser )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// 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 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
pUser = pTemp;
|
|
status = NtQueryInformationToken(
|
|
UserToken, // Handle
|
|
TokenUser, // TokenInformationClass
|
|
pUser, // TokenInformation
|
|
BytesRequired, // TokenInformationLength
|
|
&BytesRequired // ReturnLength
|
|
);
|
|
|
|
}
|
|
|
|
if ( !NT_SUCCESS(status) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
BytesRequired = RtlLengthSid(pUser->User.Sid);
|
|
pSid = LocalAlloc(LMEM_FIXED, BytesRequired);
|
|
if ( !pSid )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
status = RtlCopySid(BytesRequired, pSid, pUser->User.Sid);
|
|
|
|
if ( !NT_SUCCESS(status) )
|
|
{
|
|
LocalFree(pSid);
|
|
pSid = 0;
|
|
}
|
|
|
|
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;
|
|
SHELLEXECUTEINFO ExecInfo;
|
|
|
|
if ( GetSystemDirectory( szCurDir, ARRAYSIZE( szCurDir ) ) )
|
|
{
|
|
SetCurrentDirectory( szCurDir );
|
|
}
|
|
|
|
//
|
|
// Expand the command line and args
|
|
//
|
|
ExpandEnvironmentStrings( szCmdLine, szCmdLineEx, ARRAYSIZE(szCmdLineEx) );
|
|
ExpandEnvironmentStrings( szArgs, szArgsEx, ARRAYSIZE(szArgsEx) );
|
|
|
|
//
|
|
// Put the working directory on the front of the PATH
|
|
// environment variable
|
|
//
|
|
PrependToPath( szWorkingDir, &szOldPath );
|
|
|
|
//
|
|
// 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();
|
|
|
|
//
|
|
// Put the PATH environment variable back the way it was
|
|
//
|
|
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] );
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
//
|
|
// FILESYSPATH
|
|
//
|
|
dwType = REG_SZ;
|
|
dwSize = sizeof( szFileSysPath );
|
|
dwError = RegQueryValueEx( hKeyGPO,
|
|
FILESYSPATH,
|
|
0,
|
|
&dwType,
|
|
(LPBYTE) szFileSysPath,
|
|
&dwSize );
|
|
if ( dwError != ERROR_SUCCESS )
|
|
{
|
|
return dwError;
|
|
}
|
|
|
|
wcscat( szFileSysPath, L"\\Scripts\\" );
|
|
wcscat( szFileSysPath, szType );
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// create the following key
|
|
// HKLM\Software\Microsoft\Windows\CurrentVersion\Group Policy\State\<Target>\Scripts\<Type>
|
|
//
|
|
wcscpy( szBuffer, GP_STATE_KEY L"\\" );
|
|
if ( bMachine )
|
|
{
|
|
wcscat( szBuffer, L"Machine\\Scripts" );
|
|
}
|
|
else
|
|
{
|
|
XHandle hToken;
|
|
|
|
if ( !OpenProcessToken( GetCurrentProcess(),
|
|
TOKEN_ALL_ACCESS,
|
|
&hToken ) )
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
LPWSTR szSid = GetSidString( hToken );
|
|
|
|
if ( !szSid )
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
wcscat( szBuffer, szSid );
|
|
wcscat( szBuffer, L"\\Scripts" );
|
|
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\\<Type>
|
|
//
|
|
wcscpy( szBuffer, GPO_SCRIPTS_KEY L"\\" );
|
|
wcscat( szBuffer, szType );
|
|
|
|
//
|
|
// 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;
|
|
|
|
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;
|
|
}
|
|
|
|
|