WindowsXP-SP1/base/remoteboot/imirror/regtool.c
2020-09-30 16:53:49 +02:00

714 lines
19 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
regtool.c
Abstract:
This file contains functions for supporting the registry tools
REGINI, REGDMP, REGDIR and REGFIND
Author:
Steve Wood (stevewo) 15-Nov-1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
LONG
RegLoadHive(
IN PREG_CONTEXT RegistryContext,
IN PWSTR HiveFileName,
IN PWSTR HiveRootName
);
void
RegUnloadHive(
IN PREG_CONTEXT RegistryContext
);
BOOLEAN PrivilegeEnabled;
BOOLEAN RestoreWasEnabled;
BOOLEAN BackupWasEnabled;
BOOLEAN
RTEnableBackupRestorePrivilege( void )
{
NTSTATUS Status;
//
// Try to enable backup and restore privileges
//
Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
TRUE, // Enable
FALSE, // Not impersonating
&RestoreWasEnabled // previous state
);
if (!NT_SUCCESS( Status )) {
return FALSE;
}
Status = RtlAdjustPrivilege( SE_BACKUP_PRIVILEGE,
TRUE, // Enable
FALSE, // Not impersonating
&BackupWasEnabled // previous state
);
if (!NT_SUCCESS( Status )) {
return FALSE;
}
PrivilegeEnabled = TRUE;
return TRUE;
}
void
RTDisableBackupRestorePrivilege( void )
{
//
// Restore privileges to what they were
//
RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
RestoreWasEnabled,
FALSE,
&RestoreWasEnabled
);
RtlAdjustPrivilege( SE_BACKUP_PRIVILEGE,
BackupWasEnabled,
FALSE,
&BackupWasEnabled
);
PrivilegeEnabled = FALSE;
return;
}
LONG
RTConnectToRegistry(
IN PWSTR MachineName,
IN PWSTR HiveFileName,
IN PWSTR HiveRootName,
OUT PWSTR *DefaultRootKeyName,
OUT PREG_CONTEXT RegistryContext
)
{
LONG Error;
if (MachineName != NULL) {
if (HiveRootName || HiveFileName ) {
return ERROR_INVALID_PARAMETER;
}
Error = RegConnectRegistry( MachineName, HKEY_LOCAL_MACHINE, (PHKEY)&RegistryContext->MachineRoot );
if (Error == NO_ERROR) {
Error = RegConnectRegistry( MachineName, HKEY_USERS, (PHKEY)&RegistryContext->UsersRoot );
if (Error == NO_ERROR) {
Error = RegOpenKey( RegistryContext->UsersRoot, L".Default", &RegistryContext->CurrentUserRoot );
}
}
if (Error != NO_ERROR) {
if (RegistryContext->MachineRoot != NULL) {
RegCloseKey( RegistryContext->MachineRoot );
RegistryContext->MachineRoot = NULL;
}
if (RegistryContext->UsersRoot != NULL) {
RegCloseKey( RegistryContext->UsersRoot );
RegistryContext->UsersRoot = NULL;
}
return Error;
}
wcscpy( RegistryContext->MachinePath, L"\\Registry\\Machine" );
wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" );
wcscpy( RegistryContext->CurrentUserPath, L"\\Registry\\Users\\.Default" );
RegistryContext->Target = REG_TARGET_REMOTE_REGISTRY;
}
else if (HiveRootName != NULL || HiveFileName != NULL) {
if (HiveRootName == NULL || HiveFileName == NULL ) {
return ERROR_INVALID_PARAMETER;
}
if (!PrivilegeEnabled && !RTEnableBackupRestorePrivilege()) {
return ERROR_PRIVILEGE_NOT_HELD;
}
RegistryContext->MachineRoot = NULL;
RegistryContext->UsersRoot = NULL;
RegistryContext->CurrentUserRoot = NULL;
Error = RegLoadHive( RegistryContext, HiveFileName, HiveRootName );
if (Error != NO_ERROR) {
return Error;
}
if (DefaultRootKeyName != NULL && *DefaultRootKeyName == NULL) {
*DefaultRootKeyName = HiveRootName;
}
RegistryContext->Target = REG_TARGET_HIVE_REGISTRY;
}
else {
NTSTATUS Status;
UNICODE_STRING CurrentUserKeyPath;
RegistryContext->MachineRoot = HKEY_LOCAL_MACHINE;
RegistryContext->UsersRoot = HKEY_USERS;
RegistryContext->CurrentUserRoot = HKEY_CURRENT_USER;
wcscpy( RegistryContext->MachinePath, L"\\Registry\\Machine" );
wcscpy( RegistryContext->UsersPath, L"\\Registry\\Users" );
Status = RtlFormatCurrentUserKeyPath( &CurrentUserKeyPath );
if (!NT_SUCCESS( Status )) {
SetLastError( RtlNtStatusToDosError( Status ) );
return FALSE;
}
wcscpy( RegistryContext->CurrentUserPath, CurrentUserKeyPath.Buffer );
RtlFreeUnicodeString( &CurrentUserKeyPath );
RegistryContext->Target = REG_TARGET_LOCAL_REGISTRY;
}
if (DefaultRootKeyName != NULL && *DefaultRootKeyName == NULL) {
*DefaultRootKeyName = L"\\Registry";
}
RegistryContext->MachinePathLength = wcslen( RegistryContext->MachinePath );
RegistryContext->UsersPathLength = wcslen( RegistryContext->UsersPath );
RegistryContext->CurrentUserPathLength = wcslen( RegistryContext->CurrentUserPath );
return NO_ERROR;
}
LONG
RTDisconnectFromRegistry(
IN PREG_CONTEXT RegistryContext
)
{
switch( RegistryContext->Target ) {
case REG_TARGET_DISCONNECTED:
break;
case REG_TARGET_LOCAL_REGISTRY:
break;
case REG_TARGET_REMOTE_REGISTRY:
break;
case REG_TARGET_HIVE_REGISTRY:
RegUnloadHive( RegistryContext );
break;
}
if (PrivilegeEnabled) {
RTDisableBackupRestorePrivilege();
}
RegistryContext->Target = REG_TARGET_DISCONNECTED;
return NO_ERROR;
}
UNICODE_STRING RegHiveRootName;
LONG
RegLoadHive(
IN PREG_CONTEXT RegistryContext,
IN PWSTR HiveFileName,
IN PWSTR HiveRootName
)
{
NTSTATUS Status;
UNICODE_STRING NtFileName;
OBJECT_ATTRIBUTES File;
if (!RtlDosPathNameToNtPathName_U( HiveFileName,
&NtFileName,
NULL,
NULL
)
) {
return ERROR_BAD_PATHNAME;
}
InitializeObjectAttributes( &File,
&NtFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
RtlInitUnicodeString( &RegHiveRootName, L"\\Registry");
InitializeObjectAttributes( &RegistryContext->HiveRootKey,
&RegHiveRootName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenKey( &RegistryContext->HiveRootHandle,
MAXIMUM_ALLOWED,
&RegistryContext->HiveRootKey
);
RtlFreeHeap(RtlProcessHeap(), 0, NtFileName.Buffer);
if (!NT_SUCCESS(Status)) {
return RtlNtStatusToDosError( Status );
}
RtlInitUnicodeString( &RegHiveRootName, HiveRootName );
InitializeObjectAttributes( &RegistryContext->HiveRootKey,
&RegHiveRootName,
OBJ_CASE_INSENSITIVE,
RegistryContext->HiveRootHandle,
NULL
);
NtUnloadKey( &RegistryContext->HiveRootKey );
Status = NtLoadKey( &RegistryContext->HiveRootKey, &File );
if (!NT_SUCCESS( Status )) {
return RtlNtStatusToDosError( Status );
}
return NO_ERROR;
}
void
RegUnloadHive(
IN PREG_CONTEXT RegistryContext
)
{
NTSTATUS Status;
HANDLE Handle;
PREG_CONTEXT_OPEN_HIVE_KEY p, p1;
Status = NtOpenKey( &Handle,
MAXIMUM_ALLOWED,
&RegistryContext->HiveRootKey
);
if (NT_SUCCESS( Status )) {
NtFlushKey( Handle );
NtClose( Handle );
}
p = RegistryContext->OpenHiveKeys;
while (p) {
RegCloseKey( p->KeyHandle );
p1 = p;
p = p->Next;
HeapFree( GetProcessHeap(), 0, p1 );
};
do {
Status = NtUnloadKey( &RegistryContext->HiveRootKey );
}
while (NT_SUCCESS( Status ) );
NtClose( RegistryContext->HiveRootHandle );
return;
}
void
RegRememberOpenKey(
IN PREG_CONTEXT RegistryContext,
IN HKEY KeyHandle
)
{
PREG_CONTEXT_OPEN_HIVE_KEY p, *pp;
pp = &RegistryContext->OpenHiveKeys;
while ((p = *pp) != NULL) {
if (p->KeyHandle == KeyHandle) {
p->ReferenceCount += 1;
return;
}
else {
pp = &p->Next;
}
}
p = HeapAlloc( GetProcessHeap(), 0, sizeof( *p ) );
if (p != NULL) {
p->KeyHandle = KeyHandle;
p->ReferenceCount = 1;
p->Next = NULL;
*pp = p;
}
return;
}
void
RegForgetOpenKey(
IN PREG_CONTEXT RegistryContext,
IN HKEY KeyHandle
)
{
PREG_CONTEXT_OPEN_HIVE_KEY p, *pp;
pp = &RegistryContext->OpenHiveKeys;
while ((p = *pp) != NULL) {
if (p->KeyHandle == KeyHandle) {
p->ReferenceCount -= 1;
if (p->ReferenceCount == 0) {
*pp = p->Next;
HeapFree( GetProcessHeap(), 0, p );
return;
}
}
else {
pp = &p->Next;
}
}
return;
}
BOOLEAN
RegCheckPrefix(
IN OUT PCWSTR *s,
IN PCWSTR Prefix,
IN ULONG PrefixLength
)
{
if (PrefixLength == 0) {
return FALSE;
}
if (!_wcsnicmp( *s, Prefix, PrefixLength )) {
*s += PrefixLength;
return TRUE;
}
return FALSE;
}
BOOLEAN
RegValidateKeyPath(
IN PREG_CONTEXT RegistryContext,
IN OUT PHKEY RootKeyHandle,
IN OUT PCWSTR *SubKeyName
)
{
PCWSTR s;
s = *SubKeyName;
if (*RootKeyHandle == NULL) {
if (RegCheckPrefix( &s, L"USER:", 5 ) ||
RegCheckPrefix( &s, L"HKEY_CURRENT_USER", 17 )
) {
if (RegistryContext->CurrentUserRoot == NULL) {
SetLastError( ERROR_BAD_PATHNAME );
return FALSE;
}
if (*s == L'\\') {
s += 1;
}
else
if (s[-1] != L':' && *s != UNICODE_NULL) {
SetLastError( ERROR_BAD_PATHNAME );
return FALSE;
}
*RootKeyHandle = RegistryContext->CurrentUserRoot;
}
else
if (RegCheckPrefix( &s, L"HKEY_LOCAL_MACHINE", 18 )) {
if (*s == L'\\') {
s += 1;
}
else
if (*s != UNICODE_NULL) {
SetLastError( ERROR_BAD_PATHNAME );
return FALSE;
}
*RootKeyHandle = RegistryContext->MachineRoot;
}
else
if (RegCheckPrefix( &s, L"HKEY_USERS", 10 )) {
if (*s == L'\\') {
s += 1;
}
else
if (*s != UNICODE_NULL) {
SetLastError( ERROR_BAD_PATHNAME );
return FALSE;
}
*RootKeyHandle = RegistryContext->UsersRoot;
}
else
if (*s != L'\\') {
SetLastError( ERROR_BAD_PATHNAME );
return FALSE;
}
else
if (RegCheckPrefix( &s, RegistryContext->MachinePath, RegistryContext->MachinePathLength )) {
*RootKeyHandle = RegistryContext->MachineRoot;
if (*s == L'\\') {
s += 1;
}
}
else
if (RegCheckPrefix( &s, RegistryContext->UsersPath, RegistryContext->UsersPathLength )) {
*RootKeyHandle = RegistryContext->UsersRoot;
if (*s == L'\\') {
s += 1;
}
}
else
if (RegCheckPrefix( &s, RegistryContext->CurrentUserPath, RegistryContext->CurrentUserPathLength )) {
*RootKeyHandle = RegistryContext->CurrentUserRoot;
if (*s == L'\\') {
s += 1;
}
}
else
if (!_wcsicmp( *SubKeyName, L"\\Registry" )) {
*RootKeyHandle = NULL;
}
else {
SetLastError( ERROR_BAD_PATHNAME );
return FALSE;
}
}
else
if (*s == L'\\') {
SetLastError( ERROR_BAD_PATHNAME );
return FALSE;
}
*SubKeyName = s;
return TRUE;
}
LONG
RTCreateKey(
IN PREG_CONTEXT RegistryContext,
IN HKEY RootKeyHandle,
IN PCWSTR SubKeyName,
IN ACCESS_MASK DesiredAccess,
IN ULONG CreateOptions,
IN PVOID SecurityDescriptor,
OUT PHKEY ReturnedKeyHandle,
OUT PULONG Disposition
)
{
LONG Error;
SECURITY_ATTRIBUTES SecurityAttributes;
if (!RegValidateKeyPath( RegistryContext, &RootKeyHandle, &SubKeyName )) {
return GetLastError();
}
if (RootKeyHandle == NULL) {
*Disposition = REG_OPENED_EXISTING_KEY;
*ReturnedKeyHandle = HKEY_REGISTRY_ROOT;
return NO_ERROR;
}
else
if (RootKeyHandle == HKEY_REGISTRY_ROOT) {
*ReturnedKeyHandle = NULL;
if (!_wcsicmp( SubKeyName, L"Machine" )) {
*ReturnedKeyHandle = RegistryContext->MachineRoot;
}
else
if (!_wcsicmp( SubKeyName, L"Users" )) {
*ReturnedKeyHandle = RegistryContext->UsersRoot;
}
if (*ReturnedKeyHandle != NULL) {
return NO_ERROR;
}
else {
return ERROR_PATH_NOT_FOUND;
}
}
SecurityAttributes.nLength = sizeof( SecurityAttributes );
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
SecurityAttributes.bInheritHandle = FALSE;
Error = RegCreateKeyEx( RootKeyHandle,
SubKeyName,
0,
NULL,
CreateOptions,
(REGSAM)DesiredAccess,
&SecurityAttributes,
ReturnedKeyHandle,
Disposition
);
if (Error == NO_ERROR &&
RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
) {
RegRememberOpenKey( RegistryContext, *ReturnedKeyHandle );
}
if (Error == NO_ERROR &&
*Disposition == REG_OPENED_EXISTING_KEY &&
SecurityDescriptor != NULL
) {
RegSetKeySecurity( *ReturnedKeyHandle,
DACL_SECURITY_INFORMATION,
SecurityDescriptor
);
}
return Error;
}
LONG
RTOpenKey(
IN PREG_CONTEXT RegistryContext,
IN HKEY RootKeyHandle,
IN PCWSTR SubKeyName,
IN ACCESS_MASK DesiredAccess,
IN ULONG OpenOptions,
OUT PHKEY ReturnedKeyHandle
)
{
LONG Error;
if (!RegValidateKeyPath( RegistryContext, &RootKeyHandle, &SubKeyName )) {
return GetLastError();
}
if (RootKeyHandle == NULL) {
*ReturnedKeyHandle = HKEY_REGISTRY_ROOT;
return NO_ERROR;
}
else
if (RootKeyHandle == HKEY_REGISTRY_ROOT) {
*ReturnedKeyHandle = NULL;
if (!_wcsicmp( SubKeyName, L"Machine" )) {
*ReturnedKeyHandle = RegistryContext->MachineRoot;
}
else
if (!_wcsicmp( SubKeyName, L"Users" )) {
*ReturnedKeyHandle = RegistryContext->UsersRoot;
}
if (*ReturnedKeyHandle != NULL) {
return NO_ERROR;
}
else {
return ERROR_PATH_NOT_FOUND;
}
}
Error = RegOpenKeyEx( RootKeyHandle,
SubKeyName,
OpenOptions,
DesiredAccess,
ReturnedKeyHandle
);
if (Error == NO_ERROR &&
RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
) {
RegRememberOpenKey( RegistryContext, *ReturnedKeyHandle );
}
return Error;
}
LONG
RTCloseKey(
IN PREG_CONTEXT RegistryContext,
IN HKEY KeyHandle
)
{
LONG Error;
if (KeyHandle == HKEY_REGISTRY_ROOT) {
return NO_ERROR;
}
else {
Error = RegCloseKey( KeyHandle );
if (Error == NO_ERROR &&
RegistryContext->Target == REG_TARGET_HIVE_REGISTRY
) {
RegForgetOpenKey( RegistryContext, KeyHandle );
}
return Error;
}
}
LONG
RTEnumerateValueKey(
IN PREG_CONTEXT RegistryContext,
IN HKEY KeyHandle,
IN ULONG Index,
OUT PULONG ValueType,
IN OUT PULONG ValueNameLength,
OUT PWSTR ValueName,
IN OUT PULONG ValueDataLength,
OUT PVOID ValueData
)
{
ULONG Error;
if (KeyHandle == HKEY_REGISTRY_ROOT) {
return ERROR_NO_MORE_ITEMS;
}
else {
Error = RegEnumValue( KeyHandle,
Index,
ValueName,
ValueNameLength,
NULL,
ValueType,
ValueData,
ValueDataLength
);
if (Error == NO_ERROR) {
RtlZeroMemory( (PCHAR)ValueData + *ValueDataLength, 4 - (*ValueDataLength & 3) );
}
return Error;
}
}
LONG
RTQueryValueKey(
IN PREG_CONTEXT RegistryContext,
IN HKEY KeyHandle,
IN PWSTR ValueName,
OUT PULONG ValueType,
IN OUT PULONG ValueDataLength,
OUT PVOID ValueData
)
{
LONG Error;
Error = RegQueryValueEx( KeyHandle,
ValueName,
NULL,
ValueType,
ValueData,
ValueDataLength
);
if (Error == NO_ERROR) {
RtlZeroMemory( (PCHAR)ValueData + *ValueDataLength, 4 - (*ValueDataLength & 3) );
}
return Error;
}