You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2344 lines
74 KiB
2344 lines
74 KiB
//*************************************************************
|
|
//
|
|
// Group Policy Support for registry policies
|
|
//
|
|
// Microsoft Confidential
|
|
// Copyright (c) Microsoft Corporation 1997-1998
|
|
// All rights reserved
|
|
//
|
|
//*************************************************************
|
|
|
|
#include "gphdr.h"
|
|
#include <strsafe.h>
|
|
|
|
static BOOL ExtractKeyOrValueName( LPBYTE * ppData, LPTSTR pszName, DWORD dwNameCch );
|
|
|
|
//*************************************************************
|
|
//
|
|
// DeleteRegistryValue()
|
|
//
|
|
// Purpose: Callback from ParseRegistryFile that deletes
|
|
// registry policies
|
|
//
|
|
// Parameters: lpGPOInfo - GPO Information
|
|
// lpKeyName - Key name
|
|
// lpValueName - Value name
|
|
// dwType - Registry data type
|
|
// lpData - Registry data
|
|
// pwszGPO - Gpo
|
|
// pwszSOM - Sdou that the Gpo is linked to
|
|
// pHashTable - Hash table for registry keys
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL DeleteRegistryValue (LPGPOINFO lpGPOInfo, LPTSTR lpKeyName,
|
|
LPTSTR lpValueName, DWORD dwType,
|
|
DWORD dwDataLength, LPBYTE lpData,
|
|
WCHAR *pwszGPO,
|
|
WCHAR *pwszSOM, REGHASHTABLE *pHashTable)
|
|
{
|
|
DWORD dwDisp;
|
|
HKEY hSubKey;
|
|
LONG lResult;
|
|
INT iStrLen;
|
|
TCHAR szPolicies1[] = TEXT("Software\\Policies");
|
|
TCHAR szPolicies2[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies");
|
|
XLastError xe;
|
|
|
|
|
|
//
|
|
// Check if there is a keyname
|
|
//
|
|
|
|
if (!lpKeyName || !(*lpKeyName)) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if the key is in one of the policies keys
|
|
//
|
|
|
|
iStrLen = lstrlen(szPolicies1);
|
|
if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE, szPolicies1,
|
|
iStrLen, lpKeyName, iStrLen) != CSTR_EQUAL) {
|
|
|
|
iStrLen = lstrlen(szPolicies2);
|
|
if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE, szPolicies2,
|
|
iStrLen, lpKeyName, iStrLen) != CSTR_EQUAL) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Check if the value name starts with **
|
|
//
|
|
|
|
if (lpValueName && (lstrlen(lpValueName) > 1)) {
|
|
|
|
if ( (*lpValueName == TEXT('*')) && (*(lpValueName+1) == TEXT('*')) ) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// We found a value that needs to be deleted
|
|
//
|
|
|
|
if (RegCleanUpValue (lpGPOInfo->hKeyRoot, lpKeyName, lpValueName)) {
|
|
DebugMsg((DM_VERBOSE, TEXT("DeleteRegistryValue: Deleted %s\\%s"),
|
|
lpKeyName, lpValueName));
|
|
} else {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("DeleteRegistryValue: Failed to delete %s\\%s"),
|
|
lpKeyName, lpValueName));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// SetRegPermissionsOnPoliciesKey()
|
|
//
|
|
// Purpose: Set permissions on the policy keys to add LocalSystem permission
|
|
// and become the owner
|
|
//
|
|
// Parameters: lpGPOInfo - GPT information
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Ideally it should set the owner and permissions for each subkey but that is
|
|
// proportinal to the number of subkeys
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL SetRegPermissionsOnPoliciesKey(LPGPOINFO lpGPOInfo, LPTSTR szSubKey)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
BOOLEAN WasEnabled = FALSE;
|
|
SECURITY_DESCRIPTOR sd;
|
|
SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
|
|
PSID psidSystem = NULL;
|
|
HKEY hSubKey = NULL;
|
|
BOOL bElevated = FALSE;
|
|
BOOL bRet = TRUE;
|
|
XLastError xe;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
DWORD dwDisp = 0;
|
|
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("SetRegPermissionsOnPoliciesKey: Resetting permission on the policy key")));
|
|
|
|
if (lpGPOInfo->dwFlags & GP_MACHINE)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
DmAssert((szSubKey) && (szSubKey[0]));
|
|
|
|
// presetup the sd etc. before elevating privileges
|
|
|
|
//
|
|
// Get the system sid
|
|
//
|
|
|
|
if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID,
|
|
0, 0, 0, 0, 0, 0, 0, &psidSystem)) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("SetRegPermissionsOnPoliciesKey: Failed to initialize system sid. Error = %d"), GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("SetRegPermissionsOnPoliciesKey: Failed to initialize security descriptor. Error = %d"), GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
if (!SetSecurityDescriptorOwner(&sd, psidSystem, FALSE)) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("SetRegPermissionsOnPoliciesKey: Failed to set security descriptor owner. Error = %d"), GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
Status = RtlAdjustPrivilege(SE_TAKE_OWNERSHIP_PRIVILEGE, TRUE, FALSE, &WasEnabled);
|
|
|
|
if (!(NT_SUCCESS(Status))) {
|
|
xe = RtlNtStatusToDosError(Status);
|
|
DebugMsg((DM_WARNING, TEXT("SetRegPermissionsOnPoliciesKey: Failed to enable privilege. Error = %d"), (DWORD)xe));
|
|
goto Exit;
|
|
}
|
|
|
|
bElevated = TRUE;
|
|
|
|
|
|
//
|
|
// Open the registry key
|
|
//
|
|
|
|
dwErr = RegOpenKeyEx(lpGPOInfo->hKeyRoot,
|
|
szSubKey,
|
|
0,
|
|
WRITE_OWNER,
|
|
&hSubKey);
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
if (dwErr == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
else {
|
|
xe = dwErr;
|
|
DebugMsg((DM_WARNING, TEXT("SetRegPermissionsOnPoliciesKey: Failed to open reg key. Error = %d"), (DWORD)xe));
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
dwErr = RegSetKeySecurity (hSubKey, OWNER_SECURITY_INFORMATION, &sd);
|
|
|
|
RegCloseKey(hSubKey);
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
xe = dwErr;
|
|
DebugMsg((DM_WARNING, TEXT("SetRegPermissionsOnPoliciesKey: Failed to set security, error = %d"), dwErr));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
if (bElevated)
|
|
{
|
|
Status = RtlAdjustPrivilege(SE_TAKE_OWNERSHIP_PRIVILEGE, WasEnabled, FALSE, &WasEnabled);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DebugMsg((DM_WARNING, TEXT("SetRegPermissionsOnPoliciesKey: Failed to restore privilege to previous enabled state")));
|
|
// nothing more we can do
|
|
}
|
|
else {
|
|
bElevated = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
if (!MakeRegKeySecure(lpGPOInfo->hToken,
|
|
lpGPOInfo->hKeyRoot,
|
|
szSubKey)) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("SetRegPermissionsOnPoliciesKey: Failed to secure reg key.")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
bRet = TRUE;
|
|
|
|
Exit:
|
|
|
|
if (psidSystem) {
|
|
FreeSid(psidSystem);
|
|
}
|
|
|
|
if (bElevated)
|
|
{
|
|
Status = RtlAdjustPrivilege(SE_TAKE_OWNERSHIP_PRIVILEGE, WasEnabled, FALSE, &WasEnabled);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DebugMsg((DM_WARNING, TEXT("SetRegPermissionsOnPoliciesKey: Failed to restore privilege to previous enabled state")));
|
|
// nothing more we can do
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// ResetPolicies()
|
|
//
|
|
// Purpose: Resets the Policies and old Policies key to their
|
|
// original state.
|
|
//
|
|
// Parameters: lpGPOInfo - GPT information
|
|
// lpArchive - Name of archive file
|
|
//
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ResetPolicies (LPGPOINFO lpGPOInfo, LPTSTR lpArchive)
|
|
{
|
|
HKEY hKey;
|
|
LONG lResult;
|
|
DWORD dwDisp, dwValue = 0x91;
|
|
XLastError xe;
|
|
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ResetPolicies: Entering.")));
|
|
|
|
//
|
|
// change ownership of the key and make sure that localsystem has full control
|
|
//
|
|
|
|
if (!SetRegPermissionsOnPoliciesKey(lpGPOInfo, TEXT("Software\\Policies")))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to set permissions on the policy key(1) with %d"), GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!SetRegPermissionsOnPoliciesKey(lpGPOInfo, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies")))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to set permissions on the policy key(2) with %d"), GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Parse the archive file and delete any policies
|
|
//
|
|
|
|
if (!ParseRegistryFile (lpGPOInfo, lpArchive,
|
|
DeleteRegistryValue, NULL, NULL, NULL, NULL, FALSE )) {
|
|
DWORD Status;
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ResetPolicies: ParseRegistryFile failed with error %d. deleting policy keys"), GetLastError()));
|
|
|
|
if ((Status = RegDelnode(lpGPOInfo->hKeyRoot, TEXT("Software\\Policies"))) != ERROR_SUCCESS)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to delete the reg key with %d"), Status));
|
|
}
|
|
|
|
if ((Status = RegDelnode(lpGPOInfo->hKeyRoot, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies"))) != ERROR_SUCCESS)
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to delete the reg key with %d"), Status));
|
|
}
|
|
|
|
// cannot fail if the path is too long
|
|
}
|
|
|
|
|
|
//
|
|
// Recreate the new policies key
|
|
//
|
|
|
|
lResult = RegCreateKeyEx (lpGPOInfo->hKeyRoot,
|
|
TEXT("Software\\Policies"),
|
|
0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE, NULL, &hKey, &dwDisp);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Re-apply security
|
|
//
|
|
|
|
RegCloseKey (hKey);
|
|
|
|
if (!MakeRegKeySecure((lpGPOInfo->dwFlags & GP_MACHINE) ? NULL : lpGPOInfo->hToken,
|
|
lpGPOInfo->hKeyRoot,
|
|
TEXT("Software\\Policies"))) {
|
|
DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to secure reg key.")));
|
|
}
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to create reg key with %d."), lResult));
|
|
}
|
|
|
|
|
|
//
|
|
// Recreate the old policies key
|
|
//
|
|
|
|
lResult = RegCreateKeyEx (lpGPOInfo->hKeyRoot,
|
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies"),
|
|
0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE, NULL, &hKey, &dwDisp);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Re-apply security
|
|
//
|
|
|
|
RegCloseKey (hKey);
|
|
|
|
if (!MakeRegKeySecure((lpGPOInfo->dwFlags & GP_MACHINE) ? NULL : lpGPOInfo->hToken,
|
|
lpGPOInfo->hKeyRoot,
|
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies"))) {
|
|
DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to secure reg key.")));
|
|
}
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to create reg key with %d."), lResult));
|
|
}
|
|
|
|
|
|
//
|
|
// If this is user policy, reset the NoDriveTypeAutoRun default value
|
|
//
|
|
|
|
if (!(lpGPOInfo->dwFlags & GP_MACHINE)) {
|
|
|
|
// override the default value with what the shell team wants on server
|
|
|
|
if ((g_ProductType == PT_SERVER) || (g_ProductType == PT_DC))
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ResetPolicies: resetting shell autorun value for server.")));
|
|
dwValue = 0x95;
|
|
}
|
|
|
|
if (RegCreateKeyEx (lpGPOInfo->hKeyRoot,
|
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"),
|
|
0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE, NULL, &hKey, &dwDisp) == ERROR_SUCCESS) {
|
|
|
|
RegSetValueEx (hKey, TEXT("NoDriveTypeAutoRun"), 0,
|
|
REG_DWORD, (LPBYTE) &dwValue, sizeof(dwValue));
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ResetPolicies: Leaving.")));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// ArchiveRegistryValue()
|
|
//
|
|
// Purpose: Archives a registry value in the specified file
|
|
//
|
|
// Parameters: hFile - File handle of archive file
|
|
// lpKeyName - Key name
|
|
// lpValueName - Value name
|
|
// dwType - Registry value type
|
|
// dwDataLength - Registry value size
|
|
// lpData - Registry value
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ArchiveRegistryValue(HANDLE hFile, LPWSTR lpKeyName,
|
|
LPWSTR lpValueName, DWORD dwType,
|
|
DWORD dwDataLength, LPBYTE lpData)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
DWORD dwBytesWritten;
|
|
DWORD dwTemp;
|
|
const WCHAR cOpenBracket = L'[';
|
|
const WCHAR cCloseBracket = L']';
|
|
const WCHAR cSemiColon = L';';
|
|
XLastError xe;
|
|
|
|
|
|
//
|
|
// Write the entry to the text file.
|
|
//
|
|
// Format:
|
|
//
|
|
// [keyname;valuename;type;datalength;data]
|
|
//
|
|
|
|
// open bracket
|
|
if (!WriteFile (hFile, &cOpenBracket, sizeof(WCHAR), &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != sizeof(WCHAR))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write open bracket with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// key name
|
|
dwTemp = (lstrlen (lpKeyName) + 1) * sizeof (WCHAR);
|
|
if (!WriteFile (hFile, lpKeyName, dwTemp, &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != dwTemp)
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write key name with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// semicolon
|
|
if (!WriteFile (hFile, &cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != sizeof(WCHAR))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write semicolon with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
// value name
|
|
dwTemp = (lstrlen (lpValueName) + 1) * sizeof (WCHAR);
|
|
if (!WriteFile (hFile, lpValueName, dwTemp, &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != dwTemp)
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write value name with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// semicolon
|
|
if (!WriteFile (hFile, &cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != sizeof(WCHAR))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write semicolon with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
// type
|
|
if (!WriteFile (hFile, &dwType, sizeof(DWORD), &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != sizeof(DWORD))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write data type with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
// semicolon
|
|
if (!WriteFile (hFile, &cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != sizeof(WCHAR))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write semicolon with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
// data length
|
|
if (!WriteFile (hFile, &dwDataLength, sizeof(DWORD), &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != sizeof(DWORD))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write data type with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
// semicolon
|
|
if (!WriteFile (hFile, &cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != sizeof(WCHAR))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write semicolon with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
// data
|
|
if (!WriteFile (hFile, lpData, dwDataLength, &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != dwDataLength)
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write data with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
// close bracket
|
|
if (!WriteFile (hFile, &cCloseBracket, sizeof(WCHAR), &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != sizeof(WCHAR))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write close bracket with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Sucess
|
|
//
|
|
|
|
bResult = TRUE;
|
|
|
|
Exit:
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// ParseRegistryFile()
|
|
//
|
|
// Purpose: Parses a registry.pol file
|
|
//
|
|
// Parameters: lpGPOInfo - GPO information
|
|
// lpRegistry - Path to registry.pol
|
|
// pfnRegFileCallback - Callback function
|
|
// hArchive - Handle to archive file
|
|
// pwszGPO - Gpo
|
|
// pwszSOM - Sdou that the Gpo is linked to
|
|
// pHashTable - Hash table for registry keys
|
|
//
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ParseRegistryFile (LPGPOINFO lpGPOInfo, LPTSTR lpRegistry,
|
|
PFNREGFILECALLBACK pfnRegFileCallback,
|
|
HANDLE hArchive, WCHAR *pwszGPO,
|
|
WCHAR *pwszSOM, REGHASHTABLE *pHashTable,
|
|
BOOL bRsopPlanningMode)
|
|
{
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
BOOL bResult = FALSE;
|
|
DWORD dwTemp, dwBytesRead, dwType, dwDataLength;
|
|
LPWSTR lpKeyName = 0, lpValueName = 0, lpTemp;
|
|
LPBYTE lpData = NULL;
|
|
WCHAR chTemp;
|
|
HANDLE hOldToken;
|
|
XLastError xe;
|
|
|
|
|
|
//
|
|
// Verbose output
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ParseRegistryFile: Entering with <%s>."),
|
|
lpRegistry));
|
|
|
|
|
|
//
|
|
// Open the registry file
|
|
//
|
|
|
|
if(!bRsopPlanningMode) {
|
|
if (!ImpersonateUser(lpGPOInfo->hToken, &hOldToken)) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to impersonate user")));
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
hFile = CreateFile (lpRegistry, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL);
|
|
|
|
if(!bRsopPlanningMode) {
|
|
RevertToUser(&hOldToken);
|
|
}
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
if ((GetLastError() == ERROR_FILE_NOT_FOUND) ||
|
|
(GetLastError() == ERROR_PATH_NOT_FOUND))
|
|
{
|
|
bResult = TRUE;
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: CreateFile failed with %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_NO_REGISTRY);
|
|
ev.AddArg(lpRegistry); ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate buffers to hold the keyname, valuename, and data
|
|
//
|
|
|
|
lpKeyName = (LPWSTR) LocalAlloc (LPTR, MAX_KEYNAME_SIZE * sizeof(WCHAR));
|
|
|
|
if (!lpKeyName)
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to allocate memory with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
lpValueName = (LPWSTR) LocalAlloc (LPTR, MAX_VALUENAME_SIZE * sizeof(WCHAR));
|
|
|
|
if (!lpValueName)
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to allocate memory with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Read the header block
|
|
//
|
|
// 2 DWORDS, signature (PReg) and version number and 2 newlines
|
|
//
|
|
|
|
if (!ReadFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesRead, NULL) ||
|
|
dwBytesRead != sizeof(dwTemp))
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read signature with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
if (dwTemp != REGFILE_SIGNATURE)
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Invalid file signature")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
if (!ReadFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesRead, NULL) ||
|
|
dwBytesRead != sizeof(dwTemp))
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read version number with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
if (dwTemp != REGISTRY_FILE_VERSION)
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Invalid file version")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Read the data
|
|
//
|
|
|
|
while (TRUE)
|
|
{
|
|
|
|
//
|
|
// Read the first character. It will either be a [ or the end
|
|
// of the file.
|
|
//
|
|
|
|
if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
|
|
{
|
|
if (GetLastError() != ERROR_HANDLE_EOF)
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read first character with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ((dwBytesRead == 0) || (chTemp != L'['))
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Read the keyname
|
|
//
|
|
|
|
lpTemp = lpKeyName;
|
|
dwTemp = 0;
|
|
|
|
while (dwTemp < MAX_KEYNAME_SIZE)
|
|
{
|
|
|
|
if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read keyname character with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
*lpTemp++ = chTemp;
|
|
|
|
if (chTemp == TEXT('\0'))
|
|
break;
|
|
|
|
dwTemp++;
|
|
}
|
|
|
|
if (dwTemp >= MAX_KEYNAME_SIZE)
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Keyname exceeded max size")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Read the semi-colon
|
|
//
|
|
|
|
if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
|
|
{
|
|
if (GetLastError() != ERROR_HANDLE_EOF)
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read first character with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ((dwBytesRead == 0) || (chTemp != L';'))
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Read the valuename
|
|
//
|
|
|
|
lpTemp = lpValueName;
|
|
dwTemp = 0;
|
|
|
|
while (dwTemp < MAX_VALUENAME_SIZE)
|
|
{
|
|
|
|
if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read valuename character with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
*lpTemp++ = chTemp;
|
|
|
|
if (chTemp == TEXT('\0'))
|
|
break;
|
|
|
|
dwTemp++;
|
|
}
|
|
|
|
if (dwTemp >= MAX_VALUENAME_SIZE)
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Valuename exceeded max size")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Read the semi-colon
|
|
//
|
|
|
|
if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
|
|
{
|
|
if (GetLastError() != ERROR_HANDLE_EOF)
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read first character with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ((dwBytesRead == 0) || (chTemp != L';'))
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Read the type
|
|
//
|
|
|
|
if (!ReadFile (hFile, &dwType, sizeof(DWORD), &dwBytesRead, NULL))
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read type with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Skip semicolon
|
|
//
|
|
|
|
if (!ReadFile (hFile, &dwTemp, sizeof(WCHAR), &dwBytesRead, NULL))
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to skip semicolon with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Read the data length
|
|
//
|
|
|
|
if (!ReadFile (hFile, &dwDataLength, sizeof(DWORD), &dwBytesRead, NULL))
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to data length with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Skip semicolon
|
|
//
|
|
|
|
if (!ReadFile (hFile, &dwTemp, sizeof(WCHAR), &dwBytesRead, NULL))
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to skip semicolon with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate memory for data
|
|
//
|
|
|
|
lpData = (LPBYTE) LocalAlloc (LPTR, dwDataLength);
|
|
|
|
if (!lpData)
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to allocate memory for data with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Read data
|
|
//
|
|
|
|
if (!ReadFile (hFile, lpData, dwDataLength, &dwBytesRead, NULL))
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read data with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Skip closing bracket
|
|
//
|
|
|
|
if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to skip closing bracket with %d"),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
if (chTemp != L']')
|
|
{
|
|
xe = ERROR_INVALID_DATA;
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Expected to find ], but found %c"),
|
|
chTemp));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Call the callback function
|
|
//
|
|
|
|
if (!pfnRegFileCallback (lpGPOInfo, lpKeyName, lpValueName,
|
|
dwType, dwDataLength, lpData,
|
|
pwszGPO, pwszSOM, pHashTable ))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Callback function returned false.")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Archive the data if appropriate
|
|
//
|
|
|
|
if (hArchive) {
|
|
if (!ArchiveRegistryValue(hArchive, lpKeyName, lpValueName,
|
|
dwType, dwDataLength, lpData)) {
|
|
DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: ArchiveRegistryValue returned false.")));
|
|
}
|
|
}
|
|
|
|
LocalFree (lpData);
|
|
lpData = NULL;
|
|
|
|
}
|
|
|
|
bResult = TRUE;
|
|
|
|
Exit:
|
|
|
|
//
|
|
// Finished
|
|
//
|
|
|
|
if ( !bResult )
|
|
{
|
|
CEvents ev(TRUE, EVENT_REGISTRY_TEMPLATE_ERROR);
|
|
ev.AddArg(lpRegistry ? lpRegistry : TEXT("")); ev.AddArgWin32Error( xe ); ev.Report();
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ParseRegistryFile: Leaving.")));
|
|
if (lpData) {
|
|
LocalFree (lpData);
|
|
}
|
|
if ( hFile != INVALID_HANDLE_VALUE ) {
|
|
CloseHandle (hFile);
|
|
}
|
|
if ( lpKeyName ) {
|
|
LocalFree (lpKeyName);
|
|
}
|
|
if ( lpValueName ) {
|
|
LocalFree (lpValueName);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// ProcessRegistryValue()
|
|
//
|
|
// Purpose: Callback passed to ParseRegistryFile from ProcessRegistryFiles. Invokes AddRegHashEntry
|
|
// with appropriate parameters depending on the registry policy settings.
|
|
//
|
|
// Parameters:
|
|
// pUnused - Not used. It si there only to conform to the signature
|
|
// expected by ParseRegistryFile.
|
|
// lpKeyName - registry key name
|
|
// lpValueName - Registry value name
|
|
// dwType - Registry value type
|
|
// dwDataLength - Length of registry value data.
|
|
// lpData - Regsitry value data
|
|
// *pwszGPO - GPO associated with this registry setting
|
|
// *pwszSOM - SOM associated with the GPO
|
|
// *pHashTable - Hash table containing registry policy data for a policy target.
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ProcessRegistryValue ( void* pUnused,
|
|
LPTSTR lpKeyName,
|
|
LPTSTR lpValueName,
|
|
DWORD dwType,
|
|
DWORD dwDataLength,
|
|
LPBYTE lpData,
|
|
WCHAR *pwszGPO,
|
|
WCHAR *pwszSOM,
|
|
REGHASHTABLE *pHashTable)
|
|
{
|
|
BOOL bLoggingOk = TRUE;
|
|
BOOL bStatus;
|
|
|
|
//
|
|
// Special case some values
|
|
//
|
|
|
|
if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**del."), 6, lpValueName, 6) == 2)
|
|
{
|
|
LPTSTR lpRealValueName = lpValueName + 6;
|
|
|
|
|
|
//
|
|
// Delete one specific value
|
|
//
|
|
|
|
bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEVALUE, lpKeyName,
|
|
lpRealValueName, 0, 0, NULL,
|
|
pwszGPO, pwszSOM, lpValueName, TRUE );
|
|
}
|
|
else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**delvals."), 10, lpValueName, 10) == 2)
|
|
{
|
|
|
|
//
|
|
// Delete all values in the destination key
|
|
//
|
|
|
|
bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEALLVALUES, lpKeyName,
|
|
NULL, 0, 0, NULL,
|
|
pwszGPO, pwszSOM, lpValueName, TRUE );
|
|
|
|
}
|
|
else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**DeleteValues"), 14, lpValueName, 14) == 2)
|
|
{
|
|
TCHAR szValueName[MAX_VALUENAME_SIZE];
|
|
|
|
bLoggingOk = TRUE;
|
|
|
|
while ( *lpData )
|
|
{
|
|
bStatus = ExtractKeyOrValueName( &lpData, szValueName, MAX_VALUENAME_SIZE );
|
|
|
|
// This failure must be fatal.
|
|
if ( ! bStatus )
|
|
{
|
|
bLoggingOk = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Failures here have always allowed processing to continue. Not sure
|
|
// why, but not worth risking some wierd regression to change it.
|
|
//
|
|
bStatus = AddRegHashEntry( pHashTable, REG_DELETEVALUE, lpKeyName,
|
|
szValueName, 0, 0, NULL,
|
|
pwszGPO, pwszSOM, lpValueName, TRUE );
|
|
if ( ! bStatus )
|
|
bLoggingOk = FALSE;
|
|
}
|
|
}
|
|
|
|
else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**DeleteKeys"), 12, lpValueName, 12) == 2)
|
|
{
|
|
TCHAR szKeyName[MAX_KEYNAME_SIZE];
|
|
|
|
bLoggingOk = TRUE;
|
|
|
|
while ( *lpData )
|
|
{
|
|
bStatus = ExtractKeyOrValueName( &lpData, szKeyName, MAX_KEYNAME_SIZE );
|
|
|
|
// This failure must be fatal.
|
|
if ( ! bStatus )
|
|
{
|
|
bLoggingOk = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Failures here have always allowed processing to continue. Not sure
|
|
// why, but not worth risking some wierd regression to change it.
|
|
//
|
|
bStatus = AddRegHashEntry( pHashTable, REG_DELETEKEY, lpKeyName,
|
|
NULL, 0, 0, NULL,
|
|
pwszGPO, pwszSOM, lpValueName, TRUE );
|
|
if ( ! bStatus )
|
|
bLoggingOk = FALSE;
|
|
}
|
|
}
|
|
else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**soft."), 7, lpValueName, 7) == 2)
|
|
{
|
|
//
|
|
// In planning mode we will assume the value does not exist in the target computer.
|
|
// Therefore, we set it if no value exists in the hash table.
|
|
//
|
|
// Soft add is dealt with differently in planning mode vs. diag mode.
|
|
// In diag mode, check is done while processing policy and it is logged as a add value
|
|
// if the key doesn't exist.
|
|
// In planning mode, key is not supposed to exist beforehand and the hash table itself is
|
|
// used to determine whether to add the key or not.
|
|
|
|
|
|
LPTSTR lpRealValueName = lpValueName + 7;
|
|
|
|
bLoggingOk = AddRegHashEntry( pHashTable, REG_SOFTADDVALUE, lpKeyName,
|
|
lpRealValueName, dwType, dwDataLength, lpData,
|
|
pwszGPO, pwszSOM, lpValueName, TRUE );
|
|
|
|
}
|
|
else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**SecureKey"), 11, lpValueName, 11) == 2)
|
|
{
|
|
// There is nothing to do here.
|
|
} else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**Comment:"), 10, lpValueName, 10) == 2)
|
|
{
|
|
//
|
|
// Comment - can be ignored
|
|
//
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// AddRegHashEntry needs to log a key being logged but no values.
|
|
//
|
|
|
|
bLoggingOk = AddRegHashEntry( pHashTable, REG_ADDVALUE, lpKeyName,
|
|
lpValueName, dwType, dwDataLength, lpData,
|
|
pwszGPO, pwszSOM, TEXT(""), TRUE );
|
|
}
|
|
|
|
return bLoggingOk;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// ResetRegKeySecurity
|
|
//
|
|
// Purpose: Resets the security on a user's key
|
|
//
|
|
// Parameters: hKeyRoot - Handle to the root of the hive
|
|
// lpKeyName - Subkey name
|
|
//
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ResetRegKeySecurity (HKEY hKeyRoot, LPTSTR lpKeyName)
|
|
{
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
DWORD dwSize = 0;
|
|
LONG lResult;
|
|
HKEY hSubKey;
|
|
XLastError xe;
|
|
|
|
|
|
RegGetKeySecurity(hKeyRoot, DACL_SECURITY_INFORMATION, pSD, &dwSize);
|
|
|
|
if (!dwSize) {
|
|
DebugMsg((DM_WARNING, TEXT("ResetRegKeySecurity: RegGetKeySecurity returned 0")));
|
|
return FALSE;
|
|
}
|
|
|
|
pSD = LocalAlloc (LPTR, dwSize);
|
|
|
|
if (!pSD) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ResetRegKeySecurity: Failed to allocate memory")));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
lResult = RegGetKeySecurity(hKeyRoot, DACL_SECURITY_INFORMATION, pSD, &dwSize);
|
|
if (lResult != ERROR_SUCCESS) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ResetRegKeySecurity: Failed to query key security with %d"),
|
|
lResult));
|
|
LocalFree (pSD);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
lResult = RegOpenKeyEx(hKeyRoot,
|
|
lpKeyName,
|
|
0,
|
|
WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL,
|
|
&hSubKey);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ResetRegKeySecurity: Failed to open sub key with %d"),
|
|
lResult));
|
|
LocalFree (pSD);
|
|
return FALSE;
|
|
}
|
|
|
|
lResult = RegSetKeySecurity (hSubKey, DACL_SECURITY_INFORMATION, pSD);
|
|
|
|
RegCloseKey (hSubKey);
|
|
LocalFree (pSD);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ResetRegKeySecure: Failed to set security, error = %d"), lResult));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// SetRegistryValue()
|
|
//
|
|
// Purpose: Callback from ParseRegistryFile that sets
|
|
// registry policies
|
|
//
|
|
// Parameters: lpGPOInfo - GPO Information
|
|
// lpKeyName - Key name
|
|
// lpValueName - Value name
|
|
// dwType - Registry data type
|
|
// lpData - Registry data
|
|
// pwszGPO - Gpo
|
|
// pwszSOM - Sdou that the Gpo is linked to
|
|
// pHashTable - Hash table for registry keys
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL SetRegistryValue (LPGPOINFO lpGPOInfo, LPTSTR lpKeyName,
|
|
LPTSTR lpValueName, DWORD dwType,
|
|
DWORD dwDataLength, LPBYTE lpData,
|
|
WCHAR *pwszGPO,
|
|
WCHAR *pwszSOM, REGHASHTABLE *pHashTable)
|
|
{
|
|
DWORD dwDisp;
|
|
HKEY hSubKey;
|
|
LONG lResult;
|
|
BOOL bLoggingOk = TRUE;
|
|
BOOL bRsopLogging = (pHashTable != NULL); // Is diagnostic mode Rsop logging enabled ?
|
|
BOOL bUseValueName = FALSE;
|
|
BOOL bRegOpSuccess = TRUE;
|
|
XLastError xe;
|
|
|
|
//
|
|
// Special case some values
|
|
//
|
|
if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**del."), 6, lpValueName, 6) == 2)
|
|
{
|
|
LPTSTR lpRealValueName = lpValueName + 6;
|
|
|
|
//
|
|
// Delete one specific value
|
|
//
|
|
|
|
lResult = RegOpenKeyEx (lpGPOInfo->hKeyRoot,
|
|
lpKeyName, 0, KEY_WRITE, &hSubKey);
|
|
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
lResult = RegDeleteValue(hSubKey, lpRealValueName);
|
|
|
|
if ((lResult == ERROR_SUCCESS) || (lResult == ERROR_FILE_NOT_FOUND))
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Deleted value <%s>."),
|
|
lpRealValueName));
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
CEvents ev(FALSE, EVENT_DELETED_VALUE);
|
|
ev.AddArg(lpRealValueName); ev.Report();
|
|
}
|
|
|
|
if ( bRsopLogging ) {
|
|
bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEVALUE, lpKeyName,
|
|
lpRealValueName, 0, 0, NULL,
|
|
pwszGPO, pwszSOM, lpValueName, TRUE );
|
|
if (!bLoggingOk) {
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_DELETEVALUE <%s>."), lpRealValueName));
|
|
pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: Failed to delete value <%s> with %d"),
|
|
lpRealValueName, lResult));
|
|
xe = lResult;
|
|
CEvents ev(TRUE, EVENT_FAIL_DELETE_VALUE);
|
|
ev.AddArg(lpRealValueName); ev.AddArgWin32Error(lResult); ev.Report();
|
|
bRegOpSuccess = FALSE;
|
|
}
|
|
|
|
RegCloseKey (hSubKey);
|
|
}
|
|
else if (lResult == ERROR_FILE_NOT_FOUND) {
|
|
|
|
//
|
|
// Log into rsop even if the key is not found
|
|
//
|
|
|
|
if ( bRsopLogging ) {
|
|
bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEVALUE, lpKeyName,
|
|
lpRealValueName, 0, 0, NULL,
|
|
pwszGPO, pwszSOM, lpValueName, TRUE );
|
|
if (!bLoggingOk) {
|
|
pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_DELETEVALUE (notfound) <%s>."), lpRealValueName));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**delvals."), 10, lpValueName, 10) == 2)
|
|
{
|
|
|
|
//
|
|
// Delete all values in the destination key
|
|
//
|
|
lResult = RegOpenKeyEx (lpGPOInfo->hKeyRoot,
|
|
lpKeyName, 0, KEY_WRITE | KEY_READ, &hSubKey);
|
|
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
if (!bRsopLogging)
|
|
bRegOpSuccess = DeleteAllValues(hSubKey);
|
|
else
|
|
bRegOpSuccess = RsopDeleteAllValues(hSubKey, pHashTable, lpKeyName,
|
|
pwszGPO, pwszSOM, lpValueName, &bLoggingOk );
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Deleted all values in <%s>."),
|
|
lpKeyName));
|
|
RegCloseKey (hSubKey);
|
|
|
|
if (!bRegOpSuccess) {
|
|
xe = GetLastError();
|
|
}
|
|
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: DeleteAllvalues finished for %s. bRegOpSuccess = %s, bLoggingOk = %s."),
|
|
lpKeyName, (bRegOpSuccess ? TEXT("TRUE") : TEXT("FALSE")), (bLoggingOk ? TEXT("TRUE") : TEXT("FALSE"))));
|
|
|
|
}
|
|
else if (lResult == ERROR_FILE_NOT_FOUND) {
|
|
|
|
//
|
|
// Log into rsop even if the key is not found
|
|
// as just deleteallvalues
|
|
//
|
|
|
|
if ( bRsopLogging ) {
|
|
bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEALLVALUES, lpKeyName,
|
|
NULL, 0, 0, NULL,
|
|
pwszGPO, pwszSOM, lpValueName, TRUE );
|
|
|
|
if (!bLoggingOk) {
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_DELETEALLVALUES (notfound) key - <%s>, value <%s>."), lpKeyName, lpValueName));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**DeleteValues"), 14, lpValueName, 14) == 2)
|
|
{
|
|
TCHAR szValueName[MAX_VALUENAME_SIZE];
|
|
LONG lKeyResult;
|
|
|
|
//
|
|
// Delete the values (semi-colon separated)
|
|
//
|
|
|
|
lKeyResult = RegOpenKeyEx (lpGPOInfo->hKeyRoot,
|
|
lpKeyName, 0, KEY_WRITE, &hSubKey);
|
|
|
|
while ( *lpData )
|
|
{
|
|
szValueName[0] = 0;
|
|
|
|
if ( ExtractKeyOrValueName( &lpData, szValueName, MAX_VALUENAME_SIZE ) )
|
|
lResult = ERROR_SUCCESS;
|
|
else
|
|
lResult = ERROR_INVALID_DATA;
|
|
|
|
// Check for OpenKey failures.
|
|
if ( (lResult == ERROR_SUCCESS) &&
|
|
(lKeyResult != ERROR_SUCCESS) && (lKeyResult != ERROR_FILE_NOT_FOUND) )
|
|
lResult = lKeyResult;
|
|
|
|
if ( (lKeyResult == ERROR_SUCCESS) && (lResult == ERROR_SUCCESS) )
|
|
{
|
|
lResult = RegDeleteValue (hSubKey, szValueName);
|
|
|
|
if ((lResult == ERROR_SUCCESS) || (lResult == ERROR_FILE_NOT_FOUND))
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Deleted value <%s>."),
|
|
szValueName));
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
CEvents ev(FALSE, EVENT_DELETED_VALUE);
|
|
ev.AddArg(szValueName); ev.Report();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Checking if value name is valid, key open succeeded, and no unexpected
|
|
// error from value deletion. Note that lKeyResult is not needed because
|
|
// it's value was factored into lResult above.
|
|
//
|
|
if ( (lResult == ERROR_SUCCESS) || (lResult == ERROR_FILE_NOT_FOUND) )
|
|
{
|
|
if ( bRsopLogging ) {
|
|
bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEVALUE, lpKeyName,
|
|
szValueName, 0, 0, NULL,
|
|
pwszGPO, pwszSOM, lpValueName, TRUE );
|
|
|
|
if (!bLoggingOk)
|
|
{
|
|
//
|
|
// The debug message has always been different for the case where the key
|
|
// existed and where the key did not exist. This is merging what used
|
|
// to be duplicated code.
|
|
//
|
|
if ( ERROR_SUCCESS == lKeyResult )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_DELETEVALUE value <%s>."), szValueName));
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_DELETEVALUE value (not found case) <%s>."), szValueName));
|
|
}
|
|
pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: Failed to delete value <%s> with %d"),
|
|
szValueName, lResult));
|
|
CEvents ev(TRUE, EVENT_FAIL_DELETE_VALUE);
|
|
ev.AddArg(szValueName); ev.AddArgWin32Error(lResult); ev.Report();
|
|
xe = lResult;
|
|
bRegOpSuccess = FALSE;
|
|
if ( ERROR_INVALID_DATA == lResult )
|
|
break;
|
|
}
|
|
}
|
|
|
|
// lKeyResult is not changed after the intial call to RegOpenKey.
|
|
if (lKeyResult == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey (hSubKey);
|
|
}
|
|
}
|
|
else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**DeleteKeys"), 12, lpValueName, 12) == 2)
|
|
{
|
|
TCHAR szKeyName[MAX_KEYNAME_SIZE];
|
|
BOOL bStatus;
|
|
|
|
while ( *lpData )
|
|
{
|
|
bStatus = ExtractKeyOrValueName( &lpData, szKeyName, MAX_KEYNAME_SIZE );
|
|
|
|
if ( bStatus )
|
|
{
|
|
lResult = RegDelnode (lpGPOInfo->hKeyRoot, szKeyName);
|
|
if ( ERROR_SUCCESS == lResult )
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Deleted key <%s>."),
|
|
szKeyName));
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
CEvents ev(FALSE, EVENT_DELETED_KEY);
|
|
ev.AddArg(szKeyName); ev.Report();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lResult = ERROR_INVALID_DATA;
|
|
}
|
|
|
|
if ( lResult != ERROR_SUCCESS )
|
|
{
|
|
xe = lResult;
|
|
bRegOpSuccess = FALSE;
|
|
// This is fatal and we must bail out, szKeyName is bad so skip the DebugMsg.
|
|
if ( ERROR_INVALID_DATA == lResult )
|
|
break;
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: RegDelnode for key <%s>."), szKeyName));
|
|
}
|
|
|
|
if ( bRsopLogging ) {
|
|
bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEKEY, szKeyName,
|
|
NULL, 0, 0, NULL,
|
|
pwszGPO, pwszSOM, lpValueName, TRUE );
|
|
if (!bLoggingOk) {
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_DELETEKEY <%s>."), szKeyName));
|
|
pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**soft."), 7, lpValueName, 7) == 2)
|
|
{
|
|
|
|
//
|
|
// "soft" value, only set this if it doesn't already
|
|
// exist in destination
|
|
//
|
|
|
|
lResult = RegOpenKeyEx (lpGPOInfo->hKeyRoot,
|
|
lpKeyName, 0, KEY_QUERY_VALUE, &hSubKey);
|
|
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
TCHAR TmpValueData[MAX_PATH+1];
|
|
DWORD dwSize=sizeof(TmpValueData);
|
|
|
|
lResult = RegQueryValueEx(hSubKey, lpValueName + 7,
|
|
NULL,NULL,(LPBYTE) TmpValueData,
|
|
&dwSize);
|
|
|
|
RegCloseKey (hSubKey);
|
|
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
lpValueName += 7;
|
|
bUseValueName = TRUE;
|
|
goto SetValue;
|
|
}
|
|
}
|
|
}
|
|
else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**SecureKey"), 11, lpValueName, 11) == 2)
|
|
{
|
|
//
|
|
// Secure / unsecure a key (user only)
|
|
//
|
|
if (!(lpGPOInfo->dwFlags & GP_MACHINE))
|
|
{
|
|
if (*((LPDWORD)lpData) == 1)
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Securing key <%s>."),
|
|
lpKeyName));
|
|
bRegOpSuccess = MakeRegKeySecure(lpGPOInfo->hToken, lpGPOInfo->hKeyRoot, lpKeyName);
|
|
}
|
|
else
|
|
{
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Unsecuring key <%s>."),
|
|
lpKeyName));
|
|
|
|
bRegOpSuccess = ResetRegKeySecurity (lpGPOInfo->hKeyRoot, lpKeyName);
|
|
}
|
|
|
|
if (!bRegOpSuccess) {
|
|
xe = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("**Comment:"), 10, lpValueName, 10) == 2)
|
|
{
|
|
//
|
|
// Comment - can be ignored
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Found comment %s."),
|
|
(lpValueName+10)));
|
|
}
|
|
else
|
|
{
|
|
SetValue:
|
|
//
|
|
// Save registry value
|
|
//
|
|
|
|
lResult = RegCreateKeyEx (lpGPOInfo->hKeyRoot,
|
|
lpKeyName, 0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE, NULL, &hSubKey, &dwDisp);
|
|
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
|
|
if ((dwType == REG_NONE) && (dwDataLength == 0) &&
|
|
(*lpValueName == L'\0'))
|
|
{
|
|
lResult = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
lResult = RegSetValueEx (hSubKey, lpValueName, 0, dwType,
|
|
lpData, dwDataLength);
|
|
}
|
|
|
|
if ( bRsopLogging ) {
|
|
bLoggingOk = AddRegHashEntry( pHashTable, REG_ADDVALUE, lpKeyName,
|
|
lpValueName, dwType, dwDataLength, lpData,
|
|
pwszGPO, pwszSOM, bUseValueName ? lpValueName : TEXT(""), TRUE );
|
|
if (!bLoggingOk) {
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_ADDVALUE key <%s>, value <%s>."), lpKeyName, lpValueName));
|
|
pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
|
|
RegCloseKey (hSubKey);
|
|
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
switch (dwType) {
|
|
case REG_SZ:
|
|
case REG_EXPAND_SZ:
|
|
DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: %s => %s [OK]"),
|
|
lpValueName, (LPTSTR)lpData));
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
CEvents ev(FALSE, EVENT_SET_STRING_VALUE);
|
|
ev.AddArg(lpValueName); ev.AddArg((LPTSTR)lpData); ev.Report();
|
|
}
|
|
|
|
break;
|
|
|
|
case REG_DWORD:
|
|
DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: %s => %d [OK]"),
|
|
lpValueName, *((LPDWORD)lpData)));
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
CEvents ev(FALSE, EVENT_SET_DWORD_VALUE);
|
|
ev.AddArg(lpValueName); ev.AddArg((DWORD)*lpData); ev.Report();
|
|
}
|
|
|
|
break;
|
|
|
|
case REG_NONE:
|
|
break;
|
|
|
|
default:
|
|
DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: %s was set successfully"),
|
|
lpValueName));
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
CEvents ev(FALSE, EVENT_SET_UNKNOWN_VALUE);
|
|
ev.AddArg(lpValueName); ev.Report();
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("Control Panel\\Colors"), 20, lpKeyName, 20) == 2) {
|
|
lpGPOInfo->dwFlags |= GP_REGPOLICY_CPANEL;
|
|
|
|
} else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
|
|
TEXT("Control Panel\\Desktop"), 21, lpKeyName, 21) == 2) {
|
|
lpGPOInfo->dwFlags |= GP_REGPOLICY_CPANEL;
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: Failed to set value <%s> with %d"),
|
|
lpValueName, lResult));
|
|
xe = lResult;
|
|
CEvents ev(TRUE, EVENT_FAILED_SET);
|
|
ev.AddArg(lpValueName); ev.AddArgWin32Error(lResult); ev.Report();
|
|
bRegOpSuccess = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("SetRegistryValue: Failed to open key <%s> with %d"),
|
|
lpKeyName, lResult));
|
|
xe = lResult;
|
|
CEvents ev(TRUE, EVENT_FAILED_CREATE);
|
|
ev.AddArg(lpKeyName); ev.AddArgWin32Error(lResult); ev.Report();
|
|
bRegOpSuccess = FALSE;
|
|
}
|
|
}
|
|
|
|
return bLoggingOk && bRegOpSuccess;
|
|
}
|
|
|
|
BOOL ExtractKeyOrValueName( LPBYTE * ppData, LPTSTR pszName, DWORD dwNameCch )
|
|
{
|
|
LPTSTR lpszNameBegin, lpszNameEnd;
|
|
|
|
lpszNameBegin = (LPTSTR) *ppData;
|
|
|
|
while ( *lpszNameBegin == TEXT(' ') )
|
|
lpszNameBegin++;
|
|
|
|
lpszNameEnd = lpszNameBegin;
|
|
|
|
while ( *lpszNameEnd && *lpszNameEnd != TEXT(';') )
|
|
lpszNameEnd++;
|
|
|
|
if ( dwNameCch < (DWORD) (lpszNameEnd - lpszNameBegin + 1) )
|
|
{
|
|
DebugMsg((DM_WARNING,
|
|
TEXT("Key or value name %s of size %d exceeds maximum. Further processing aborted."),
|
|
pszName,
|
|
lpszNameEnd - lpszNameBegin));
|
|
return FALSE;
|
|
}
|
|
|
|
(void) StringCchCopyN( pszName, dwNameCch, lpszNameBegin, lpszNameEnd - lpszNameBegin );
|
|
pszName[lpszNameEnd - lpszNameBegin] = 0;
|
|
|
|
while ( *lpszNameEnd == TEXT(';') )
|
|
lpszNameEnd++;
|
|
|
|
*ppData = (LPBYTE) lpszNameEnd;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// ProcessGPORegistryPolicy()
|
|
//
|
|
// Purpose: Proceses GPO registry policy
|
|
//
|
|
// Parameters: lpGPOInfo - GPO information
|
|
// pChangedGPOList - Link list of changed GPOs
|
|
//
|
|
// Notes: This function is called in the context of
|
|
// local system, which allows us to create the
|
|
// directory, write to the file etc.
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ProcessGPORegistryPolicy (LPGPOINFO lpGPOInfo,
|
|
PGROUP_POLICY_OBJECT pChangedGPOList, HRESULT *phrRsopLogging)
|
|
{
|
|
PGROUP_POLICY_OBJECT lpGPO;
|
|
TCHAR szPath[MAX_PATH];
|
|
TCHAR szBuffer[MAX_PATH];
|
|
TCHAR szKeyName[100];
|
|
LPTSTR lpEnd, lpGPOComment;
|
|
HANDLE hFile;
|
|
DWORD dwTemp, dwBytesWritten;
|
|
REGHASHTABLE *pHashTable = NULL;
|
|
WIN32_FIND_DATA findData;
|
|
ADMFILEINFO *pAdmFileCache = NULL;
|
|
XLastError xe;
|
|
HRESULT hr = S_OK;
|
|
BOOL bStatus = FALSE;
|
|
|
|
*phrRsopLogging = S_OK;
|
|
|
|
//
|
|
// Claim the registry lock before starting registry processing -- this will
|
|
// allow internal components to synchronize on registry processing rather than
|
|
// all policy processing, which means a much shorter wait time
|
|
//
|
|
// We wait for 60 seconds -- if the application does not release the lock
|
|
// in that time, we continue, as 60 seconds should be sufficient to read
|
|
// a few registry settings
|
|
//
|
|
|
|
HANDLE hRegistrySection = EnterCriticalPolicySectionEx(
|
|
lpGPOInfo->dwFlags & GP_MACHINE,
|
|
60000,
|
|
ECP_REGISTRY_ONLY);
|
|
|
|
if ( ! hRegistrySection )
|
|
{
|
|
goto ProcessGPORegistryPolicy_Exit;
|
|
}
|
|
|
|
//
|
|
// Get the path name to the appropriate profile
|
|
//
|
|
|
|
szPath[0] = TEXT('\0');
|
|
dwTemp = ARRAYSIZE(szPath);
|
|
|
|
if (lpGPOInfo->dwFlags & GP_MACHINE) {
|
|
GetAllUsersProfileDirectoryEx(szPath, &dwTemp, TRUE);
|
|
} else {
|
|
GetUserProfileDirectory(lpGPOInfo->hToken, szPath, &dwTemp);
|
|
}
|
|
|
|
if (szPath[0] == TEXT('\0')) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: Failed to get path to profile root")));
|
|
goto ProcessGPORegistryPolicy_Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Tack on the archive file name
|
|
//
|
|
|
|
DmAssert( lstrlen(szPath) + lstrlen(TEXT("\\ntuser.pol")) < MAX_PATH );
|
|
|
|
hr = StringCchCat (szPath, sizeof(szPath)/sizeof(WCHAR), TEXT("\\ntuser.pol"));
|
|
if (FAILED(hr)) {
|
|
xe = HRESULT_CODE(hr);
|
|
goto ProcessGPORegistryPolicy_Exit;
|
|
}
|
|
|
|
//
|
|
// Delete any existing policies
|
|
//
|
|
|
|
if (!ResetPolicies (lpGPOInfo, szPath)) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: ResetPolicies failed.")));
|
|
// couldn't undo the values set in local ntuser.pol
|
|
// seems like the best we can do is abandon cleanup and
|
|
// and apply new policies.
|
|
// If we return here, the user has a better chance of not
|
|
// getting tattooed though...
|
|
|
|
// event is already logged
|
|
}
|
|
|
|
|
|
//
|
|
// Delete the old archive file
|
|
//
|
|
|
|
SetFileAttributes (szPath, FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFile (szPath);
|
|
|
|
//
|
|
// Recreate the archive file
|
|
//
|
|
|
|
hFile = CreateFile (szPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL);
|
|
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: Failed to create archive file with %d"),
|
|
GetLastError()));
|
|
goto ProcessGPORegistryPolicy_Exit;
|
|
}
|
|
|
|
//
|
|
// Set the header information in the archive file
|
|
//
|
|
|
|
dwTemp = REGFILE_SIGNATURE;
|
|
|
|
if (!WriteFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != sizeof(dwTemp))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: Failed to write signature with %d"),
|
|
GetLastError()));
|
|
CloseHandle (hFile);
|
|
goto ProcessGPORegistryPolicy_Exit;
|
|
}
|
|
|
|
|
|
dwTemp = REGISTRY_FILE_VERSION;
|
|
|
|
if (!WriteFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesWritten, NULL) ||
|
|
dwBytesWritten != sizeof(dwTemp))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: Failed to write version number with %d"),
|
|
GetLastError()));
|
|
CloseHandle (hFile);
|
|
goto ProcessGPORegistryPolicy_Exit;
|
|
}
|
|
|
|
if ( lpGPOInfo->pWbemServices ) {
|
|
|
|
//
|
|
// If Rsop logging is enabled, setup hash table
|
|
//
|
|
|
|
pHashTable = AllocHashTable();
|
|
if ( pHashTable == NULL ) {
|
|
CloseHandle (hFile);
|
|
*phrRsopLogging = HRESULT_FROM_WIN32(GetLastError());
|
|
xe = GetLastError();
|
|
goto ProcessGPORegistryPolicy_Exit;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Now loop through the GPOs applying the registry.pol files
|
|
//
|
|
|
|
lpGPO = pChangedGPOList;
|
|
|
|
while ( lpGPO ) {
|
|
|
|
//
|
|
// Add the source GPO comment
|
|
//
|
|
DWORD dwCommentLength = lstrlen(lpGPO->lpDisplayName) + 25;
|
|
lpGPOComment = (LPTSTR) LocalAlloc (LPTR, (dwCommentLength) * sizeof(TCHAR));
|
|
|
|
if (lpGPOComment) {
|
|
|
|
hr = StringCchCopy (szKeyName, ARRAYSIZE(szKeyName), TEXT("Software\\Policies\\Microsoft\\Windows\\Group Policy Objects\\"));
|
|
ASSERT(SUCCEEDED(hr));
|
|
hr = StringCchCat (szKeyName, ARRAYSIZE(szKeyName), lpGPO->szGPOName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
hr = StringCchCopy (lpGPOComment, dwCommentLength, TEXT("**Comment:GPO Name: "));
|
|
ASSERT(SUCCEEDED(hr));
|
|
hr = StringCchCat (lpGPOComment, dwCommentLength, lpGPO->lpDisplayName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
if (!ArchiveRegistryValue(hFile, szKeyName, lpGPOComment, REG_SZ, 0, NULL)) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: ArchiveRegistryValue returned false.")));
|
|
}
|
|
|
|
LocalFree (lpGPOComment);
|
|
}
|
|
|
|
|
|
//
|
|
// Build the path to registry.pol
|
|
//
|
|
|
|
DmAssert( lstrlen(lpGPO->lpFileSysPath) + lstrlen(c_szRegistryPol) + 1 < MAX_PATH );
|
|
|
|
hr = StringCchCopy (szBuffer, sizeof(szBuffer)/sizeof(WCHAR), lpGPO->lpFileSysPath);
|
|
if (FAILED(hr)) {
|
|
xe = HRESULT_CODE(hr);
|
|
CloseHandle (hFile);
|
|
FreeHashTable( pHashTable );
|
|
goto ProcessGPORegistryPolicy_Exit;
|
|
}
|
|
|
|
lpEnd = CheckSlash (szBuffer);
|
|
|
|
hr = StringCchCopy (lpEnd, sizeof(szBuffer)/sizeof(WCHAR) - (lpEnd - szBuffer), c_szRegistryPol);
|
|
if (FAILED(hr)) {
|
|
xe = ERROR_INSUFFICIENT_BUFFER;
|
|
CloseHandle (hFile);
|
|
FreeHashTable( pHashTable );
|
|
goto ProcessGPORegistryPolicy_Exit;
|
|
}
|
|
|
|
if (!ParseRegistryFile (lpGPOInfo, szBuffer, SetRegistryValue, hFile,
|
|
lpGPO->lpDSPath, lpGPO->lpLink, pHashTable, FALSE )) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: ParseRegistryFile failed.")));
|
|
CloseHandle (hFile);
|
|
FreeHashTable( pHashTable );
|
|
// no logging is done in any case
|
|
goto ProcessGPORegistryPolicy_Exit;
|
|
}
|
|
|
|
if ( lpGPOInfo->pWbemServices ) {
|
|
|
|
//
|
|
// Log Adm data
|
|
//
|
|
|
|
HANDLE hFindFile;
|
|
WIN32_FILE_ATTRIBUTE_DATA attrData;
|
|
DWORD dwFilePathSize = lstrlen( lpGPO->lpFileSysPath );
|
|
TCHAR szComputerName[3*MAX_COMPUTERNAME_LENGTH + 1];
|
|
DWORD dwSize;
|
|
|
|
dwSize = 3*MAX_COMPUTERNAME_LENGTH + 1;
|
|
if (!GetComputerName(szComputerName, &dwSize)) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: Couldn't get the computer Name with error %d."), GetLastError()));
|
|
szComputerName[0] = TEXT('\0');
|
|
}
|
|
|
|
|
|
dwSize = dwFilePathSize + MAX_PATH;
|
|
|
|
WCHAR *pwszEnd;
|
|
WCHAR *pwszFile = (WCHAR *) LocalAlloc( LPTR, dwSize * sizeof(WCHAR) );
|
|
|
|
if ( pwszFile == 0 ) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: ParseRegistryFile failed to allocate memory.")));
|
|
CloseHandle (hFile);
|
|
FreeHashTable( pHashTable );
|
|
// no logging is done in any case
|
|
goto ProcessGPORegistryPolicy_Exit;
|
|
}
|
|
|
|
hr = StringCchCopy( pwszFile, dwSize, lpGPO->lpFileSysPath );
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
//
|
|
// Strip off trailing 'machine' or 'user'
|
|
//
|
|
|
|
pwszEnd = pwszFile + lstrlen( pwszFile );
|
|
|
|
if ( lpGPOInfo->dwFlags & GP_MACHINE )
|
|
pwszEnd -= 7; // length of "machine"
|
|
else
|
|
pwszEnd -= 4; // length of "user"
|
|
|
|
hr = StringCchCopy( pwszEnd, dwSize - (pwszEnd - pwszFile), L"Adm\\*.adm");
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
//
|
|
// Remember end point so that the actual Adm filename can be
|
|
// easily concatenated.
|
|
//
|
|
|
|
pwszEnd = pwszEnd + lstrlen( L"Adm\\" );
|
|
|
|
//
|
|
// Enumerate all Adm files
|
|
//
|
|
|
|
hFindFile = FindFirstFile( pwszFile, &findData);
|
|
|
|
if ( hFindFile != INVALID_HANDLE_VALUE )
|
|
{
|
|
do
|
|
{
|
|
if ( !(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
|
|
{
|
|
DmAssert( dwFilePathSize + lstrlen(findData.cFileName) + lstrlen( L"\\Adm\\" ) < dwSize );
|
|
|
|
hr = StringCchCopy( pwszEnd, dwSize - (pwszEnd - pwszFile), findData.cFileName);
|
|
if (FAILED(hr)) {
|
|
if (pHashTable->hrError == S_OK)
|
|
pHashTable->hrError = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else {
|
|
ZeroMemory (&attrData, sizeof(attrData));
|
|
|
|
if ( GetFileAttributesEx (pwszFile, GetFileExInfoStandard, &attrData ) != 0 ) {
|
|
|
|
if ( !AddAdmFile( pwszFile, lpGPO->lpDSPath, &attrData.ftLastWriteTime,
|
|
szComputerName, &pAdmFileCache ) ) {
|
|
DebugMsg((DM_WARNING,
|
|
TEXT("ProcessGPORegistryPolicy: AddAdmFile failed.")));
|
|
|
|
if (pHashTable->hrError == S_OK)
|
|
pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
}
|
|
}
|
|
} // if findData & file_attr_dir
|
|
} while ( FindNextFile(hFindFile, &findData) );// do
|
|
|
|
FindClose(hFindFile);
|
|
|
|
} // if hfindfile
|
|
|
|
LocalFree( pwszFile );
|
|
|
|
} // if rsoploggingenabled
|
|
|
|
lpGPO = lpGPO->pNext;
|
|
}
|
|
|
|
//
|
|
// Log registry data to Cimom database
|
|
//
|
|
|
|
if ( lpGPOInfo->pWbemServices ) {
|
|
|
|
if ( ! LogRegistryRsopData( lpGPOInfo->dwFlags, pHashTable, lpGPOInfo->pWbemServices ) ) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Error when logging Registry Rsop data. Continuing.")));
|
|
|
|
if (pHashTable->hrError == S_OK)
|
|
pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
if ( ! LogAdmRsopData( pAdmFileCache, lpGPOInfo->pWbemServices ) ) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Error when logging Adm Rsop data. Continuing.")));
|
|
|
|
if (pHashTable->hrError == S_OK)
|
|
pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
*phrRsopLogging = pHashTable->hrError;
|
|
}
|
|
|
|
|
|
FreeHashTable( pHashTable );
|
|
FreeAdmFileCache( pAdmFileCache );
|
|
|
|
CloseHandle (hFile);
|
|
|
|
#if 0
|
|
//
|
|
// Set the security on the file
|
|
//
|
|
|
|
if (!MakeFileSecure (szPath, 0)) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: Failed to set security on the group policy registry file with %d"),
|
|
GetLastError()));
|
|
}
|
|
#endif
|
|
|
|
bStatus = TRUE;
|
|
|
|
ProcessGPORegistryPolicy_Exit:
|
|
|
|
if ( hRegistrySection )
|
|
{
|
|
LeaveCriticalPolicySection( hRegistrySection );
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// AddAdmFile()
|
|
//
|
|
// Purpose: Prepends to list of Adm files
|
|
//
|
|
// Parameters: pwszFile - File path
|
|
// pwszGPO - Gpo
|
|
// pftWrite - Last write time
|
|
// ppAdmFileCache - List of Adm files processed
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL AddAdmFile( WCHAR *pwszFile, WCHAR *pwszGPO, FILETIME *pftWrite, WCHAR *szComputerName,
|
|
ADMFILEINFO **ppAdmFileCache )
|
|
{
|
|
XPtrLF<WCHAR> xszLongPath;
|
|
LPTSTR pwszUNCPath;
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("AllocAdmFileInfo: Adding File name <%s> to the Adm list."), pwszFile));
|
|
if ((szComputerName) && (*szComputerName) && (!IsUNCPath(pwszFile))) {
|
|
xszLongPath = MakePathUNC(pwszFile, szComputerName);
|
|
|
|
if (!xszLongPath) {
|
|
DebugMsg((DM_WARNING, TEXT("AllocAdmFileInfo: Failed to Make the path UNC with error %d."), GetLastError()));
|
|
return FALSE;
|
|
}
|
|
pwszUNCPath = xszLongPath;
|
|
}
|
|
else
|
|
pwszUNCPath = pwszFile;
|
|
|
|
|
|
ADMFILEINFO *pAdmInfo = AllocAdmFileInfo( pwszUNCPath, pwszGPO, pftWrite );
|
|
if ( pAdmInfo == NULL )
|
|
return FALSE;
|
|
|
|
pAdmInfo->pNext = *ppAdmFileCache;
|
|
*ppAdmFileCache = pAdmInfo;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// FreeAdmFileCache()
|
|
//
|
|
// Purpose: Frees Adm File list
|
|
//
|
|
// Parameters: pAdmFileCache - List of Adm files to free
|
|
//
|
|
//
|
|
//*************************************************************
|
|
|
|
void FreeAdmFileCache( ADMFILEINFO *pAdmFileCache )
|
|
{
|
|
ADMFILEINFO *pNext;
|
|
|
|
while ( pAdmFileCache ) {
|
|
pNext = pAdmFileCache->pNext;
|
|
FreeAdmFileInfo( pAdmFileCache );
|
|
pAdmFileCache = pNext;
|
|
}
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// AllocAdmFileInfo()
|
|
//
|
|
// Purpose: Allocates a new struct for ADMFILEINFO
|
|
//
|
|
// Parameters: pwszFile - File name
|
|
// pwszGPO - Gpo
|
|
// pftWrite - Last write time
|
|
//
|
|
//
|
|
//*************************************************************
|
|
|
|
ADMFILEINFO * AllocAdmFileInfo( WCHAR *pwszFile, WCHAR *pwszGPO, FILETIME *pftWrite )
|
|
{
|
|
XLastError xe;
|
|
HRESULT hr = S_OK;
|
|
|
|
ADMFILEINFO *pAdmFileInfo = (ADMFILEINFO *) LocalAlloc( LPTR, sizeof(ADMFILEINFO) );
|
|
if ( pAdmFileInfo == NULL ) {
|
|
DebugMsg((DM_WARNING, TEXT("AllocAdmFileInfo: Failed to allocate memory.")));
|
|
return NULL;
|
|
}
|
|
|
|
pAdmFileInfo->pwszFile = (WCHAR *) LocalAlloc( LPTR, (lstrlen(pwszFile) + 1) * sizeof(WCHAR) );
|
|
if ( pAdmFileInfo->pwszFile == NULL ) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("AllocAdmFileInfo: Failed to allocate memory.")));
|
|
LocalFree( pAdmFileInfo );
|
|
return NULL;
|
|
}
|
|
|
|
pAdmFileInfo->pwszGPO = (WCHAR *) LocalAlloc( LPTR, (lstrlen(pwszGPO) + 1) * sizeof(WCHAR) );
|
|
if ( pAdmFileInfo->pwszGPO == NULL ) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("AllocAdmFileInfo: Failed to allocate memory.")));
|
|
LocalFree( pAdmFileInfo->pwszFile );
|
|
LocalFree( pAdmFileInfo );
|
|
return NULL;
|
|
}
|
|
|
|
hr = StringCchCopy( pAdmFileInfo->pwszFile, lstrlen(pwszFile) + 1, pwszFile );
|
|
ASSERT(SUCCEEDED(hr));
|
|
hr = StringCchCopy( pAdmFileInfo->pwszGPO, lstrlen(pwszGPO) + 1, pwszGPO );
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
pAdmFileInfo->ftWrite = *pftWrite;
|
|
|
|
return pAdmFileInfo;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// FreeAdmFileInfo()
|
|
//
|
|
// Purpose: Deletes a ADMFILEINFO struct
|
|
//
|
|
// Parameters: pAdmFileInfo - Struct to delete
|
|
// pftWrite - Last write time
|
|
//
|
|
//
|
|
//*************************************************************
|
|
|
|
void FreeAdmFileInfo( ADMFILEINFO *pAdmFileInfo )
|
|
{
|
|
if ( pAdmFileInfo ) {
|
|
LocalFree( pAdmFileInfo->pwszFile );
|
|
LocalFree( pAdmFileInfo->pwszGPO );
|
|
LocalFree( pAdmFileInfo );
|
|
}
|
|
}
|