Leaked source code of windows server 2003
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

//*************************************************************
//
// 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 );
}
}