2456 lines
73 KiB
C
2456 lines
73 KiB
C
/*++
|
||
|
||
Copyright (c) 1998-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
migrate.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the code necessary for Plug and Play to prepare the
|
||
necessary state during a winnt32.exe upgrade or an ASR (Automated System
|
||
Recovery) backup operation. Typically, these aspects of the Plug and Play
|
||
registry are saved in a sif for later use, during the text-mode setup
|
||
portion of an upgrade or ASR recovery operation.
|
||
|
||
Author:
|
||
|
||
Jim Cavalaris (jamesca) 07-Mar-2000
|
||
|
||
Environment:
|
||
|
||
User-mode only.
|
||
|
||
Revision History:
|
||
|
||
07-March-2000 jamesca
|
||
|
||
Creation and initial implementation.
|
||
|
||
--*/
|
||
|
||
|
||
//
|
||
// includes
|
||
//
|
||
#include "precomp.h"
|
||
#include "debug.h"
|
||
#include "util.h"
|
||
|
||
#include <aclapi.h>
|
||
#include <regstr.h>
|
||
#include <pnpmgr.h>
|
||
#include <cfgmgr32.h>
|
||
|
||
|
||
//
|
||
// definitions
|
||
//
|
||
|
||
// do the lock/unlock Enum security thing? (as taken from PNPREG)
|
||
#define DO_LOCK_UNLOCK 0
|
||
|
||
|
||
//
|
||
// memory allocation macros
|
||
// (always use LocalAlloc/LocalReAlloc so that the caller can LocalFree the
|
||
// returned buffer.)
|
||
//
|
||
|
||
#define MyMalloc(size) LocalAlloc(0, size);
|
||
#define MyFree(entry) LocalFree(entry);
|
||
#define MyRealloc(entry,size) LocalReAlloc(entry, size, LMEM_MOVEABLE | LMEM_ZEROINIT);
|
||
|
||
|
||
//
|
||
// globals for the Enum branch lock/unlock and security routines - taken from PNPREG
|
||
// (we only need these if we're doing the Enum lock/unlock thing)
|
||
//
|
||
|
||
#if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
|
||
|
||
PSID g_pAdminSid;
|
||
PSID g_pSystemSid;
|
||
PSID g_pWorldSid;
|
||
|
||
SECURITY_DESCRIPTOR g_DeviceParametersSD;
|
||
PACL g_pDeviceParametersDacl;
|
||
|
||
SECURITY_DESCRIPTOR g_LockedPrivateKeysSD;
|
||
PACL g_pLockedPrivateKeysDacl;
|
||
|
||
#if 0 //#if DBG // DBG
|
||
TCHAR g_szCurrentKeyName[4096];
|
||
DWORD g_dwCurrentKeyNameLength = 0;
|
||
#endif // DBG
|
||
|
||
#endif // DO_LOCK_UNLOCK
|
||
|
||
|
||
//
|
||
// public prototypes
|
||
//
|
||
|
||
BOOL
|
||
MigrateDeviceInstanceData(
|
||
OUT LPTSTR *Buffer
|
||
);
|
||
|
||
BOOL
|
||
MigrateClassKeys(
|
||
OUT LPTSTR *Buffer
|
||
);
|
||
|
||
BOOL
|
||
MigrateHashValues(
|
||
OUT LPTSTR *Buffer
|
||
);
|
||
|
||
|
||
//
|
||
// private prototypes
|
||
//
|
||
|
||
BOOL
|
||
EnumerateDeviceKeys(
|
||
IN HKEY CCSEnumKey,
|
||
IN LPTSTR Enumerator,
|
||
IN OUT LPTSTR *pszDeviceInstanceSection,
|
||
IN OUT LPTSTR *pszDeviceInstanceCurrent,
|
||
IN OUT DWORD *dwDeviceInstanceSectionLength,
|
||
IN OUT DWORD *dwDeviceInstanceSectionRemaining
|
||
);
|
||
|
||
BOOL
|
||
EnumerateInstanceKeys(
|
||
IN HKEY EnumeratorKey,
|
||
IN LPTSTR Enumerator,
|
||
IN LPTSTR Device,
|
||
IN OUT LPTSTR *pszDeviceInstanceSection,
|
||
IN OUT LPTSTR *pszDeviceInstanceCurrent,
|
||
IN OUT DWORD *dwDeviceInstanceSectionLength,
|
||
IN OUT DWORD *dwDeviceInstanceSectionRemaining
|
||
);
|
||
|
||
BOOL
|
||
EnumerateClassSubkeys(
|
||
IN HKEY ClassKey,
|
||
IN LPTSTR ClassKeyName,
|
||
IN OUT LPTSTR *pszClassKeySection,
|
||
IN OUT LPTSTR *pszClassKeyCurrent,
|
||
IN OUT DWORD *dwClassKeySectionLength,
|
||
IN OUT DWORD *dwClassKeySectionRemaining
|
||
);
|
||
|
||
BOOL
|
||
CanStringBeMigrated(
|
||
IN LPTSTR pszBuffer
|
||
);
|
||
|
||
|
||
// we only need these if we're doing the Enum lock/unlock thing
|
||
#if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
|
||
|
||
VOID
|
||
LockUnlockEnumTree(
|
||
IN BOOL bLock
|
||
);
|
||
|
||
VOID
|
||
EnumKeysAndApplyDacls(
|
||
IN HKEY hParentKey,
|
||
IN LPTSTR pszKeyName,
|
||
IN DWORD dwLevel,
|
||
IN BOOL bInDeviceParameters,
|
||
IN BOOL bApplyTopDown,
|
||
IN PSECURITY_DESCRIPTOR pPrivateKeySD,
|
||
IN PSECURITY_DESCRIPTOR pDeviceParametersSD
|
||
);
|
||
|
||
BOOL
|
||
CreateSecurityDescriptors(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
FreeSecurityDescriptors(
|
||
VOID
|
||
);
|
||
|
||
#endif // DO_LOCK_UNLOCK
|
||
|
||
|
||
//
|
||
// Device instance enumeration routines
|
||
//
|
||
|
||
|
||
BOOL
|
||
MigrateDeviceInstanceData(
|
||
OUT LPTSTR *Buffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine walks the Plug and Play Enum tree in the registry, and collects
|
||
the data that is relevant to restoring this state during textmode setup.
|
||
|
||
Specifically, a multi-sz string will be returned to the caller that contains
|
||
migration data for the UniqueParentID, ParentIdPrefix, and Driver registry
|
||
values for all device instances in the Enum tree.
|
||
|
||
Arguments:
|
||
|
||
Buffer - Supplies the address of a character pointer, that on success will
|
||
contain a multi-sz list of device instances and relevant values to
|
||
migrate.
|
||
|
||
The caller is responsible for freeing the memory via LocalFree.
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, FALSE otherwise. Upon failure, additional information
|
||
can be retrieved by calling GetLastError().
|
||
|
||
--*/
|
||
{
|
||
LONG result = ERROR_SUCCESS;
|
||
HKEY hEnumKey = NULL;
|
||
DWORD dwSubkeyCount, dwMaxSubKeyLength, i;
|
||
LPTSTR pszEnumerator = NULL;
|
||
|
||
LPTSTR pszDeviceInstanceSection = NULL;
|
||
LPTSTR pszDeviceInstanceCurrent = NULL;
|
||
|
||
DWORD dwDeviceInstanceSectionLength = 0;
|
||
DWORD dwDeviceInstanceSectionRemaining = 0;
|
||
|
||
|
||
//
|
||
// Initialize the output parameter.
|
||
//
|
||
*Buffer = NULL;
|
||
|
||
#if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
|
||
|
||
//
|
||
// Unlock the Enum key.
|
||
//
|
||
LockUnlockEnumTree(FALSE);
|
||
|
||
#endif // DO_LOCK_UNLOCK
|
||
|
||
//
|
||
// Allocate storage and initialize variables for the device instance
|
||
// migration section.
|
||
//
|
||
if (pszDeviceInstanceSection == NULL) {
|
||
|
||
dwDeviceInstanceSectionLength = dwDeviceInstanceSectionRemaining = 256;
|
||
pszDeviceInstanceSection = MyMalloc(dwDeviceInstanceSectionLength * sizeof(TCHAR));
|
||
|
||
if (!pszDeviceInstanceSection) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateDeviceInstanceData: initial ALLOC for ClassKeySection failed!!\n") ));
|
||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
pszDeviceInstanceCurrent = pszDeviceInstanceSection;
|
||
}
|
||
|
||
//
|
||
// Open a handle to the HKLM\SYSTEM\CCS\Enum key.
|
||
//
|
||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
REGSTR_PATH_SYSTEMENUM,
|
||
0,
|
||
KEY_READ,
|
||
&hEnumKey);
|
||
if (result != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateDeviceInstanceData: failed to open %s, error=0x%08lx\n"),
|
||
REGSTR_PATH_SYSTEMENUM, result));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Query the Enum key for enumerator subkey information.
|
||
//
|
||
result = RegQueryInfoKey(hEnumKey,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&dwSubkeyCount,
|
||
&dwMaxSubKeyLength,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
if (result != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateDeviceInstanceData: failed to query %s key, error=0x%08lx\n"),
|
||
REGSTR_PATH_SYSTEMENUM, result));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Allocate a buffer to hold the largest enumerator key name.
|
||
//
|
||
dwMaxSubKeyLength++;
|
||
pszEnumerator = MyMalloc(dwMaxSubKeyLength * sizeof(TCHAR));
|
||
if (!pszEnumerator) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateDeviceInstanceData: failed to allocate buffer for Enum subkeys\n") ));
|
||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Enumerate the enumerator subkeys.
|
||
//
|
||
for (i = 0; i < dwSubkeyCount; i++) {
|
||
DWORD dwEnumeratorLength = dwMaxSubKeyLength;
|
||
|
||
result = RegEnumKeyEx(hEnumKey,
|
||
i,
|
||
pszEnumerator,
|
||
&dwEnumeratorLength,
|
||
0,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
if (result != ERROR_SUCCESS) {
|
||
//
|
||
// If there was some error enumerating this key, skip it.
|
||
//
|
||
MYASSERT(result != ERROR_NO_MORE_ITEMS);
|
||
DBGTRACE( DBGF_WARNINGS,
|
||
(TEXT("MigrateDeviceInstanceData: failed to enumerate an enumerator subkey, error=0x%08lx\n"),
|
||
result));
|
||
result = ERROR_SUCCESS;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Enumerate the devices and device instances for this enumerator, and
|
||
// append the migration data for each to the section buffer.
|
||
//
|
||
if (!EnumerateDeviceKeys(hEnumKey,
|
||
pszEnumerator,
|
||
&pszDeviceInstanceSection,
|
||
&pszDeviceInstanceCurrent,
|
||
&dwDeviceInstanceSectionLength,
|
||
&dwDeviceInstanceSectionRemaining)) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateDeviceInstanceData: EnumerateDeviceKeys failed, error=0x%08lx\n"),
|
||
GetLastError()));
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Once we've enumerated all device instances, add the final NULL terminator
|
||
// to the multi-sz buffer. There must be enough space for the final NULL
|
||
// terminator because the buffer is always reallocated unless there is room.
|
||
//
|
||
MYASSERT(dwDeviceInstanceSectionRemaining > 0);
|
||
|
||
MYASSERT(pszDeviceInstanceCurrent);
|
||
*pszDeviceInstanceCurrent = TEXT('\0');
|
||
|
||
dwDeviceInstanceSectionRemaining -= 1;
|
||
|
||
Clean0:
|
||
|
||
//
|
||
// Do some cleanup.
|
||
//
|
||
if (pszEnumerator) {
|
||
MyFree(pszEnumerator);
|
||
}
|
||
|
||
if (hEnumKey) {
|
||
RegCloseKey(hEnumKey);
|
||
}
|
||
|
||
#if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
|
||
|
||
//
|
||
// Lock the Enum tree.
|
||
//
|
||
LockUnlockEnumTree(TRUE);
|
||
|
||
#endif // DO_LOCK_UNLOCK
|
||
|
||
//
|
||
// Return the buffer to the caller only if successful.
|
||
//
|
||
if (result == ERROR_SUCCESS) {
|
||
*Buffer = pszDeviceInstanceSection;
|
||
} else {
|
||
SetLastError(result);
|
||
if (pszDeviceInstanceSection) {
|
||
MyFree(pszDeviceInstanceSection);
|
||
}
|
||
}
|
||
return (result == ERROR_SUCCESS);
|
||
|
||
} // MigrateDeviceInstanceData()
|
||
|
||
|
||
|
||
BOOL
|
||
EnumerateDeviceKeys(
|
||
IN HKEY CCSEnumKey,
|
||
IN LPTSTR Enumerator,
|
||
IN OUT LPTSTR *pszDeviceInstanceSection,
|
||
IN OUT LPTSTR *pszDeviceInstanceCurrent,
|
||
IN OUT DWORD *dwDeviceInstanceSectionLength,
|
||
IN OUT DWORD *dwDeviceInstanceSectionRemaining
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Enumerates device keys of an enumerator.
|
||
Worker routine for MigrateDeviceInstanceData.
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, FALSE otherwise. Upon failure, additional information
|
||
can be retrieved by calling GetLastError().
|
||
|
||
--*/
|
||
{
|
||
LONG result;
|
||
HKEY hEnumeratorKey = NULL;
|
||
LPTSTR pszDeviceName = NULL;
|
||
DWORD dwSubkeyCount, dwMaxSubKeyLength, dwDeviceLength, i;
|
||
|
||
|
||
//
|
||
// Open the enumerator key, under HKLM\SYSTEM\CCS\Enum.
|
||
//
|
||
result = RegOpenKeyEx(CCSEnumKey,
|
||
Enumerator,
|
||
0,
|
||
KEY_READ,
|
||
&hEnumeratorKey);
|
||
|
||
if (result != ERROR_SUCCESS) {
|
||
//
|
||
// If we failed to open the Enumerator key, there's nothing we can do.
|
||
//
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateDeviceKeys: failed to open '%s' enumerator key, error=0x%08lx\n"),
|
||
Enumerator, result));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Query the enumerator key for device subkey information.
|
||
//
|
||
result = RegQueryInfoKey(hEnumeratorKey,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&dwSubkeyCount,
|
||
&dwMaxSubKeyLength,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
if (result != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateDeviceKeys: failed to query '%s' enumerator key, error=0x%08lx\n"),
|
||
Enumerator, result));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Allocate a buffer to hold the largest device subkey name.
|
||
//
|
||
dwMaxSubKeyLength++;
|
||
pszDeviceName = MyMalloc(dwMaxSubKeyLength * sizeof(TCHAR));
|
||
if (!pszDeviceName) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateDeviceKeys: failed to allocate buffer for device subkeys of '%s'\n"),
|
||
Enumerator));
|
||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Enumerate the enumerator's devices.
|
||
//
|
||
for (i = 0; i < dwSubkeyCount; i++) {
|
||
dwDeviceLength = dwMaxSubKeyLength;
|
||
result = RegEnumKeyEx(hEnumeratorKey,
|
||
i,
|
||
pszDeviceName,
|
||
&dwDeviceLength,
|
||
0,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
if (result != ERROR_SUCCESS) {
|
||
//
|
||
// If there was some error enumerating this device key, skip it.
|
||
//
|
||
MYASSERT(result != ERROR_NO_MORE_ITEMS);
|
||
DBGTRACE( DBGF_WARNINGS,
|
||
(TEXT("EnumerateDeviceKeys: failed to enumerate device subkey for '%s', error=0x%08lx\n"),
|
||
Enumerator, result));
|
||
result = ERROR_SUCCESS;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Enumerate the device instances, and append the migration data for
|
||
// each to the section buffer.
|
||
//
|
||
if (!EnumerateInstanceKeys(hEnumeratorKey,
|
||
Enumerator,
|
||
pszDeviceName,
|
||
pszDeviceInstanceSection,
|
||
pszDeviceInstanceCurrent,
|
||
dwDeviceInstanceSectionLength,
|
||
dwDeviceInstanceSectionRemaining)) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateDeviceKeys: EnumerateInstanceKeys failed for %s\\%s, error=0x%08lx\n"),
|
||
Enumerator, pszDeviceName, GetLastError()));
|
||
}
|
||
}
|
||
|
||
Clean0:
|
||
|
||
//
|
||
// Do some cleanup
|
||
//
|
||
if (pszDeviceName) {
|
||
MyFree(pszDeviceName);
|
||
}
|
||
|
||
if (hEnumeratorKey) {
|
||
RegCloseKey(hEnumeratorKey);
|
||
}
|
||
|
||
if (result != ERROR_SUCCESS) {
|
||
SetLastError(result);
|
||
}
|
||
|
||
return (result == ERROR_SUCCESS);
|
||
|
||
} // EnumerateDeviceKeys()
|
||
|
||
|
||
|
||
BOOL
|
||
EnumerateInstanceKeys(
|
||
IN HKEY EnumeratorKey,
|
||
IN LPTSTR Enumerator,
|
||
IN LPTSTR Device,
|
||
IN OUT LPTSTR *pszDeviceInstanceSection,
|
||
IN OUT LPTSTR *pszDeviceInstanceCurrent,
|
||
IN OUT DWORD *dwDeviceInstanceSectionLength,
|
||
IN OUT DWORD *dwDeviceInstanceSectionRemaining
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Enumerates instance keys of a device.
|
||
Worker routine for EnumerateDeviceKeys,MigrateDeviceInstanceData.
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, FALSE otherwise. Upon failure, additional information
|
||
can be retrieved by calling GetLastError().
|
||
|
||
--*/
|
||
{
|
||
LONG result = ERROR_SUCCESS;
|
||
HKEY hDeviceKey = NULL;
|
||
LPTSTR pszDeviceInstanceId = NULL;
|
||
DWORD dwSubkeyCount, dwMaxSubKeyLength, dwSpaceNeeded, dwSpaceConsumed, i;
|
||
BOOL bIsDeviceRootEnumerated;
|
||
|
||
//
|
||
// Keep track of whether this is a ROOT enumerated device.
|
||
//
|
||
bIsDeviceRootEnumerated = (lstrcmpi(Enumerator, REGSTR_KEY_ROOTENUM) == 0);
|
||
|
||
//
|
||
// If this is a LEGACY_ ROOT enumerated device, don't bother migrating it
|
||
// for textmode setup to see.
|
||
//
|
||
if (bIsDeviceRootEnumerated) {
|
||
if (wcsncmp(Device,
|
||
TEXT("LEGACY_"),
|
||
lstrlen(TEXT("LEGACY_"))) == 0) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Open the device key, under the enumerator key.
|
||
//
|
||
result = RegOpenKeyEx(EnumeratorKey,
|
||
Device,
|
||
0,
|
||
KEY_READ,
|
||
&hDeviceKey);
|
||
|
||
if (result != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateInstanceKeys: failed to open '%s\\%s' device key, error=0x%08lx\n"),
|
||
Enumerator, Device, result));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Query the device key for instance subkey information.
|
||
//
|
||
result = RegQueryInfoKey(hDeviceKey,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&dwSubkeyCount,
|
||
&dwMaxSubKeyLength,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
if (result != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateInstanceKeys: failed to query '%s\\%s' device key, error=0x%08lx\n"),
|
||
Enumerator, Device, result));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Allocate a buffer to hold the largest device instance subkey name.
|
||
//
|
||
dwMaxSubKeyLength++;
|
||
pszDeviceInstanceId = MyMalloc(dwMaxSubKeyLength * sizeof(TCHAR));
|
||
if (!pszDeviceInstanceId) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateInstanceKeys: failed to allocate buffer for instance subkeys of '%s\\%s'\n"),
|
||
Enumerator, Device));
|
||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Enumerate the device's instances.
|
||
//
|
||
for (i = 0; i < dwSubkeyCount; i++) {
|
||
|
||
DWORD dwInstanceLength, dwType, dwBufferSize;
|
||
DWORD dwUniqueParentID, dwFirmwareIdentified;
|
||
TCHAR szParentIdPrefix[MAX_PATH];
|
||
TCHAR szUniqueParentID[11], szFirmwareIdentified[11];
|
||
TCHAR szDriver[2*MAX_PATH + 1];
|
||
GUID classGuid;
|
||
DWORD dwDrvInst;
|
||
HKEY hInstanceKey = NULL, hLogConfKey = NULL;
|
||
TCHAR szService[MAX_PATH];
|
||
PBYTE pBootConfig = NULL;
|
||
LPTSTR pszBootConfig = NULL;
|
||
DWORD dwBootConfigSize = 0;
|
||
|
||
dwInstanceLength = dwMaxSubKeyLength;
|
||
result = RegEnumKeyEx(hDeviceKey,
|
||
i,
|
||
pszDeviceInstanceId,
|
||
&dwInstanceLength,
|
||
0,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
if (result != ERROR_SUCCESS) {
|
||
//
|
||
// If there was some error enumerating this key, skip it.
|
||
//
|
||
MYASSERT(result != ERROR_NO_MORE_ITEMS);
|
||
DBGTRACE( DBGF_WARNINGS,
|
||
(TEXT("EnumerateInstanceKeys: failed to enumerate instance subkey of '%s\\%s', error=0x&08lx\n"),
|
||
Enumerator, Device, result));
|
||
result = ERROR_SUCCESS;
|
||
continue;
|
||
}
|
||
|
||
result = RegOpenKeyEx(hDeviceKey,
|
||
pszDeviceInstanceId,
|
||
0,
|
||
KEY_READ,
|
||
&hInstanceKey);
|
||
if (result != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_WARNINGS,
|
||
(TEXT("EnumerateInstanceKeys: failed to open '%s\\%s\\%s', error=0x%08lx\n"),
|
||
Enumerator, Device, pszDeviceInstanceId, result));
|
||
result = ERROR_SUCCESS;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Check for the "UniqueParentID" value
|
||
//
|
||
dwBufferSize = sizeof(dwUniqueParentID);
|
||
result = RegQueryValueEx(hInstanceKey,
|
||
REGSTR_VALUE_UNIQUE_PARENT_ID,
|
||
0,
|
||
&dwType,
|
||
(LPBYTE)&dwUniqueParentID,
|
||
&dwBufferSize);
|
||
if ((result == ERROR_SUCCESS) &&
|
||
(dwType == REG_DWORD)){
|
||
//
|
||
// Write the UniqueParentID value to the sif as a base 16 value.
|
||
// (see admin\ntsetup\textmode\kernel\spsetup.c)
|
||
//
|
||
wsprintf(szUniqueParentID,
|
||
TEXT("%X"), // base 16
|
||
dwUniqueParentID);
|
||
} else {
|
||
//
|
||
// No "UniqueParentID" value to migrate.
|
||
//
|
||
*szUniqueParentID = TEXT('\0');
|
||
}
|
||
|
||
//
|
||
// Check for the "ParentIdPrefix" value
|
||
//
|
||
dwBufferSize = sizeof(szParentIdPrefix);
|
||
result = RegQueryValueEx(hInstanceKey,
|
||
REGSTR_VALUE_PARENT_ID_PREFIX,
|
||
0,
|
||
&dwType,
|
||
(LPBYTE)szParentIdPrefix,
|
||
&dwBufferSize);
|
||
if ((result != ERROR_SUCCESS) ||
|
||
(dwType != REG_SZ)) {
|
||
//
|
||
// No "ParentIdPrefix" value to migrate.
|
||
//
|
||
*szParentIdPrefix = TEXT('\0');
|
||
result = ERROR_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Build the device's Driver key name by checking for the GUID and
|
||
// DrvInst values.
|
||
//
|
||
*szDriver = TEXT('\0');
|
||
dwBufferSize = sizeof(classGuid);
|
||
result = RegQueryValueEx(hInstanceKey,
|
||
TEXT("GUID"),
|
||
0,
|
||
&dwType,
|
||
(LPBYTE)&classGuid,
|
||
&dwBufferSize);
|
||
|
||
if ((result == ERROR_SUCCESS) &&
|
||
(dwType == REG_BINARY)) {
|
||
//
|
||
// Get the DrvInst value for the driver key
|
||
//
|
||
dwBufferSize = sizeof(dwDrvInst);
|
||
result = RegQueryValueEx(hInstanceKey,
|
||
TEXT("DrvInst"),
|
||
0,
|
||
&dwType,
|
||
(LPBYTE)&dwDrvInst,
|
||
&dwBufferSize);
|
||
if ((result == ERROR_SUCCESS) &&
|
||
(dwType == REG_DWORD)) {
|
||
if (pSifUtilStringFromGuid(&classGuid,
|
||
szDriver,
|
||
sizeof(szDriver)/sizeof(TCHAR))) {
|
||
//
|
||
// Build the driver key
|
||
//
|
||
wsprintf((LPWSTR)szDriver, TEXT("%s\\%04u"), szDriver, dwDrvInst);
|
||
} else {
|
||
result = GetLastError();
|
||
}
|
||
} else {
|
||
//
|
||
// Generic error value so we try to find the driver value using
|
||
// the old scheme.
|
||
//
|
||
result = ERROR_INVALID_PARAMETER;
|
||
}
|
||
} else {
|
||
//
|
||
// Generic error value so we try to find the driver value using
|
||
// the old scheme.
|
||
//
|
||
result = ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// If this device instance key is not using the new GUID\DrvInst
|
||
// scheme, check for the "Driver" value
|
||
//
|
||
if (result != ERROR_SUCCESS) {
|
||
dwBufferSize = sizeof(szDriver);
|
||
result = RegQueryValueEx(hInstanceKey,
|
||
REGSTR_VAL_DRIVER,
|
||
0,
|
||
&dwType,
|
||
(LPBYTE)szDriver,
|
||
&dwBufferSize);
|
||
|
||
if ((result != ERROR_SUCCESS) ||
|
||
(dwType != REG_SZ)) {
|
||
//
|
||
// No "Driver" value to migrate.
|
||
//
|
||
*szDriver = TEXT('\0');
|
||
result = ERROR_SUCCESS;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If this is a ROOT enumerated device, check for Service, BootConfig
|
||
// and FirmwareIdentified values.
|
||
//
|
||
if (bIsDeviceRootEnumerated) {
|
||
//
|
||
// Check for the "Service" value.
|
||
//
|
||
dwBufferSize = sizeof(szService);
|
||
result = RegQueryValueEx(hInstanceKey,
|
||
REGSTR_VAL_SERVICE,
|
||
0,
|
||
&dwType,
|
||
(LPBYTE)szService,
|
||
&dwBufferSize);
|
||
if ((result != ERROR_SUCCESS) ||
|
||
(dwType != REG_SZ)) {
|
||
//
|
||
// No "Service" value to migrate.
|
||
//
|
||
*szService = TEXT('\0');
|
||
result = ERROR_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Check for the "LogConf\BootConfig" value.
|
||
//
|
||
result = RegOpenKeyEx(hInstanceKey,
|
||
REGSTR_KEY_LOGCONF,
|
||
0,
|
||
KEY_READ,
|
||
&hLogConfKey);
|
||
if (result == ERROR_SUCCESS) {
|
||
result = RegQueryValueEx(hLogConfKey,
|
||
REGSTR_VAL_BOOTCONFIG,
|
||
0,
|
||
&dwType,
|
||
(LPBYTE)NULL,
|
||
&dwBootConfigSize);
|
||
if ((result == ERROR_SUCCESS) &&
|
||
(dwType == REG_RESOURCE_LIST)) {
|
||
|
||
pBootConfig = MyMalloc(dwBootConfigSize);
|
||
if (pBootConfig) {
|
||
result = RegQueryValueEx(hLogConfKey,
|
||
REGSTR_VAL_BOOTCONFIG,
|
||
0,
|
||
&dwType,
|
||
(LPBYTE)pBootConfig,
|
||
&dwBootConfigSize);
|
||
if ((result == ERROR_SUCCESS) &&
|
||
(dwType == REG_RESOURCE_LIST)) {
|
||
//
|
||
// Allocate a string buffer large enough to store
|
||
// each nibble of the BootConfig data as a separate
|
||
// character.
|
||
//
|
||
pszBootConfig = MyMalloc((dwBootConfigSize*2 + 1)*sizeof(TCHAR));
|
||
|
||
if (pszBootConfig) {
|
||
DWORD b;
|
||
//
|
||
// Convert the binary BootConfig data to a string
|
||
// format that we can throw into the sif.
|
||
//
|
||
for (b = 0; b < dwBootConfigSize; b++) {
|
||
// first write the high-order nibble,
|
||
wsprintf((PTCHAR)&pszBootConfig[2*b],
|
||
TEXT("%X"),
|
||
pBootConfig[b] / (0x10));
|
||
// then the low order nibble.
|
||
wsprintf((PTCHAR)&pszBootConfig[2*b + 1],
|
||
TEXT("%X"),
|
||
pBootConfig[b] % (0x10));
|
||
}
|
||
}
|
||
}
|
||
|
||
MyFree(pBootConfig);
|
||
pBootConfig = NULL;
|
||
}
|
||
} else {
|
||
//
|
||
// No "LogConf\BootConfig" value to migrate.
|
||
//
|
||
pszBootConfig = NULL;
|
||
}
|
||
RegCloseKey(hLogConfKey);
|
||
}
|
||
|
||
//
|
||
// Check for the "FirmwareIdentified" value
|
||
//
|
||
dwBufferSize = sizeof(dwFirmwareIdentified);
|
||
result = RegQueryValueEx(hInstanceKey,
|
||
REGSTR_VAL_FIRMWAREIDENTIFIED,
|
||
0,
|
||
&dwType,
|
||
(LPBYTE)&dwFirmwareIdentified,
|
||
&dwBufferSize);
|
||
if ((result == ERROR_SUCCESS) &&
|
||
(dwType == REG_DWORD)){
|
||
//
|
||
// Write the FirmwareIdentified value to the sif as a base 16 value.
|
||
// (see admin\ntsetup\textmode\kernel\spsetup.c)
|
||
//
|
||
wsprintf(szFirmwareIdentified,
|
||
TEXT("%X"), // base 16
|
||
dwFirmwareIdentified);
|
||
} else {
|
||
//
|
||
// No "FirmwareIdentified" value to migrate.
|
||
//
|
||
*szFirmwareIdentified = TEXT('\0');
|
||
}
|
||
|
||
} else {
|
||
//
|
||
// We only migrate Service, BootConfig, and FirmwareIdentified
|
||
// values for Root enumerated devices.
|
||
//
|
||
*szService = TEXT('\0');
|
||
pszBootConfig = NULL;
|
||
*szFirmwareIdentified = TEXT('\0');
|
||
}
|
||
|
||
|
||
//
|
||
// If there are no values to migrate for this device instance, skip it.
|
||
//
|
||
if (!*szUniqueParentID &&
|
||
!*szDriver &&
|
||
!*szParentIdPrefix &&
|
||
!*szService &&
|
||
!pszBootConfig &&
|
||
!*szFirmwareIdentified) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// If any of the strings cannot be migrated, skip it.
|
||
//
|
||
if ((!CanStringBeMigrated(szDriver)) ||
|
||
(!CanStringBeMigrated(szService)) ||
|
||
(!CanStringBeMigrated(Enumerator)) ||
|
||
(!CanStringBeMigrated(Device)) ||
|
||
(!CanStringBeMigrated(pszDeviceInstanceId))) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// This block appends the class key data we want to migrate to a
|
||
// multi-sz style string that will be written to the sif file.
|
||
//
|
||
|
||
//
|
||
// Need space in the section buffer for a string of the form:
|
||
// Enumerator\Device\Instance,UniqueParentID,ParentIdPrefix,DriverKey,Service,BootConfig
|
||
//
|
||
|
||
//
|
||
// First, determine the space required by the common parts.
|
||
//
|
||
dwSpaceNeeded = 1 + // TEXT('\"')
|
||
lstrlen(Enumerator) +
|
||
1 + // TEXT('\\')
|
||
lstrlen(Device) +
|
||
1 + // TEXT('\\')
|
||
lstrlen(pszDeviceInstanceId) +
|
||
1 + // TEXT('\"')
|
||
1; // TEXT(',')
|
||
|
||
//
|
||
// Next, determine the space required, based on the data we have.
|
||
//
|
||
if (*szFirmwareIdentified) {
|
||
dwSpaceNeeded +=
|
||
lstrlen(szUniqueParentID) +
|
||
1 + // TEXT(',')
|
||
lstrlen(szParentIdPrefix) +
|
||
1 + // TEXT(',')
|
||
lstrlen(szDriver) +
|
||
1 + // TEXT(',')
|
||
1 + // TEXT('"')
|
||
lstrlen(szService) +
|
||
1 + // TEXT('"')
|
||
1 + // TEXT(',')
|
||
(pszBootConfig ? lstrlen(pszBootConfig) : 0) +
|
||
1 + // TEXT(',')
|
||
lstrlen(szFirmwareIdentified);
|
||
} else if (pszBootConfig) {
|
||
dwSpaceNeeded +=
|
||
lstrlen(szUniqueParentID) +
|
||
1 + // TEXT(',')
|
||
lstrlen(szParentIdPrefix) +
|
||
1 + // TEXT(',')
|
||
lstrlen(szDriver) +
|
||
1 + // TEXT(',')
|
||
1 + // TEXT('"')
|
||
lstrlen(szService) +
|
||
1 + // TEXT('"')
|
||
1 + // TEXT(',')
|
||
lstrlen(pszBootConfig);
|
||
} else if (*szService) {
|
||
dwSpaceNeeded +=
|
||
lstrlen(szUniqueParentID) +
|
||
1 + // TEXT(',')
|
||
lstrlen(szParentIdPrefix) +
|
||
1 + // TEXT(',')
|
||
lstrlen(szDriver) +
|
||
1 + // TEXT(',')
|
||
1 + // TEXT('"')
|
||
lstrlen(szService) +
|
||
1; // TEXT('"')
|
||
} else if (*szDriver) {
|
||
dwSpaceNeeded +=
|
||
lstrlen(szUniqueParentID) +
|
||
1 + // TEXT(',')
|
||
lstrlen(szParentIdPrefix) +
|
||
1 + // TEXT(',')
|
||
lstrlen(szDriver);
|
||
} else if (*szParentIdPrefix) {
|
||
dwSpaceNeeded +=
|
||
lstrlen(szUniqueParentID) +
|
||
1 + // TEXT(',')
|
||
lstrlen(szParentIdPrefix);
|
||
} else if (*szUniqueParentID) {
|
||
dwSpaceNeeded +=
|
||
lstrlen(szUniqueParentID);
|
||
}
|
||
|
||
//
|
||
// Account for the NULL terminator.
|
||
//
|
||
dwSpaceNeeded += 1;
|
||
|
||
if (*dwDeviceInstanceSectionRemaining <= dwSpaceNeeded) {
|
||
//
|
||
// ReAllocate the section block.
|
||
//
|
||
LPTSTR p;
|
||
DWORD dwTempSectionLength, dwTempSectionRemaining;
|
||
|
||
dwTempSectionRemaining = *dwDeviceInstanceSectionRemaining + *dwDeviceInstanceSectionLength;
|
||
dwTempSectionLength = *dwDeviceInstanceSectionLength * 2;
|
||
|
||
p = *pszDeviceInstanceSection;
|
||
p = MyRealloc(p,
|
||
dwTempSectionLength*sizeof(TCHAR));
|
||
|
||
if (!p) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateInstanceKeys: REALLOC failed!!!\n") ));
|
||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
RegCloseKey(hInstanceKey);
|
||
goto Clean0;
|
||
}
|
||
|
||
*pszDeviceInstanceSection = p;
|
||
*dwDeviceInstanceSectionRemaining = dwTempSectionRemaining;
|
||
*dwDeviceInstanceSectionLength = dwTempSectionLength;
|
||
|
||
*pszDeviceInstanceCurrent = *pszDeviceInstanceSection +
|
||
(*dwDeviceInstanceSectionLength -
|
||
*dwDeviceInstanceSectionRemaining);
|
||
}
|
||
|
||
//
|
||
// Write the current line to the section block.
|
||
//
|
||
if (*szFirmwareIdentified) {
|
||
dwSpaceConsumed = wsprintf(*pszDeviceInstanceCurrent,
|
||
TEXT("\"%s\\%s\\%s\",%s,%s,%s,\"%s\",%s,%s"),
|
||
Enumerator, Device, pszDeviceInstanceId,
|
||
szUniqueParentID,
|
||
szParentIdPrefix,
|
||
szDriver,
|
||
szService,
|
||
(pszBootConfig ? pszBootConfig : TEXT("\0")),
|
||
szFirmwareIdentified);
|
||
} else if (pszBootConfig) {
|
||
dwSpaceConsumed = wsprintf(*pszDeviceInstanceCurrent,
|
||
TEXT("\"%s\\%s\\%s\",%s,%s,%s,\"%s\",%s"),
|
||
Enumerator, Device, pszDeviceInstanceId,
|
||
szUniqueParentID,
|
||
szParentIdPrefix,
|
||
szDriver,
|
||
szService,
|
||
pszBootConfig);
|
||
} else if (*szService) {
|
||
dwSpaceConsumed = wsprintf(*pszDeviceInstanceCurrent,
|
||
TEXT("\"%s\\%s\\%s\",%s,%s,%s,\"%s\""),
|
||
Enumerator, Device, pszDeviceInstanceId,
|
||
szUniqueParentID,
|
||
szParentIdPrefix,
|
||
szDriver,
|
||
szService);
|
||
} else if (*szDriver) {
|
||
dwSpaceConsumed = wsprintf(*pszDeviceInstanceCurrent,
|
||
TEXT("\"%s\\%s\\%s\",%s,%s,%s"),
|
||
Enumerator, Device, pszDeviceInstanceId,
|
||
szUniqueParentID,
|
||
szParentIdPrefix,
|
||
szDriver);
|
||
} else if (*szParentIdPrefix) {
|
||
dwSpaceConsumed = wsprintf(*pszDeviceInstanceCurrent,
|
||
TEXT("\"%s\\%s\\%s\",%s,%s"),
|
||
Enumerator, Device, pszDeviceInstanceId,
|
||
szUniqueParentID,
|
||
szParentIdPrefix);
|
||
} else if (*szUniqueParentID) {
|
||
dwSpaceConsumed = wsprintf(*pszDeviceInstanceCurrent,
|
||
TEXT("\"%s\\%s\\%s\",%s"),
|
||
Enumerator, Device, pszDeviceInstanceId,
|
||
szUniqueParentID);
|
||
}
|
||
|
||
//
|
||
// Free the allocated BootConfig string buffer.
|
||
//
|
||
if (pszBootConfig) {
|
||
MyFree(pszBootConfig);
|
||
pszBootConfig = NULL;
|
||
}
|
||
|
||
//
|
||
// Account for the NULL terminator
|
||
//
|
||
dwSpaceConsumed += 1;
|
||
|
||
*pszDeviceInstanceCurrent += dwSpaceConsumed;
|
||
*dwDeviceInstanceSectionRemaining -= dwSpaceConsumed;
|
||
|
||
//
|
||
// Close the device instance key
|
||
//
|
||
RegCloseKey(hInstanceKey);
|
||
}
|
||
|
||
Clean0:
|
||
|
||
//
|
||
// Do some cleanup
|
||
//
|
||
if (pszDeviceInstanceId) {
|
||
MyFree(pszDeviceInstanceId);
|
||
}
|
||
|
||
if (hDeviceKey != NULL) {
|
||
RegCloseKey(hDeviceKey);
|
||
}
|
||
|
||
if (result != ERROR_SUCCESS) {
|
||
SetLastError(result);
|
||
}
|
||
|
||
return (result == ERROR_SUCCESS);
|
||
|
||
} // EnumerateInstanceKeys()
|
||
|
||
|
||
|
||
BOOL
|
||
CanStringBeMigrated(
|
||
IN LPTSTR pszBuffer
|
||
)
|
||
{
|
||
LPTSTR p;
|
||
BOOL bStatus;
|
||
|
||
try {
|
||
//
|
||
// An empty string can be migrated.
|
||
//
|
||
if (!ARGUMENT_PRESENT(pszBuffer)) {
|
||
bStatus = TRUE;
|
||
goto Clean0;
|
||
}
|
||
|
||
for (p = pszBuffer; *p; p++) {
|
||
//
|
||
// Check for the presence of non-migratable characters.
|
||
//
|
||
if ((*p == TEXT('=')) || (*p == TEXT('"'))) {
|
||
bStatus = FALSE;
|
||
goto Clean0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Found no problems with the string.
|
||
//
|
||
bStatus = TRUE;
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
bStatus = FALSE;
|
||
}
|
||
|
||
return bStatus;
|
||
|
||
} // CanStringBeMigrated
|
||
|
||
|
||
//
|
||
// Class key enumeration routines
|
||
//
|
||
|
||
|
||
BOOL
|
||
MigrateClassKeys(
|
||
OUT LPTSTR *Buffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine walks the Plug and Play setup class branch of the registry, and
|
||
collects the data about what keys currently exist. This information is
|
||
relevant to maintaining plug and play state during textmode setup, such that
|
||
the names of existing keys are not reassigned before they have been migrated
|
||
to the registry at the end of textmode setup.
|
||
|
||
Specifically, a multi-sz string will be returned to the caller that contains
|
||
each subkey of the class branch.
|
||
|
||
Arguments:
|
||
|
||
Buffer - Supplies the address of a character pointer, that on success will
|
||
contain a multi-sz list of setup class subkeys to migrate.
|
||
|
||
The caller is responsible for freeing the memory via LocalFree.
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, FALSE otherwise. Upon failure, additional information
|
||
can be retrieved by calling GetLastError().
|
||
|
||
--*/
|
||
{
|
||
LONG result = ERROR_SUCCESS;
|
||
HKEY hClassKey = NULL;
|
||
DWORD dwSubkeyCount, dwMaxSubKeyLength, i;
|
||
LPTSTR pszClassKeyName = NULL;
|
||
|
||
LPTSTR pszClassKeySection = NULL;
|
||
LPTSTR pszClassKeyCurrent = NULL;
|
||
DWORD dwClassKeySectionLength = 0;
|
||
DWORD dwClassKeySectionRemaining = 0;
|
||
|
||
|
||
//
|
||
// Initialize the output parameter.
|
||
//
|
||
*Buffer = NULL;
|
||
|
||
//
|
||
// Allocate storage and initialize variables for the class Key migration
|
||
// section.
|
||
//
|
||
if (pszClassKeySection == NULL) {
|
||
|
||
dwClassKeySectionLength = dwClassKeySectionRemaining = 256;
|
||
pszClassKeySection = MyMalloc(dwClassKeySectionLength * sizeof(TCHAR));
|
||
|
||
if (!pszClassKeySection) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateClassKeys: initial ALLOC for ClassKeySection failed!!\n") ));
|
||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
pszClassKeyCurrent = pszClassKeySection;
|
||
}
|
||
|
||
//
|
||
// Open a handle to the HKLM\SYSTEM\CCS\Control\Class key.
|
||
//
|
||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
REGSTR_PATH_CLASS_NT,
|
||
0,
|
||
KEY_READ,
|
||
&hClassKey);
|
||
if (result != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateClassKeys: failed to open %s, error=0x%08lx\n"),
|
||
REGSTR_PATH_CLASS_NT, result));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Query the Class key for class GUID subkey information.
|
||
//
|
||
result = RegQueryInfoKey(hClassKey,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&dwSubkeyCount,
|
||
&dwMaxSubKeyLength,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
if (result != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateClassKeys: failed to query %s key, error=0x%08lx\n"),
|
||
REGSTR_PATH_CLASS_NT, result));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Allocate a buffer to hold the largest setup class GUID subkey name.
|
||
//
|
||
dwMaxSubKeyLength++;
|
||
MYASSERT(dwMaxSubKeyLength == MAX_GUID_STRING_LEN);
|
||
pszClassKeyName = MyMalloc(dwMaxSubKeyLength * sizeof(TCHAR));
|
||
if (!pszClassKeyName) {
|
||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateClassKeys: ALLOC for Class GUID key names failed!!\n") ));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Enumerate the setup class GUIDs.
|
||
//
|
||
for (i = 0; i < dwSubkeyCount; i++) {
|
||
DWORD dwClassKeyLength;
|
||
|
||
dwClassKeyLength = dwMaxSubKeyLength;
|
||
|
||
result = RegEnumKeyEx(hClassKey,
|
||
i,
|
||
pszClassKeyName,
|
||
&dwClassKeyLength,
|
||
0,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
if (result != ERROR_SUCCESS) {
|
||
//
|
||
// If there was some error enumerating this key, skip it.
|
||
//
|
||
MYASSERT(result != ERROR_NO_MORE_ITEMS);
|
||
DBGTRACE( DBGF_WARNINGS,
|
||
(TEXT("MigrateClassKeys: failed to enumerate a class subkey, error=0x%08lx\n"),
|
||
result));
|
||
result = ERROR_SUCCESS;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Enumerate all subkeys for a given setup class key, and append them to
|
||
// the section buffer.
|
||
//
|
||
if (!EnumerateClassSubkeys(hClassKey,
|
||
pszClassKeyName,
|
||
&pszClassKeySection,
|
||
&pszClassKeyCurrent,
|
||
&dwClassKeySectionLength,
|
||
&dwClassKeySectionRemaining)) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateClassSubkeys failed, error=0x%08lx\n"),
|
||
GetLastError()));
|
||
}
|
||
}
|
||
|
||
//
|
||
// Once we've enumerated all class subkeys, add the final NULL terminator to
|
||
// the multi-sz buffer. There must be enough space for the final NULL
|
||
// terminator because the buffer is always reallocated unless there is room.
|
||
//
|
||
MYASSERT(dwClassKeySectionRemaining > 0);
|
||
|
||
MYASSERT(pszClassKeyCurrent);
|
||
*pszClassKeyCurrent = TEXT('\0');
|
||
|
||
dwClassKeySectionRemaining -= 1;
|
||
|
||
Clean0:
|
||
|
||
//
|
||
// Do some cleanup.
|
||
//
|
||
if (pszClassKeyName) {
|
||
MyFree(pszClassKeyName);
|
||
}
|
||
|
||
if (hClassKey) {
|
||
RegCloseKey(hClassKey);
|
||
}
|
||
|
||
//
|
||
// Return the buffer to the caller only if successful.
|
||
//
|
||
if (result == ERROR_SUCCESS) {
|
||
*Buffer = pszClassKeySection;
|
||
} else {
|
||
SetLastError(result);
|
||
if (pszClassKeySection) {
|
||
MyFree(pszClassKeySection);
|
||
}
|
||
}
|
||
|
||
return (result == ERROR_SUCCESS);
|
||
|
||
} // MigrateClassKeys()
|
||
|
||
|
||
|
||
BOOL
|
||
EnumerateClassSubkeys(
|
||
IN HKEY ClassKey,
|
||
IN LPTSTR ClassKeyName,
|
||
IN OUT LPTSTR *pszClassKeySection,
|
||
IN OUT LPTSTR *pszClassKeyCurrent,
|
||
IN OUT DWORD *dwClassKeySectionLength,
|
||
IN OUT DWORD *dwClassKeySectionRemaining
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Enumerates subkeys of a setup class key.
|
||
Worker routine for MigrateClassKeys.
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, FALSE otherwise. Upon failure, additional information
|
||
can be retrieved by calling GetLastError().
|
||
|
||
--*/
|
||
{
|
||
LONG result = ERROR_SUCCESS;
|
||
HKEY hClassSubkey = NULL;
|
||
LPTSTR pszClassSubkey = NULL;
|
||
DWORD dwSubkeyCount, dwMaxSubKeyLength, dwSpaceNeeded, dwSpaceConsumed, i;
|
||
|
||
|
||
//
|
||
// Open the class subkey.
|
||
//
|
||
result = RegOpenKeyEx(ClassKey,
|
||
ClassKeyName,
|
||
0,
|
||
KEY_READ,
|
||
&hClassSubkey);
|
||
|
||
if (result != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateClassSubkeys: failed to open '%s' class key, error=0x%08lx\n"),
|
||
ClassKeyName, result));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Query the class GUID key for setup class subkey information.
|
||
//
|
||
result = RegQueryInfoKey(hClassSubkey,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&dwSubkeyCount,
|
||
&dwMaxSubKeyLength,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
|
||
if (result != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateClassSubkeys: failed to query '%s' class key, error=0x%08lx\n"),
|
||
ClassKeyName, result));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Allocate a buffer to hold the largest setup class subkey name.
|
||
//
|
||
dwMaxSubKeyLength++;
|
||
pszClassSubkey = MyMalloc(dwMaxSubKeyLength * sizeof(TCHAR));
|
||
if (!pszClassSubkey) {
|
||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateClassSubkeys: ALLOC for Class GUID subkey names failed!!\n") ));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Enumerate the setup class's "software" subkeys.
|
||
//
|
||
for (i = 0; i < dwSubkeyCount; i++) {
|
||
|
||
DWORD dwClassSubkeyLength;
|
||
|
||
dwClassSubkeyLength = dwMaxSubKeyLength;
|
||
result = RegEnumKeyEx(hClassSubkey,
|
||
i,
|
||
pszClassSubkey,
|
||
&dwClassSubkeyLength,
|
||
0,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
|
||
if ((result != ERROR_SUCCESS) ||
|
||
(dwClassSubkeyLength != 4)) {
|
||
//
|
||
// if there was some error, or this is not an actual "software" key
|
||
// (in the form "XXXX"), skip this key and move on.
|
||
//
|
||
if (result != ERROR_SUCCESS) {
|
||
MYASSERT(result != ERROR_NO_MORE_ITEMS);
|
||
DBGTRACE( DBGF_WARNINGS,
|
||
(TEXT("EnumerateClassSubkeys: failed to enumerate a '%s' subkey, error=0x%08lx\n"),
|
||
ClassKeyName, result));
|
||
}
|
||
result = ERROR_SUCCESS;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// This block appends the class key data we want to migrate to a
|
||
// multi-sz style string that will be written to the sif file.
|
||
//
|
||
|
||
//
|
||
// Need space in the section buffer for a string of the form:
|
||
// ClassKeyName\pszClassSubkey
|
||
//
|
||
dwSpaceNeeded = lstrlen(ClassKeyName) +
|
||
1 + // TEXT('\\')
|
||
lstrlen(pszClassSubkey);
|
||
|
||
//
|
||
// Account for the NULL terminator.
|
||
//
|
||
dwSpaceNeeded += 1;
|
||
|
||
if (*dwClassKeySectionRemaining <= dwSpaceNeeded) {
|
||
//
|
||
// ReAllocate the section block.
|
||
//
|
||
LPTSTR p;
|
||
DWORD dwTempSectionLength, dwTempSectionRemaining;
|
||
|
||
dwTempSectionRemaining = *dwClassKeySectionRemaining + *dwClassKeySectionLength;
|
||
dwTempSectionLength = *dwClassKeySectionLength * 2;
|
||
|
||
p = *pszClassKeySection;
|
||
p = MyRealloc(p,
|
||
dwTempSectionLength*sizeof(TCHAR));
|
||
|
||
if (!p) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumerateClassSubkeys: REALLOC failed!!!\n") ));
|
||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
*pszClassKeySection = p;
|
||
*dwClassKeySectionRemaining = dwTempSectionRemaining;
|
||
*dwClassKeySectionLength = dwTempSectionLength;
|
||
|
||
*pszClassKeyCurrent = *pszClassKeySection +
|
||
(*dwClassKeySectionLength -
|
||
*dwClassKeySectionRemaining);
|
||
}
|
||
|
||
//
|
||
// Write the current line to the section block.
|
||
//
|
||
dwSpaceConsumed = wsprintf(*pszClassKeyCurrent,
|
||
TEXT("%s\\%s"),
|
||
ClassKeyName,
|
||
pszClassSubkey);
|
||
|
||
//
|
||
// Account for the NULL terminator.
|
||
//
|
||
dwSpaceConsumed += 1;
|
||
|
||
*pszClassKeyCurrent += dwSpaceConsumed;
|
||
*dwClassKeySectionRemaining -= dwSpaceConsumed;
|
||
}
|
||
|
||
Clean0:
|
||
|
||
//
|
||
// Do some cleanup.
|
||
//
|
||
if (hClassSubkey != NULL) {
|
||
RegCloseKey(hClassSubkey);
|
||
}
|
||
|
||
if (pszClassSubkey) {
|
||
MyFree(pszClassSubkey);
|
||
}
|
||
|
||
if (result != ERROR_SUCCESS) {
|
||
SetLastError(result);
|
||
}
|
||
|
||
return (result == ERROR_SUCCESS);
|
||
|
||
} // EnumerateClassSubkeys()
|
||
|
||
|
||
//
|
||
// Hash value migration routines
|
||
//
|
||
|
||
|
||
BOOL
|
||
MigrateHashValues(
|
||
OUT LPTSTR *Buffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine searches the Plug and Play Enum key of the registry, and
|
||
collects the data about what hash value entries currently exist. This
|
||
information is relevant to maintaining plug and play state during textmode
|
||
setup, such that the names of existing device instances are not reassigned
|
||
before they have been migrated to the registry at the end of textmode setup.
|
||
|
||
Specifically, a multi-sz string will be returned to the caller that contains
|
||
the name of the hash value, and its count.
|
||
|
||
Arguments:
|
||
|
||
Buffer - Supplies the address of a character pointer, that on success will
|
||
contain a multi-sz list of hash values to migrate.
|
||
|
||
The caller is responsible for freeing the memory via LocalFree.
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, FALSE otherwise. Upon failure, additional information
|
||
can be retrieved by calling GetLastError().
|
||
|
||
--*/
|
||
{
|
||
LONG result = ERROR_SUCCESS;
|
||
HKEY hEnumKey = NULL;
|
||
DWORD dwValueCount, dwMaxValueNameLength, dwSpaceNeeded, dwSpaceConsumed, i;
|
||
LPTSTR pszHashValueName = NULL;
|
||
|
||
LPTSTR pszHashValueSection = NULL;
|
||
LPTSTR pszHashValueCurrent = NULL;
|
||
|
||
DWORD dwHashValueSectionLength = 0;
|
||
DWORD dwHashValueSectionRemaining = 0;
|
||
|
||
|
||
//
|
||
// Initialize the output parameter.
|
||
//
|
||
*Buffer = NULL;
|
||
|
||
#if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
|
||
|
||
//
|
||
// Unlock the Enum key
|
||
//
|
||
LockUnlockEnumTree(FALSE);
|
||
|
||
#endif // DO_LOCK_UNLOCK
|
||
|
||
//
|
||
// Allocate storage and initialize variables for the hash value migration
|
||
// section.
|
||
//
|
||
if (pszHashValueSection == NULL) {
|
||
|
||
dwHashValueSectionLength = dwHashValueSectionRemaining = 256;
|
||
pszHashValueSection = MyMalloc(dwHashValueSectionLength * sizeof(TCHAR));
|
||
|
||
if (!pszHashValueSection) {
|
||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateHashValues: initial ALLOC for HashValueSection failed!!\n") ));
|
||
goto Clean0;
|
||
}
|
||
|
||
pszHashValueCurrent = pszHashValueSection;
|
||
}
|
||
|
||
//
|
||
// Open a handle to the HKLM\SYSTEM\CCS\Enum key.
|
||
//
|
||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
REGSTR_PATH_SYSTEMENUM,
|
||
0,
|
||
KEY_READ,
|
||
&hEnumKey);
|
||
if (result != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateHashValues: failed to open %s, error=0x%08lx\n"),
|
||
REGSTR_PATH_SYSTEMENUM, result));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Query the Enum key for hash value information.
|
||
//
|
||
result = RegQueryInfoKey(hEnumKey,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&dwValueCount,
|
||
&dwMaxValueNameLength,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
if (result != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateHashValues: failed to query %s key, error=0x%08lx\n"),
|
||
REGSTR_PATH_SYSTEMENUM, result));
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Allocate a variable to hold the largest hash value key name.
|
||
//
|
||
dwMaxValueNameLength++;
|
||
pszHashValueName = MyMalloc(dwMaxValueNameLength * sizeof(TCHAR));
|
||
if (!pszHashValueName) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateHashValues: failed to allocate buffer for Enum key hash values\n") ));
|
||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Enumerate all values and append them to the supplied buffer.
|
||
//
|
||
for (i = 0; i < dwValueCount; i++) {
|
||
DWORD dwHashValueLength, dwType, dwData, dwSize;
|
||
TCHAR szHashValueData[11];
|
||
|
||
|
||
dwHashValueLength = dwMaxValueNameLength;
|
||
dwType = REG_DWORD;
|
||
dwData = 0;
|
||
dwSize = sizeof(DWORD);
|
||
|
||
result = RegEnumValue(hEnumKey,
|
||
i,
|
||
pszHashValueName,
|
||
&dwHashValueLength,
|
||
0,
|
||
&dwType,
|
||
(LPBYTE)&dwData,
|
||
&dwSize);
|
||
|
||
if ((result != ERROR_SUCCESS) ||
|
||
(dwType != REG_DWORD) ||
|
||
(dwSize != sizeof(DWORD))) {
|
||
//
|
||
// If there was some error enumerating this value, or the value
|
||
// return was not expected, skip it.
|
||
//
|
||
MYASSERT(result != ERROR_NO_MORE_ITEMS);
|
||
DBGTRACE( DBGF_WARNINGS,
|
||
(TEXT("MigrateHashValues: failed to enumerate Enum values, error=0x%08lx\n"),
|
||
result));
|
||
result = ERROR_SUCCESS;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Write the hash value data to the sif as a base 10 value.
|
||
// (see admin\ntsetup\textmode\kernel\spsetup.c)
|
||
//
|
||
wsprintf(szHashValueData,
|
||
TEXT("%d"), dwData); // base 10
|
||
|
||
//
|
||
// This block appends the class key data we want to migrate to a
|
||
// multi-sz style string that will be written to the sif file.
|
||
//
|
||
|
||
//
|
||
// Need space in the section buffer for a string of the form:
|
||
// HashValueName=HashValueData
|
||
//
|
||
dwSpaceNeeded = lstrlen(pszHashValueName) +
|
||
1 + // TEXT('=')
|
||
lstrlen(szHashValueData);
|
||
|
||
//
|
||
// Account for the NULL terminator.
|
||
//
|
||
dwSpaceNeeded += 1;
|
||
|
||
if (dwHashValueSectionRemaining <= dwSpaceNeeded) {
|
||
//
|
||
// ReAllocate the section block.
|
||
//
|
||
LPTSTR p;
|
||
DWORD dwTempSectionLength, dwTempSectionRemaining;
|
||
|
||
dwTempSectionRemaining = dwHashValueSectionRemaining + dwHashValueSectionLength;
|
||
dwTempSectionLength = dwHashValueSectionLength * 2;
|
||
|
||
p = pszHashValueSection;
|
||
p = MyRealloc(p,
|
||
dwTempSectionLength*sizeof(TCHAR));
|
||
|
||
if (!p) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("MigrateHashValues: REALLOC failed!!!\n") ));
|
||
result = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
pszHashValueSection = p;
|
||
dwHashValueSectionRemaining = dwTempSectionRemaining;
|
||
dwHashValueSectionLength = dwTempSectionLength;
|
||
|
||
pszHashValueCurrent = pszHashValueSection +
|
||
(dwHashValueSectionLength -
|
||
dwHashValueSectionRemaining);
|
||
}
|
||
|
||
//
|
||
// Write the current line to the section block.
|
||
//
|
||
dwSpaceConsumed = wsprintf(pszHashValueCurrent,
|
||
TEXT("%s=%s"),
|
||
pszHashValueName,
|
||
szHashValueData);
|
||
|
||
//
|
||
// Account for the NULL terminator.
|
||
//
|
||
dwSpaceConsumed += 1;
|
||
|
||
pszHashValueCurrent += dwSpaceConsumed;
|
||
dwHashValueSectionRemaining -= dwSpaceConsumed;
|
||
}
|
||
|
||
//
|
||
// Once we've enumerated all hash values, add the final NULL terminator to
|
||
// the multi-sz buffer. There must be enough space for the final NULL
|
||
// terminator because the buffer is always reallocated unless there is room.
|
||
//
|
||
MYASSERT(dwHashValueSectionRemaining > 0);
|
||
|
||
MYASSERT(pszHashValueCurrent);
|
||
*pszHashValueCurrent = TEXT('\0');
|
||
|
||
dwHashValueSectionRemaining -= 1;
|
||
|
||
Clean0:
|
||
|
||
//
|
||
// Do some cleanup
|
||
//
|
||
if (pszHashValueName) {
|
||
MyFree(pszHashValueName);
|
||
}
|
||
|
||
if (hEnumKey) {
|
||
RegCloseKey(hEnumKey);
|
||
}
|
||
|
||
#if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
|
||
|
||
//
|
||
// Lock the Enum tree
|
||
//
|
||
LockUnlockEnumTree(TRUE);
|
||
|
||
#endif // DO_LOCK_UNLOCK
|
||
|
||
//
|
||
// Return the buffer to the caller only if successful.
|
||
//
|
||
if (result == ERROR_SUCCESS) {
|
||
*Buffer = pszHashValueSection;
|
||
} else {
|
||
SetLastError(result);
|
||
if (pszHashValueSection) {
|
||
MyFree(pszHashValueSection);
|
||
}
|
||
}
|
||
|
||
return (result == ERROR_SUCCESS);
|
||
|
||
} // MigrateHashValues()
|
||
|
||
|
||
|
||
//
|
||
// Enum branch lock/unlock and security routines - taken from PNPREG.
|
||
// (we only need these if we're doing the Enum lock/unlock thing)
|
||
//
|
||
|
||
#if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
|
||
|
||
|
||
VOID
|
||
LockUnlockEnumTree(
|
||
IN BOOL bLock
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function "locks" or "unlocks" the Plug and Play Enum tree in the
|
||
registry.
|
||
|
||
Arguments:
|
||
|
||
bLock - If TRUE, specifies that the Enum tree should be "locked".
|
||
Otherwise, specifies that the Enum tree should be "unlocked".
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PSECURITY_DESCRIPTOR pSD;
|
||
HKEY hParentKey;
|
||
LONG RegStatus;
|
||
|
||
if (CreateSecurityDescriptors()) {
|
||
|
||
EnumKeysAndApplyDacls(HKEY_LOCAL_MACHINE,
|
||
REGSTR_PATH_SYSTEMENUM,
|
||
0,
|
||
FALSE,
|
||
!bLock,
|
||
bLock ? &g_LockedPrivateKeysSD : &g_DeviceParametersSD,
|
||
&g_DeviceParametersSD);
|
||
|
||
FreeSecurityDescriptors();
|
||
}
|
||
|
||
return;
|
||
|
||
} // LockUnlockEnumTree()
|
||
|
||
|
||
|
||
VOID
|
||
EnumKeysAndApplyDacls(
|
||
IN HKEY hParentKey,
|
||
IN LPTSTR pszKeyName,
|
||
IN DWORD dwLevel,
|
||
IN BOOL bInDeviceParameters,
|
||
IN BOOL bApplyTopDown,
|
||
IN PSECURITY_DESCRIPTOR pPrivateKeySD,
|
||
IN PSECURITY_DESCRIPTOR pDeviceParametersSD
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function applies the DACL in pSD to all the keys rooted at hKey
|
||
including hKey itself.
|
||
|
||
Arguments:
|
||
|
||
hParentKey - Handle to a registry key.
|
||
|
||
pszKeyName - Name of the key.
|
||
|
||
dwLevel - Number of levels remaining to recurse.
|
||
|
||
pSD - Pointer to a security descriptor containing a DACL.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
LONG regStatus;
|
||
DWORD dwMaxSubKeySize;
|
||
LPTSTR pszSubKey;
|
||
DWORD index;
|
||
HKEY hKey;
|
||
BOOL bNewInDeviceParameters;
|
||
|
||
#if 0 //#if DBG // DBG
|
||
DWORD dwStartKeyNameLength = g_dwCurrentKeyNameLength;
|
||
|
||
if (g_dwCurrentKeyNameLength != 0) {
|
||
g_szCurrentKeyName[ g_dwCurrentKeyNameLength++ ] = TEXT('\\');
|
||
}
|
||
|
||
_tcscpy(&g_szCurrentKeyName[g_dwCurrentKeyNameLength], pszKeyName);
|
||
g_dwCurrentKeyNameLength += _tcslen(pszKeyName);
|
||
|
||
#endif // DBG
|
||
|
||
DBGTRACE( DBGF_REGISTRY,
|
||
(TEXT("EnumKeysAndApplyDacls(0x%08X, \"%s\", %d, %s, %s, 0x%08X, 0x%08X)\n"),
|
||
hParentKey,
|
||
g_szCurrentKeyName,
|
||
dwLevel,
|
||
bInDeviceParameters ? TEXT("TRUE") : TEXT("FALSE"),
|
||
bApplyTopDown ? TEXT("TRUE") : TEXT("FALSE"),
|
||
pPrivateKeySD,
|
||
pDeviceParametersSD) );
|
||
|
||
if (bApplyTopDown) {
|
||
|
||
regStatus = RegOpenKeyEx( hParentKey,
|
||
pszKeyName,
|
||
0,
|
||
WRITE_DAC,
|
||
&hKey
|
||
);
|
||
|
||
if (regStatus != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumKeysAndApplyDacls(\"%s\") RegOpenKeyEx() failed, error = %d\n"),
|
||
g_szCurrentKeyName, regStatus));
|
||
|
||
return;
|
||
}
|
||
|
||
DBGTRACE( DBGF_REGISTRY,
|
||
(TEXT("Setting security on %s on the way down\n"),
|
||
g_szCurrentKeyName) );
|
||
|
||
//
|
||
// apply the new security to the registry key
|
||
//
|
||
regStatus = RegSetKeySecurity( hKey,
|
||
DACL_SECURITY_INFORMATION,
|
||
bInDeviceParameters ?
|
||
pDeviceParametersSD :
|
||
pPrivateKeySD
|
||
);
|
||
|
||
if (regStatus != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumKeysAndApplyDacls(\"%s\") RegSetKeySecurity() failed, error = %d\n"),
|
||
g_szCurrentKeyName, regStatus));
|
||
}
|
||
|
||
//
|
||
// Close the key and reopen it later for read (which hopefully was just
|
||
// granted in the DACL we just wrote
|
||
//
|
||
RegCloseKey( hKey );
|
||
}
|
||
|
||
regStatus = RegOpenKeyEx( hParentKey,
|
||
pszKeyName,
|
||
0,
|
||
KEY_READ | WRITE_DAC,
|
||
&hKey
|
||
);
|
||
|
||
if (regStatus != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumKeysAndApplyDacls(\"%s\") RegOpenKeyEx() failed, error = %d\n"),
|
||
g_szCurrentKeyName, regStatus));
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Determine length of longest subkey
|
||
//
|
||
regStatus = RegQueryInfoKey( hKey,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&dwMaxSubKeySize,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL );
|
||
|
||
if (regStatus == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Allocate a buffer to hold the subkey names. RegQueryInfoKey returns the
|
||
// size in characters and doesn't include the NUL terminator.
|
||
//
|
||
pszSubKey = LocalAlloc(0, ++dwMaxSubKeySize * sizeof(TCHAR));
|
||
|
||
if (pszSubKey != NULL) {
|
||
|
||
//
|
||
// Enumerate all the subkeys and then call ourselves recursively for each
|
||
// until dwLevel reaches 0.
|
||
//
|
||
|
||
for (index = 0; ; index++) {
|
||
|
||
regStatus = RegEnumKey( hKey,
|
||
index,
|
||
pszSubKey,
|
||
dwMaxSubKeySize
|
||
);
|
||
|
||
if (regStatus != ERROR_SUCCESS) {
|
||
|
||
if (regStatus != ERROR_NO_MORE_ITEMS) {
|
||
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumKeysAndApplyDacls(\"%s\") RegEnumKeyEx() failed, error = %d\n"),
|
||
g_szCurrentKeyName,
|
||
regStatus) );
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
bNewInDeviceParameters = bInDeviceParameters ||
|
||
(dwLevel == 3 &&
|
||
_tcsicmp( pszSubKey,
|
||
REGSTR_KEY_DEVICEPARAMETERS ) == 0);
|
||
|
||
EnumKeysAndApplyDacls( hKey,
|
||
pszSubKey,
|
||
dwLevel + 1,
|
||
bNewInDeviceParameters,
|
||
bApplyTopDown,
|
||
pPrivateKeySD,
|
||
pDeviceParametersSD
|
||
);
|
||
}
|
||
|
||
LocalFree( pszSubKey );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumKeysAndApplyDacls(\"%s\") RegQueryInfoKey() failed, error = %d\n"),
|
||
g_szCurrentKeyName, regStatus));
|
||
}
|
||
|
||
if (!bApplyTopDown) {
|
||
|
||
DBGTRACE( DBGF_REGISTRY,
|
||
(TEXT("Setting security on %s on the way back up\n"),
|
||
g_szCurrentKeyName) );
|
||
|
||
//
|
||
// apply the new security to the registry key
|
||
//
|
||
regStatus = RegSetKeySecurity( hKey,
|
||
DACL_SECURITY_INFORMATION,
|
||
bInDeviceParameters ?
|
||
pDeviceParametersSD :
|
||
pPrivateKeySD
|
||
);
|
||
|
||
if (regStatus != ERROR_SUCCESS) {
|
||
DBGTRACE( DBGF_ERRORS,
|
||
(TEXT("EnumKeysAndApplyDacls(\"%s\") RegSetKeySecurity() failed, error = %d\n"),
|
||
g_szCurrentKeyName, regStatus));
|
||
}
|
||
}
|
||
|
||
RegCloseKey( hKey );
|
||
|
||
#if 0 //#if DBG // DBG
|
||
g_dwCurrentKeyNameLength = dwStartKeyNameLength;
|
||
g_szCurrentKeyName[g_dwCurrentKeyNameLength] = TEXT('\0');
|
||
#endif // DBG
|
||
|
||
return;
|
||
|
||
} // EnumKeysAndApplyDacls()
|
||
|
||
|
||
|
||
BOOL
|
||
CreateSecurityDescriptors(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function creates a properly initialized Security Descriptor for the
|
||
Device Parameters key and its subkeys. The SIDs and DACL created by this
|
||
routine must be freed by calling FreeSecurityDescriptors.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Pointer to the initialized Security Descriptor. NULL is returned if an
|
||
error occurs.
|
||
|
||
--*/
|
||
|
||
{
|
||
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
||
SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
|
||
|
||
EXPLICIT_ACCESS ExplicitAccess[3];
|
||
|
||
DWORD dwError;
|
||
BOOL bSuccess;
|
||
|
||
DWORD i;
|
||
|
||
FARPROC pSetEntriesInAcl;
|
||
HMODULE pAdvApi32;
|
||
|
||
pAdvApi32 = LoadLibrary( TEXT("advapi32.dll"));
|
||
if (!pAdvApi32) {
|
||
return(FALSE);
|
||
}
|
||
|
||
#ifdef UNICODE
|
||
pSetEntriesInAcl = GetProcAddress( pAdvApi32, "SetEntriesInAclW" );
|
||
#else
|
||
pSetEntriesInAcl = GetProcAddress( pAdvApi32, "SetEntriesInAclA" );
|
||
#endif
|
||
|
||
if (!pSetEntriesInAcl) {
|
||
FreeLibrary( pAdvApi32 );
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// Create SIDs - Admins and System
|
||
//
|
||
|
||
bSuccess = AllocateAndInitializeSid( &NtAuthority,
|
||
2,
|
||
SECURITY_BUILTIN_DOMAIN_RID,
|
||
DOMAIN_ALIAS_RID_ADMINS,
|
||
0, 0, 0, 0, 0, 0,
|
||
&g_pAdminSid);
|
||
|
||
bSuccess = bSuccess && AllocateAndInitializeSid( &NtAuthority,
|
||
1,
|
||
SECURITY_LOCAL_SYSTEM_RID,
|
||
0, 0, 0, 0, 0, 0, 0,
|
||
&g_pSystemSid);
|
||
|
||
bSuccess = bSuccess && AllocateAndInitializeSid( &WorldAuthority,
|
||
1,
|
||
SECURITY_WORLD_RID,
|
||
0, 0, 0, 0, 0, 0, 0,
|
||
&g_pWorldSid);
|
||
|
||
if (bSuccess) {
|
||
|
||
//
|
||
// Initialize Access structures describing the ACEs we want:
|
||
// System Full Control
|
||
// Admins Full Control
|
||
//
|
||
// We'll take advantage of the fact that the unlocked private keys is
|
||
// the same as the device parameters key and they are a superset of the
|
||
// locked private keys.
|
||
//
|
||
// When we create the DACL for the private key we'll specify a subset of
|
||
// the ExplicitAccess array.
|
||
//
|
||
for (i = 0; i < 3; i++) {
|
||
ExplicitAccess[i].grfAccessMode = SET_ACCESS;
|
||
ExplicitAccess[i].grfInheritance = CONTAINER_INHERIT_ACE;
|
||
ExplicitAccess[i].Trustee.pMultipleTrustee = NULL;
|
||
ExplicitAccess[i].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
|
||
ExplicitAccess[i].Trustee.TrusteeForm = TRUSTEE_IS_SID;
|
||
ExplicitAccess[i].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
|
||
}
|
||
|
||
ExplicitAccess[0].grfAccessPermissions = KEY_ALL_ACCESS;
|
||
ExplicitAccess[0].Trustee.ptstrName = (LPTSTR)g_pAdminSid;
|
||
|
||
ExplicitAccess[1].grfAccessPermissions = KEY_ALL_ACCESS;
|
||
ExplicitAccess[1].Trustee.ptstrName = (LPTSTR)g_pSystemSid;
|
||
|
||
ExplicitAccess[2].grfAccessPermissions = KEY_READ;
|
||
ExplicitAccess[2].Trustee.ptstrName = (LPTSTR)g_pWorldSid;
|
||
|
||
//
|
||
// Create the DACL with the both the above ACEs for the DeviceParameters
|
||
//
|
||
dwError = (DWORD)pSetEntriesInAcl( 3,
|
||
ExplicitAccess,
|
||
NULL,
|
||
&g_pDeviceParametersDacl );
|
||
|
||
if (dwError == ERROR_SUCCESS) {
|
||
//
|
||
// Create the DACL with just the system ACE for the locked private
|
||
// keys.
|
||
//
|
||
dwError = (DWORD)pSetEntriesInAcl( 2,
|
||
ExplicitAccess + 1,
|
||
NULL,
|
||
&g_pLockedPrivateKeysDacl );
|
||
}
|
||
|
||
bSuccess = dwError == ERROR_SUCCESS;
|
||
|
||
}
|
||
|
||
//
|
||
// Initialize the DeviceParameters security descriptor
|
||
//
|
||
bSuccess = bSuccess && InitializeSecurityDescriptor( &g_DeviceParametersSD,
|
||
SECURITY_DESCRIPTOR_REVISION );
|
||
|
||
//
|
||
// Set the new DACL in the security descriptor
|
||
//
|
||
bSuccess = bSuccess && SetSecurityDescriptorDacl( &g_DeviceParametersSD,
|
||
TRUE,
|
||
g_pDeviceParametersDacl,
|
||
FALSE);
|
||
|
||
//
|
||
// validate the new security descriptor
|
||
//
|
||
bSuccess = bSuccess && IsValidSecurityDescriptor( &g_DeviceParametersSD );
|
||
|
||
|
||
//
|
||
// Initialize the DeviceParameters security descriptor
|
||
//
|
||
bSuccess = bSuccess && InitializeSecurityDescriptor( &g_LockedPrivateKeysSD,
|
||
SECURITY_DESCRIPTOR_REVISION );
|
||
|
||
//
|
||
// Set the new DACL in the security descriptor
|
||
//
|
||
bSuccess = bSuccess && SetSecurityDescriptorDacl( &g_LockedPrivateKeysSD,
|
||
TRUE,
|
||
g_pLockedPrivateKeysDacl,
|
||
FALSE);
|
||
|
||
//
|
||
// validate the new security descriptor
|
||
//
|
||
bSuccess = bSuccess && IsValidSecurityDescriptor( &g_LockedPrivateKeysSD );
|
||
|
||
|
||
if (!bSuccess) {
|
||
|
||
FreeSecurityDescriptors();
|
||
}
|
||
|
||
FreeLibrary( pAdvApi32 );
|
||
|
||
return bSuccess;
|
||
|
||
} // CreateSecurityDescriptors()
|
||
|
||
|
||
|
||
VOID
|
||
FreeSecurityDescriptors(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function deallocates the data structures allocated and initialized by
|
||
CreateSecurityDescriptors.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
if (g_pDeviceParametersDacl) {
|
||
LocalFree(g_pDeviceParametersDacl);
|
||
g_pDeviceParametersDacl = NULL;
|
||
}
|
||
|
||
if (g_pLockedPrivateKeysDacl) {
|
||
LocalFree(g_pLockedPrivateKeysDacl);
|
||
g_pLockedPrivateKeysDacl = NULL;
|
||
}
|
||
|
||
if (g_pAdminSid != NULL) {
|
||
FreeSid(g_pAdminSid);
|
||
g_pAdminSid = NULL;
|
||
}
|
||
|
||
if (g_pSystemSid != NULL) {
|
||
FreeSid(g_pSystemSid);
|
||
g_pSystemSid = NULL;
|
||
}
|
||
|
||
if (g_pWorldSid != NULL) {
|
||
FreeSid(g_pWorldSid);
|
||
g_pWorldSid = NULL;
|
||
}
|
||
|
||
return;
|
||
|
||
} // FreeSecurityDescriptors()
|
||
|
||
#endif // DO_LOCK_UNLOCK
|
||
|
||
|
||
|