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
|
|||
|
|
|||
|
|
|||
|
|