Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131/* * ReactOS kernel * Copyright (C) 2003 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *//* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Setup Library * FILE: base/setup/lib/registry.c * PURPOSE: Registry creation functions * PROGRAMMERS: ... * Hermes Belusca-Maito (hermes.belusca@sfr.fr) */
/* INCLUDES *****************************************************************/
#include "precomp.h"#include "filesup.h"#include "infsupp.h"#include "regutil.h"
#include "registry.h"
#define NDEBUG#include <debug.h>
// #ifdef __REACTOS__#if 1 // FIXME: Disable if setupapi.h is included in the code...#define FLG_ADDREG_BINVALUETYPE 0x00000001#define FLG_ADDREG_NOCLOBBER 0x00000002#define FLG_ADDREG_DELVAL 0x00000004#define FLG_ADDREG_APPEND 0x00000008#define FLG_ADDREG_KEYONLY 0x00000010#define FLG_ADDREG_OVERWRITEONLY 0x00000020#define FLG_ADDREG_TYPE_SZ 0x00000000#define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000#define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000#define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)#define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)#define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)#define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)#endif
/* GLOBALS ******************************************************************/
#define REGISTRY_SETUP_MACHINE L"\\Registry\\Machine\\SYSTEM\\USetup_Machine\\"#define REGISTRY_SETUP_USER L"\\Registry\\Machine\\SYSTEM\\USetup_User\\"
typedef struct _ROOT_KEY{ PCWSTR Name; PCWSTR MountPoint; HANDLE Handle;} ROOT_KEY, *PROOT_KEY;
ROOT_KEY RootKeys[] ={ { L"HKCR", REGISTRY_SETUP_MACHINE L"SOFTWARE\\Classes\\", NULL }, /* "\\Registry\\Machine\\SOFTWARE\\Classes\\" */ // HKEY_CLASSES_ROOT { L"HKCU", REGISTRY_SETUP_USER L".DEFAULT\\" , NULL }, /* "\\Registry\\User\\.DEFAULT\\" */ // HKEY_CURRENT_USER { L"HKLM", REGISTRY_SETUP_MACHINE , NULL }, /* "\\Registry\\Machine\\" */ // HKEY_LOCAL_MACHINE { L"HKU" , REGISTRY_SETUP_USER , NULL }, /* "\\Registry\\User\\" */ // HKEY_USERS#if 0 { L"HKR", NULL, NULL },#endif};
/* FUNCTIONS ****************************************************************/
#define IsPredefKey(HKey) \ (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
#define GetPredefKeyIndex(HKey) \ ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
HANDLEGetRootKeyByPredefKey( IN HANDLE KeyHandle, OUT PCWSTR* RootKeyMountPoint OPTIONAL){ ULONG_PTR Index = GetPredefKeyIndex(KeyHandle);
if (!IsPredefKey(KeyHandle)) return NULL; if (Index >= ARRAYSIZE(RootKeys)) return NULL;
if (RootKeyMountPoint) *RootKeyMountPoint = RootKeys[Index].MountPoint; return RootKeys[Index].Handle;}
HANDLEGetRootKeyByName( IN PCWSTR RootKeyName, OUT PCWSTR* RootKeyMountPoint OPTIONAL){ UCHAR i;
for (i = 0; i < ARRAYSIZE(RootKeys); ++i) { if (!_wcsicmp(RootKeyName, RootKeys[i].Name)) { if (RootKeyMountPoint) *RootKeyMountPoint = RootKeys[i].MountPoint; return RootKeys[i].Handle; } }
return NULL;}
/*********************************************************************** * append_multi_sz_value * * Append a multisz string to a multisz registry value. */// NOTE: Synced with setupapi/install.c ; see also mkhive/reginf.c#if 0static voidappend_multi_sz_value (HANDLE hkey, const WCHAR *value, const WCHAR *strings, DWORD str_size ){ DWORD size, type, total; WCHAR *buffer, *p;
if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return; if (type != REG_MULTI_SZ) return;
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size + str_size * sizeof(WCHAR) ))) return; if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
/* compare each string against all the existing ones */ total = size; while (*strings) { int len = strlenW(strings) + 1;
for (p = buffer; *p; p += strlenW(p) + 1) if (!strcmpiW( p, strings )) break;
if (!*p) /* not found, need to append it */ { memcpy( p, strings, len * sizeof(WCHAR) ); p[len] = 0; total += len; } strings += len; } if (total != size) { TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) ); RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total ); } done: HeapFree( GetProcessHeap(), 0, buffer );}#endif
/*********************************************************************** * delete_multi_sz_value * * Remove a string from a multisz registry value. */#if 0static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string ){ DWORD size, type; WCHAR *buffer, *src, *dst;
if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return; if (type != REG_MULTI_SZ) return; /* allocate double the size, one for value before and one for after */ if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return; if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done; src = buffer; dst = buffer + size; while (*src) { int len = strlenW(src) + 1; if (strcmpiW( src, string )) { memcpy( dst, src, len * sizeof(WCHAR) ); dst += len; } src += len; } *dst++ = 0; if (dst != buffer + 2*size) /* did we remove something? */ { TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) ); RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)(buffer + size), dst - (buffer + size) ); } done: HeapFree( GetProcessHeap(), 0, buffer );}#endif
/*********************************************************************** * do_reg_operation * * Perform an add/delete registry operation depending on the flags. */static BOOLEANdo_reg_operation(HANDLE KeyHandle, PUNICODE_STRING ValueName, PINFCONTEXT Context, ULONG Flags){ WCHAR EmptyStr = 0; ULONG Type; ULONG Size;
if (Flags & FLG_ADDREG_DELVAL) /* deletion */ {#if 0 if (ValueName) { RegDeleteValueW( KeyHandle, ValueName ); } else { RegDeleteKeyW( KeyHandle, NULL ); }#endif return TRUE; }
if (Flags & FLG_ADDREG_KEYONLY) return TRUE;
#if 0 if (Flags & (FLG_ADDREG_NOCLOBBER | FLG_ADDREG_OVERWRITEONLY)) { BOOL exists = !RegQueryValueExW( hkey, ValueName, NULL, NULL, NULL, NULL ); if (exists && (flags & FLG_ADDREG_NOCLOBBER)) return TRUE; if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY)) return TRUE; }#endif
switch (Flags & FLG_ADDREG_TYPE_MASK) { case FLG_ADDREG_TYPE_SZ: Type = REG_SZ; break;
case FLG_ADDREG_TYPE_MULTI_SZ: Type = REG_MULTI_SZ; break;
case FLG_ADDREG_TYPE_EXPAND_SZ: Type = REG_EXPAND_SZ; break;
case FLG_ADDREG_TYPE_BINARY: Type = REG_BINARY; break;
case FLG_ADDREG_TYPE_DWORD: Type = REG_DWORD; break;
case FLG_ADDREG_TYPE_NONE: Type = REG_NONE; break;
default: Type = Flags >> 16; break; }
if (!(Flags & FLG_ADDREG_BINVALUETYPE) || (Type == REG_DWORD && SpInfGetFieldCount(Context) == 5)) { PWCHAR Str = NULL;
if (Type == REG_MULTI_SZ) { if (!SpInfGetMultiSzField(Context, 5, NULL, 0, &Size)) Size = 0;
if (Size) { Str = (WCHAR*) RtlAllocateHeap(ProcessHeap, 0, Size * sizeof(WCHAR)); if (Str == NULL) return FALSE;
SpInfGetMultiSzField(Context, 5, Str, Size, NULL); }
if (Flags & FLG_ADDREG_APPEND) { if (Str == NULL) return TRUE;
DPRINT1("append_multi_sz_value '%S' commented out, WHY??\n", ValueName);// append_multi_sz_value( hkey, value, str, size );
RtlFreeHeap (ProcessHeap, 0, Str); return TRUE; } /* else fall through to normal string handling */ } else { if (!SpInfGetStringField(Context, 5, NULL, 0, &Size)) Size = 0;
if (Size) { Str = (WCHAR*)RtlAllocateHeap(ProcessHeap, 0, Size * sizeof(WCHAR)); if (Str == NULL) return FALSE;
SpInfGetStringField(Context, 5, Str, Size, NULL); } }
if (Type == REG_DWORD) { ULONG dw = Str ? wcstoul (Str, NULL, 0) : 0;
DPRINT("setting dword %wZ to %lx\n", ValueName, dw);
NtSetValueKey (KeyHandle, ValueName, 0, Type, (PVOID)&dw, sizeof(ULONG)); } else { DPRINT("setting value %wZ to %S\n", ValueName, Str);
if (Str) { NtSetValueKey (KeyHandle, ValueName, 0, Type, (PVOID)Str, Size * sizeof(WCHAR)); } else { NtSetValueKey (KeyHandle, ValueName, 0, Type, (PVOID)&EmptyStr, sizeof(WCHAR)); } } RtlFreeHeap (ProcessHeap, 0, Str); } else /* get the binary data */ { PUCHAR Data = NULL;
if (!SpInfGetBinaryField(Context, 5, NULL, 0, &Size)) Size = 0;
if (Size) { Data = (unsigned char*) RtlAllocateHeap(ProcessHeap, 0, Size); if (Data == NULL) return FALSE;
DPRINT("setting binary data %wZ len %lu\n", ValueName, Size); SpInfGetBinaryField(Context, 5, Data, Size, NULL); }
NtSetValueKey (KeyHandle, ValueName, 0, Type, (PVOID)Data, Size);
RtlFreeHeap (ProcessHeap, 0, Data); }
return TRUE;}
/*********************************************************************** * registry_callback * * Called once for each AddReg and DelReg entry in a given section. */static BOOLEANregistry_callback(HINF hInf, PCWSTR Section, BOOLEAN Delete){ NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING Name, Value; PUNICODE_STRING ValuePtr; UINT Flags; WCHAR Buffer[MAX_INF_STRING_LENGTH];
INFCONTEXT Context; PCWSTR RootKeyName; HANDLE RootKeyHandle, KeyHandle; BOOLEAN Ok;
Ok = SpInfFindFirstLine(hInf, Section, NULL, &Context); if (!Ok) return TRUE; /* Don't fail if the section isn't present */
for (;Ok; Ok = SpInfFindNextLine(&Context, &Context)) { /* get root */ if (!SpInfGetStringField(&Context, 1, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL)) continue; RootKeyHandle = GetRootKeyByName(Buffer, &RootKeyName); if (!RootKeyHandle) continue;
/* get key */ if (!SpInfGetStringField(&Context, 2, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL)) *Buffer = 0;
DPRINT("KeyName: <%S\\%S>\n", RootKeyName, Buffer);
/* get flags */ if (!SpInfGetIntField(&Context, 4, (PINT)&Flags)) Flags = 0;
DPRINT("Flags: %lx\n", Flags);
RtlInitUnicodeString(&Name, Buffer); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, RootKeyHandle, NULL);
if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY)) { Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &Name, Status); continue; /* ignore if it doesn't exist */ } } else { Status = CreateNestedKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes, REG_OPTION_NON_VOLATILE); if (!NT_SUCCESS(Status)) { DPRINT1("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name, Status); continue; } }
/* get value name */ if (SpInfGetStringField(&Context, 3, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL)) { RtlInitUnicodeString(&Value, Buffer); ValuePtr = &Value; } else { ValuePtr = NULL; }
/* and now do it */ if (!do_reg_operation(KeyHandle, ValuePtr, &Context, Flags)) { NtClose(KeyHandle); return FALSE; }
NtClose(KeyHandle); }
return TRUE;}
BOOLEANImportRegistryFile( IN PCWSTR SourcePath, IN PCWSTR FileName, IN PCWSTR Section, IN LCID LocaleId, IN BOOLEAN Delete){ HINF hInf; UINT ErrorLine; WCHAR FileNameBuffer[MAX_PATH];
/* Load the INF file from the installation media */ CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2, SourcePath, FileName);
hInf = SpInfOpenInfFile(FileNameBuffer, NULL, INF_STYLE_WIN4, LocaleId, &ErrorLine); if (hInf == INVALID_HANDLE_VALUE) { DPRINT1("SpInfOpenInfFile() failed\n"); return FALSE; }
#if 0 if (!registry_callback(hInf, L"DelReg", FALSE)) { DPRINT1("registry_callback() failed\n"); SpInfCloseInfFile(hInf); return FALSE; }#endif
if (!registry_callback(hInf, L"AddReg", FALSE)) { DPRINT1("registry_callback() failed\n"); SpInfCloseInfFile(hInf); return FALSE; }
if (!registry_callback(hInf, L"AddReg.NT" INF_ARCH, FALSE)) { DPRINT1("registry_callback() failed\n"); SpInfCloseInfFile(hInf); return FALSE; }
SpInfCloseInfFile(hInf); return TRUE;}
typedef enum _HIVE_UPDATE_STATE{ Create, // Create a new hive file and save possibly existing old one with a .old extension. Repair, // Re-create a new hive file and save possibly existing old one with a .brk extension. Update // Hive update, do not need to be recreated.} HIVE_UPDATE_STATE;
typedef struct _HIVE_LIST_ENTRY{ PCWSTR HiveName; // HiveFileName; PCWSTR HiveRegistryPath; // HiveRegMountPoint; HANDLE PredefKeyHandle; PCWSTR RegSymLink; HIVE_UPDATE_STATE State; // PUCHAR SecurityDescriptor; // ULONG SecurityDescriptorLength;} HIVE_LIST_ENTRY, *PHIVE_LIST_ENTRY;
#define NUMBER_OF_STANDARD_REGISTRY_HIVES 3
HIVE_LIST_ENTRY RegistryHives[/*NUMBER_OF_STANDARD_REGISTRY_HIVES*/] ={ { L"SYSTEM" , L"\\Registry\\Machine\\USetup_SYSTEM" , HKEY_LOCAL_MACHINE, L"SYSTEM" , Create /* , SystemSecurity , sizeof(SystemSecurity) */ }, { L"SOFTWARE", L"\\Registry\\Machine\\USetup_SOFTWARE", HKEY_LOCAL_MACHINE, L"SOFTWARE", Create /* , SoftwareSecurity, sizeof(SoftwareSecurity) */ }, { L"DEFAULT" , L"\\Registry\\User\\USetup_DEFAULT" , HKEY_USERS , L".DEFAULT", Create /* , SystemSecurity , sizeof(SystemSecurity) */ },
// { L"BCD" , L"\\Registry\\Machine\\USetup_BCD", HKEY_LOCAL_MACHINE, L"BCD00000000", Create /* , BcdSecurity , sizeof(BcdSecurity) */ },};C_ASSERT(_countof(RegistryHives) == NUMBER_OF_STANDARD_REGISTRY_HIVES);
#define NUMBER_OF_SECURITY_REGISTRY_HIVES 2
/** These hives are created by LSASS during 2nd stage setup */HIVE_LIST_ENTRY SecurityRegistryHives[/*NUMBER_OF_SECURITY_REGISTRY_HIVES*/] ={ { L"SAM" , L"\\Registry\\Machine\\USetup_SAM" , HKEY_LOCAL_MACHINE, L"SAM" , Create /* , SystemSecurity , sizeof(SystemSecurity) */ }, { L"SECURITY", L"\\Registry\\Machine\\USetup_SECURITY", HKEY_LOCAL_MACHINE, L"SECURITY", Create /* , NULL , 0 */ },};C_ASSERT(_countof(SecurityRegistryHives) == NUMBER_OF_SECURITY_REGISTRY_HIVES);
NTSTATUSVerifyRegistryHives( IN PUNICODE_STRING NtSystemRoot, OUT PBOOLEAN ShouldRepairRegistry){ NTSTATUS Status; BOOLEAN PrivilegeSet[2] = {FALSE, FALSE}; UINT i;
/* Suppose first the registry hives do not have to be fully recreated */ *ShouldRepairRegistry = FALSE;
/* Acquire restore privilege */ Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]); if (!NT_SUCCESS(Status)) { DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status); /* Exit prematurely here.... */ return Status; }
/* Acquire backup privilege */ Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]); if (!NT_SUCCESS(Status)) { DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status); RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]); /* Exit prematurely here.... */ return Status; }
for (i = 0; i < ARRAYSIZE(RegistryHives); ++i) { Status = VerifyRegistryHive(NtSystemRoot, RegistryHives[i].HiveName); if (!NT_SUCCESS(Status)) { DPRINT1("Registry hive '%S' needs repair!\n", RegistryHives[i].HiveName); RegistryHives[i].State = Repair; *ShouldRepairRegistry = TRUE; } else { RegistryHives[i].State = Update; } }
/** These hives are created by LSASS during 2nd stage setup */ for (i = 0; i < ARRAYSIZE(SecurityRegistryHives); ++i) { Status = VerifyRegistryHive(NtSystemRoot, SecurityRegistryHives[i].HiveName); if (!NT_SUCCESS(Status)) { DPRINT1("Registry hive '%S' needs repair!\n", SecurityRegistryHives[i].HiveName); SecurityRegistryHives[i].State = Repair; /* * Note that it's not the role of the 1st-stage installer to fix * the security hives. This should be done at 2nd-stage installation * by LSASS. */ } else { SecurityRegistryHives[i].State = Update; } }
/* Reset the status (we succeeded in checking all the hives) */ Status = STATUS_SUCCESS;
/* Remove restore and backup privileges */ RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]); RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
return Status;}
NTSTATUSRegInitializeRegistry( IN PUNICODE_STRING NtSystemRoot){ NTSTATUS Status; HANDLE KeyHandle; UNICODE_STRING KeyName; OBJECT_ATTRIBUTES ObjectAttributes; BOOLEAN PrivilegeSet[2] = {FALSE, FALSE}; ULONG Disposition; UINT i;
/* Acquire restore privilege */ Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]); if (!NT_SUCCESS(Status)) { DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status); /* Exit prematurely here.... */ return Status; }
/* Acquire backup privilege */ Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]); if (!NT_SUCCESS(Status)) { DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status); RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]); /* Exit prematurely here.... */ return Status; }
/* * Create the template proto-hive. * * Use a dummy root key name: * - On 2k/XP/2k3, this is "$$$PROTO.HIV" * - On Vista+, this is "CMI-CreateHive{guid}" * See https://github.com/libyal/winreg-kb/blob/main/docs/sources/windows-registry/Files.md * for more information. */ RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM\\$$$PROTO.HIV"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtCreateKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateKey() failed to create the proto-hive (Status %lx)\n", Status); goto Quit; } NtFlushKey(KeyHandle);
for (i = 0; i < ARRAYSIZE(RegistryHives); ++i) { if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair) continue;
Status = CreateRegistryFile(NtSystemRoot, RegistryHives[i].HiveName, RegistryHives[i].State != Repair, // RegistryHives[i].State == Create, KeyHandle); if (!NT_SUCCESS(Status)) { DPRINT1("CreateRegistryFile(%S) failed, Status 0x%08lx\n", RegistryHives[i].HiveName, Status); /* Exit prematurely here.... */ /* That is now done, remove the proto-hive */ NtDeleteKey(KeyHandle); NtClose(KeyHandle); goto Quit; } }
/* That is now done, remove the proto-hive */ NtDeleteKey(KeyHandle); NtClose(KeyHandle);
/* * Prepare the registry root keys. Since we cannot create real registry keys * inside the master keys (\Registry, \Registry\Machine or \Registry\User), * we need to perform some SymLink tricks instead. */
/* Our offline HKLM '\Registry\Machine' is inside '\Registry\Machine\SYSTEM\USetup_Machine' */ RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].MountPoint); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); KeyHandle = NULL; Status = NtCreateKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, // FIXME: Using REG_OPTION_VOLATILE works OK on Windows, // but I need to check whether it works OK on ReactOS too. REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE, &Disposition); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName, Status); // return Status; } RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle = KeyHandle;
/* Our offline HKU '\Registry\User' is inside '\Registry\Machine\SYSTEM\USetup_User' */ RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_USERS)].MountPoint); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); KeyHandle = NULL; Status = NtCreateKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, // FIXME: Using REG_OPTION_VOLATILE works OK on Windows, // but I need to check whether it works OK on ReactOS too. REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE, &Disposition); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName, Status); // return Status; } RootKeys[GetPredefKeyIndex(HKEY_USERS)].Handle = KeyHandle;
/* * Now properly mount the offline hive files */ for (i = 0; i < ARRAYSIZE(RegistryHives); ++i) { // if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair) // continue;
if (RegistryHives[i].State == Create || RegistryHives[i].State == Repair) { Status = ConnectRegistry(NULL, RegistryHives[i].HiveRegistryPath, NtSystemRoot, RegistryHives[i].HiveName /* SystemSecurity, sizeof(SystemSecurity) */); if (!NT_SUCCESS(Status)) { DPRINT1("ConnectRegistry(%S) failed, Status 0x%08lx\n", RegistryHives[i].HiveName, Status); }
/* Create the registry symlink to this key */ Status = CreateSymLinkKey(RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle, RegistryHives[i].RegSymLink, RegistryHives[i].HiveRegistryPath); if (!NT_SUCCESS(Status)) { DPRINT1("CreateSymLinkKey(%S) failed, Status 0x%08lx\n", RegistryHives[i].RegSymLink, Status); } } else { /* Create *DUMMY* volatile hives just to make the update procedure working */
RtlInitUnicodeString(&KeyName, RegistryHives[i].RegSymLink); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle, NULL); KeyHandle = NULL; Status = NtCreateKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, // FIXME: Using REG_OPTION_VOLATILE works OK on Windows, // but I need to check whether it works OK on ReactOS too. REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE, &Disposition); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName, Status); // return Status; } NtClose(KeyHandle); } }
/* HKCU is a handle to 'HKU\.DEFAULT' */#if 0 RtlInitUnicodeString(&KeyName, L".DEFAULT"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, RootKeys[GetPredefKeyIndex(HKEY_USERS)].Handle, NULL);#else RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_CURRENT_USER)].MountPoint); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);#endif KeyHandle = NULL; Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &KeyName, Status); } RootKeys[GetPredefKeyIndex(HKEY_CURRENT_USER)].Handle = KeyHandle;
/* HKCR is a handle to 'HKLM\Software\Classes' */#if 0 RtlInitUnicodeString(&KeyName, L"Software\\Classes"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle, NULL);#else RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_CLASSES_ROOT)].MountPoint); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);#endif KeyHandle = NULL; /* We use NtCreateKey instead of NtOpenKey because Software\Classes doesn't exist originally */ Status = NtCreateKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &Disposition); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateKey(%wZ) failed (Status %lx)\n", &KeyName, Status); } else { DPRINT("NtCreateKey() succeeded to %s the %wZ key (Status %lx)\n", Disposition == REG_CREATED_NEW_KEY ? "create" : /* REG_OPENED_EXISTING_KEY */ "open", &KeyName, Status); } RootKeys[GetPredefKeyIndex(HKEY_CLASSES_ROOT)].Handle = KeyHandle;
Status = STATUS_SUCCESS;
/* Create the 'HKLM\SYSTEM\ControlSet001' key */ // REGISTRY_SETUP_MACHINE L"SYSTEM\\ControlSet001" RtlInitUnicodeString(&KeyName, L"SYSTEM\\ControlSet001"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle, NULL); Status = NtCreateKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &Disposition); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateKey() failed to create the ControlSet001 key (Status %lx)\n", Status); // return Status; } else { DPRINT("NtCreateKey() succeeded to %s the ControlSet001 key (Status %lx)\n", Disposition == REG_CREATED_NEW_KEY ? "create" : /* REG_OPENED_EXISTING_KEY */ "open", Status); } NtClose(KeyHandle);
/* Create the 'HKLM\SYSTEM\CurrentControlSet' symlink */ Status = CreateSymLinkKey(RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle, L"SYSTEM\\CurrentControlSet", REGISTRY_SETUP_MACHINE L"SYSTEM\\ControlSet001"); if (!NT_SUCCESS(Status)) { DPRINT1("CreateSymLinkKey(CurrentControlSet) failed, Status 0x%08lx\n", Status); }
Status = STATUS_SUCCESS;
Quit: /* Remove restore and backup privileges */ RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]); RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
return Status;}
VOIDRegCleanupRegistry( IN PUNICODE_STRING NtSystemRoot){ NTSTATUS Status; HANDLE KeyHandle; UNICODE_STRING KeyName; OBJECT_ATTRIBUTES ObjectAttributes; BOOLEAN PrivilegeSet[2] = {FALSE, FALSE}; UINT i; WCHAR SrcPath[MAX_PATH]; WCHAR DstPath[MAX_PATH];
/* Acquire restore privilege */ Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]); if (!NT_SUCCESS(Status)) { DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status); /* Exit prematurely here.... */ return; }
/* Acquire backup privilege */ Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]); if (!NT_SUCCESS(Status)) { DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status); RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]); /* Exit prematurely here.... */ return; }
/* * To keep the running system clean we need first to remove the symlinks * we have created and then unmounting the hives. Finally we delete the * master registry keys. */
for (i = 0; i < ARRAYSIZE(RegistryHives); ++i) { if (RegistryHives[i].State == Create || RegistryHives[i].State == Repair) { /* Delete the registry symlink to this key */ Status = DeleteSymLinkKey(RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle, RegistryHives[i].RegSymLink); if (!NT_SUCCESS(Status)) { DPRINT1("DeleteSymLinkKey(%S) failed, Status 0x%08lx\n", RegistryHives[i].RegSymLink, Status); }
/* Unmount the hive */ Status = DisconnectRegistry(NULL, RegistryHives[i].HiveRegistryPath, 1 /* REG_FORCE_UNLOAD */); if (!NT_SUCCESS(Status)) { DPRINT1("Unmounting '%S' failed\n", RegistryHives[i].HiveRegistryPath); }
/* Switch the hive state to 'Update' */ RegistryHives[i].State = Update; } else { /* Delete the *DUMMY* volatile hives created for the update procedure */
RtlInitUnicodeString(&KeyName, RegistryHives[i].RegSymLink); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle, NULL); KeyHandle = NULL; Status = NtOpenKey(&KeyHandle, DELETE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenKey(%wZ) failed, Status 0x%08lx\n", &KeyName, Status); // return; }
NtDeleteKey(KeyHandle); NtClose(KeyHandle); } }
/* * FIXME: Once force-unloading keys is correctly fixed, I'll fix * this code that closes some of the registry keys that were opened * inside the hives we've just unmounted above... */
/* Remove the registry root keys */ for (i = 0; i < ARRAYSIZE(RootKeys); ++i) { if (RootKeys[i].Handle) { /**/NtFlushKey(RootKeys[i].Handle);/**/ // FIXME: Why does it hang? Answer: because we have some problems in CMAPI! NtDeleteKey(RootKeys[i].Handle); NtClose(RootKeys[i].Handle); RootKeys[i].Handle = NULL; } }
// // RegBackupRegistry() // /* Now backup the hives into .sav files */ for (i = 0; i < ARRAYSIZE(RegistryHives); ++i) { if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair) continue;
CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 3, NtSystemRoot->Buffer, L"System32\\config", RegistryHives[i].HiveName); RtlStringCchCopyW(DstPath, ARRAYSIZE(DstPath), SrcPath); RtlStringCchCatW(DstPath, ARRAYSIZE(DstPath), L".sav");
DPRINT1("Copy hive: %S ==> %S\n", SrcPath, DstPath); Status = SetupCopyFile(SrcPath, DstPath, FALSE); if (!NT_SUCCESS(Status)) { DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status); // return Status; } }
/* Remove restore and backup privileges */ RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]); RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);}
/* EOF */