Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * PURPOSE: Rtl registry functions * FILE: lib/rtl/registry.c * PROGRAMER: Alex Ionescu (alex.ionescu@reactos.org) * Eric Kohl */
/* INCLUDES *****************************************************************/
#include <rtl.h>
#include <ndk/cmfuncs.h>
#define NDEBUG#include <debug.h>
#define TAG_RTLREGISTRY 'vrqR'
extern SIZE_T RtlpAllocDeallocQueryBufferSize;
/* DATA **********************************************************************/
PCWSTR RtlpRegPaths[RTL_REGISTRY_MAXIMUM] ={ NULL, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services", L"\\Registry\\Machine\\System\\CurrentControlSet\\Control", L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion", L"\\Registry\\Machine\\Hardware\\DeviceMap", L"\\Registry\\User\\.Default",};
/* PRIVATE FUNCTIONS *********************************************************/
NTSTATUSNTAPIRtlpQueryRegistryDirect(IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Buffer){ USHORT ActualLength; PUNICODE_STRING ReturnString = Buffer; PULONG Length = Buffer; ULONG RealLength;
/* Check if this is a string */ if ((ValueType == REG_SZ) || (ValueType == REG_EXPAND_SZ) || (ValueType == REG_MULTI_SZ)) { /* Normalize the length */ if (ValueLength > MAXUSHORT) ActualLength = MAXUSHORT; else ActualLength = (USHORT)ValueLength;
/* Check if the return string has been allocated */ if (!ReturnString->Buffer) { /* Allocate it */ ReturnString->Buffer = RtlpAllocateStringMemory(ActualLength, TAG_RTLREGISTRY); if (!ReturnString->Buffer) return STATUS_NO_MEMORY; ReturnString->MaximumLength = ActualLength; } else if (ActualLength > ReturnString->MaximumLength) { /* The string the caller allocated is too small */ return STATUS_BUFFER_TOO_SMALL; }
/* Copy the data */ RtlCopyMemory(ReturnString->Buffer, ValueData, ActualLength); ReturnString->Length = ActualLength - sizeof(UNICODE_NULL); } else if (ValueLength <= sizeof(ULONG)) { /* Check if we can just copy the data */ if ((Buffer != ValueData) && (ValueLength)) { /* Copy it */ RtlCopyMemory(Buffer, ValueData, ValueLength); } } else { /* Check if the length is negative */ if ((LONG)*Length < 0) { /* Get the real length and copy the buffer */ RealLength = -(LONG)*Length; if (RealLength < ValueLength) return STATUS_BUFFER_TOO_SMALL; RtlCopyMemory(Buffer, ValueData, ValueLength); } else { if (ValueType != REG_BINARY) { /* Check if there's space for the length and type, plus data */ if (*Length < (2 * sizeof(ULONG) + ValueLength)) { /* Nope, fail */ return STATUS_BUFFER_TOO_SMALL; }
/* Return the data */ *Length++ = ValueLength; *Length++ = ValueType; RtlCopyMemory(Length, ValueData, ValueLength); } else { /* Return the REG_BINARY data */ RtlCopyMemory(Length, ValueData, ValueLength); } } }
/* All done */ return STATUS_SUCCESS;}
NTSTATUSNTAPIRtlpCallQueryRegistryRoutine(IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PKEY_VALUE_FULL_INFORMATION KeyValueInfo, IN OUT PULONG InfoSize, IN PVOID Context, IN PVOID Environment){ ULONG InfoLength; SIZE_T Length, SpareLength, c; ULONG RequiredLength; PCHAR SpareData, DataEnd; ULONG Type; PWCHAR Name, p, ValueEnd; PVOID Data; NTSTATUS Status; BOOLEAN FoundExpander = FALSE; UNICODE_STRING Source, Destination;
/* Setup defaults */ InfoLength = *InfoSize; *InfoSize = 0;
/* Check if there's no data */ if (KeyValueInfo->DataOffset == MAXULONG) { /* Return proper status code */ return (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED) ? STATUS_OBJECT_NAME_NOT_FOUND : STATUS_SUCCESS; }
/* Setup spare data pointers */ SpareData = (PCHAR)KeyValueInfo; SpareLength = InfoLength; DataEnd = SpareData + SpareLength;
/* Check if there's no value or data */ if ((KeyValueInfo->Type == REG_NONE) || (!(KeyValueInfo->DataLength) && (KeyValueInfo->Type == QueryTable->DefaultType))) { /* Check if there's no value */ if (QueryTable->DefaultType == REG_NONE) { /* Return proper status code */ return (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED) ? STATUS_OBJECT_NAME_NOT_FOUND : STATUS_SUCCESS; }
/* We can setup a default value... capture the defaults */ Name = (PWCHAR)QueryTable->Name; Type = QueryTable->DefaultType; Data = QueryTable->DefaultData; Length = QueryTable->DefaultLength; if (!Length) { /* No default length given, try to calculate it */ p = Data; if ((Type == REG_SZ) || (Type == REG_EXPAND_SZ)) { /* This is a string, count the characters */ while (*p++); Length = (ULONG_PTR)p - (ULONG_PTR)Data; } else if (Type == REG_MULTI_SZ) { /* This is a multi-string, calculate all characters */ while (*p) while (*p++); Length = (ULONG_PTR)p - (ULONG_PTR)Data + sizeof(UNICODE_NULL); } } } else { /* Check if we have length */ if (KeyValueInfo->DataLength) { /* Increase the spare data */ SpareData += KeyValueInfo->DataOffset + KeyValueInfo->DataLength; } else { /* Otherwise, the spare data only has the name data */ SpareData += FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) + KeyValueInfo->NameLength; }
/* Align the pointer and get new size of spare data */ SpareData = (PVOID)(((ULONG_PTR)SpareData + 7) & ~7); SpareLength = DataEnd - SpareData;
/* Check if we have space to copy the data */ RequiredLength = KeyValueInfo->NameLength + sizeof(UNICODE_NULL); if ((SpareData > DataEnd) || (SpareLength < RequiredLength)) { /* Fail and return the missing length */ *InfoSize = (ULONG)(SpareData - (PCHAR)KeyValueInfo) + RequiredLength; return STATUS_BUFFER_TOO_SMALL; }
/* Check if this isn't a direct return */ if (!(QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)) { /* Copy the data and null-terminate it */ Name = (PWCHAR)SpareData; RtlCopyMemory(Name, KeyValueInfo->Name, KeyValueInfo->NameLength); Name[KeyValueInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
/* Update the spare data information */ SpareData += RequiredLength; SpareData = (PVOID)(((ULONG_PTR)SpareData + 7) & ~7); SpareLength = DataEnd - SpareData; } else { /* Just return the name */ Name = (PWCHAR)QueryTable->Name; }
/* Capture key data */ Type = KeyValueInfo->Type; Data = (PVOID)((ULONG_PTR)KeyValueInfo + KeyValueInfo->DataOffset); Length = KeyValueInfo->DataLength; }
/* Check if we're expanding */ if (!(QueryTable->Flags & RTL_QUERY_REGISTRY_NOEXPAND)) { /* Check if it's a multi-string */ if (Type == REG_MULTI_SZ) { /* Prepare defaults */ Status = STATUS_SUCCESS; /* Skip the last two UNICODE_NULL chars (the terminating null string) */ ValueEnd = (PWSTR)((ULONG_PTR)Data + Length - 2 * sizeof(UNICODE_NULL)); p = Data;
/* Loop all strings */ while (p < ValueEnd) { /* Go to the next string */ while (*p++);
/* Get the length and check if this is direct */ Length = (ULONG_PTR)p - (ULONG_PTR)Data; if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT) { /* Do the query */ Status = RtlpQueryRegistryDirect(REG_SZ, Data, (ULONG)Length, QueryTable->EntryContext); QueryTable->EntryContext = (PVOID)((ULONG_PTR)QueryTable->EntryContext + sizeof(UNICODE_STRING)); } else { /* Call the custom routine */ Status = QueryTable->QueryRoutine(Name, REG_SZ, Data, (ULONG)Length, Context, QueryTable->EntryContext); }
/* Normalize status */ if (Status == STATUS_BUFFER_TOO_SMALL) Status = STATUS_SUCCESS; if (!NT_SUCCESS(Status)) break;
/* Update data pointer */ Data = p; }
/* Return */ return Status; }
/* Check if this is an expand string */ if ((Type == REG_EXPAND_SZ) && (Length >= sizeof(WCHAR))) { /* Try to find the expander */ c = Length - sizeof(UNICODE_NULL); p = (PWCHAR)Data; while (c) { /* Check if this is one */ if (*p == L'%') { /* Yup! */ FoundExpander = TRUE; break; }
/* Continue in the buffer */ p++; c -= sizeof(WCHAR); }
/* So check if we have one */ if (FoundExpander) { /* Setup the source string */ RtlInitEmptyUnicodeString(&Source, Data, (USHORT)Length); Source.Length = Source.MaximumLength - sizeof(UNICODE_NULL);
/* Setup the destination string */ RtlInitEmptyUnicodeString(&Destination, (PWCHAR)SpareData, 0);
/* Check if we're out of space */ if (SpareLength <= 0) { /* Then we don't have any space in our string */ Destination.MaximumLength = 0; } else if (SpareLength <= MAXUSHORT) { /* This is the good case, where we fit into a string */ Destination.MaximumLength = (USHORT)SpareLength; Destination.Buffer[SpareLength / sizeof(WCHAR) - 1] = UNICODE_NULL; } else { /* We can't fit into a string, so truncate */ Destination.MaximumLength = MAXUSHORT; Destination.Buffer[MAXUSHORT / sizeof(WCHAR) - 1] = UNICODE_NULL; }
/* Expand the strings and set our type as one string */ Status = RtlExpandEnvironmentStrings_U(Environment, &Source, &Destination, &RequiredLength); Type = REG_SZ;
/* Check for success */ if (NT_SUCCESS(Status)) { /* Set the value name and length to our string */ Data = Destination.Buffer; Length = Destination.Length + sizeof(UNICODE_NULL); } else { /* Check if our buffer is too small */ if (Status == STATUS_BUFFER_TOO_SMALL) { /* Set the required missing length */ *InfoSize = (ULONG)(SpareData - (PCHAR)KeyValueInfo) + RequiredLength;
/* Notify debugger */ DPRINT1("RTL: Expand variables for %wZ failed - " "Status == %lx Size %x > %x <%x>\n", &Source, Status, *InfoSize, InfoLength, Destination.MaximumLength); } else { /* Notify debugger */ DPRINT1("RTL: Expand variables for %wZ failed - " "Status == %lx\n", &Source, Status); }
/* Return the status */ return Status; } } } }
/* Check if this is a direct query */ if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT) { /* Return the data */ Status = RtlpQueryRegistryDirect(Type, Data, (ULONG)Length, QueryTable->EntryContext); } else { /* Call the query routine */ Status = QueryTable->QueryRoutine(Name, Type, Data, (ULONG)Length, Context, QueryTable->EntryContext); }
/* Normalize and return status */ return (Status == STATUS_BUFFER_TOO_SMALL) ? STATUS_SUCCESS : Status;}
_Success_(return!=NULL || BufferSize==0)_When_(BufferSize!=NULL,__drv_allocatesMem(Mem))PVOIDNTAPIRtlpAllocDeallocQueryBuffer( _In_opt_ PSIZE_T BufferSize, _In_opt_ __drv_freesMem(Mem) PVOID OldBuffer, _In_ SIZE_T OldBufferSize, _Out_opt_ _On_failure_(_Post_satisfies_(*Status < 0)) PNTSTATUS Status){ PVOID Buffer = NULL;
/* Assume success */ if (Status) *Status = STATUS_SUCCESS;
/* Free the old buffer */ if (OldBuffer) RtlpFreeMemory(OldBuffer, TAG_RTLREGISTRY);
/* Check if we need to allocate a new one */ if (BufferSize) { /* Allocate */ Buffer = RtlpAllocateMemory(*BufferSize, TAG_RTLREGISTRY); if (!(Buffer) && (Status)) *Status = STATUS_NO_MEMORY; }
/* Return the pointer */ return Buffer;}
NTSTATUSNTAPIRtlpGetRegistryHandle(IN ULONG RelativeTo, IN PCWSTR Path, IN BOOLEAN Create, IN PHANDLE KeyHandle){ UNICODE_STRING KeyPath, KeyName; WCHAR KeyBuffer[MAX_PATH]; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status;
/* Check if we just want the handle */ if (RelativeTo & RTL_REGISTRY_HANDLE) { *KeyHandle = (HANDLE)Path; return STATUS_SUCCESS; }
/* Check for optional flag */ if (RelativeTo & RTL_REGISTRY_OPTIONAL) { /* Mask it out */ RelativeTo &= ~RTL_REGISTRY_OPTIONAL; }
/* Fail on invalid parameter */ if (RelativeTo >= RTL_REGISTRY_MAXIMUM) return STATUS_INVALID_PARAMETER;
/* Initialize the key name */ RtlInitEmptyUnicodeString(&KeyName, KeyBuffer, sizeof(KeyBuffer));
/* Check if we have to lookup a path to prefix */ if (RelativeTo != RTL_REGISTRY_ABSOLUTE) { /* Check if we need the current user key */ if (RelativeTo == RTL_REGISTRY_USER) { /* Get the user key path */ Status = RtlFormatCurrentUserKeyPath(&KeyPath);
/* Check if it worked */ if (NT_SUCCESS(Status)) { /* Append the user key path */ Status = RtlAppendUnicodeStringToString(&KeyName, &KeyPath);
/* Free the user key path */ RtlFreeUnicodeString (&KeyPath); } else { /* It didn't work so fall back to the default user key */ Status = RtlAppendUnicodeToString(&KeyName, RtlpRegPaths[RTL_REGISTRY_USER]); } } else { /* Get one of the prefixes */ Status = RtlAppendUnicodeToString(&KeyName, RtlpRegPaths[RelativeTo]); }
/* Check for failure, otherwise, append the path separator */ if (!NT_SUCCESS(Status)) return Status; Status = RtlAppendUnicodeToString(&KeyName, L"\\"); if (!NT_SUCCESS(Status)) return Status; }
if (Path != NULL) { /* And now append the path */ if (Path[0] == L'\\' && RelativeTo != RTL_REGISTRY_ABSOLUTE) Path++; // HACK! Status = RtlAppendUnicodeToString(&KeyName, Path); if (!NT_SUCCESS(Status)) return Status; }
/* Initialize the object attributes */ InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
/* Check if we want to create it */ if (Create) { /* Create the key with write privileges */ Status = ZwCreateKey(KeyHandle, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL); } else { /* Otherwise, just open it with read access */ Status = ZwOpenKey(KeyHandle, MAXIMUM_ALLOWED | GENERIC_READ, &ObjectAttributes); }
/* Return status */ return Status;}
FORCEINLINEVOIDRtlpCloseRegistryHandle( _In_ ULONG RelativeTo, _In_ HANDLE KeyHandle){ /* Did the caller pass a key handle? */ if (!(RelativeTo & RTL_REGISTRY_HANDLE)) { /* We opened the key in RtlpGetRegistryHandle, so close it now */ ZwClose(KeyHandle); }}
/* PUBLIC FUNCTIONS **********************************************************/
/* * @implemented */NTSTATUSNTAPIRtlCheckRegistryKey(IN ULONG RelativeTo, IN PWSTR Path){ HANDLE KeyHandle; NTSTATUS Status; PAGED_CODE_RTL();
/* Call the helper */ Status = RtlpGetRegistryHandle(RelativeTo, Path, FALSE, &KeyHandle); if (!NT_SUCCESS(Status)) return Status;
/* Close the handle even for RTL_REGISTRY_HANDLE */ ZwClose(KeyHandle); return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSNTAPIRtlCreateRegistryKey(IN ULONG RelativeTo, IN PWSTR Path){ HANDLE KeyHandle; NTSTATUS Status; PAGED_CODE_RTL();
/* Call the helper */ Status = RtlpGetRegistryHandle(RelativeTo, Path, TRUE, &KeyHandle); if (!NT_SUCCESS(Status)) return Status;
/* All went well, close the handle and return status */ RtlpCloseRegistryHandle(RelativeTo, KeyHandle); return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSNTAPIRtlDeleteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName){ HANDLE KeyHandle; NTSTATUS Status; UNICODE_STRING Name; PAGED_CODE_RTL();
/* Call the helper */ Status = RtlpGetRegistryHandle(RelativeTo, Path, TRUE, &KeyHandle); if (!NT_SUCCESS(Status)) return Status;
/* Initialize the key name and delete it */ RtlInitUnicodeString(&Name, ValueName); Status = ZwDeleteValueKey(KeyHandle, &Name);
/* Close the handle and return status */ RtlpCloseRegistryHandle(RelativeTo, KeyHandle); return Status;}
/* * @implemented */NTSTATUSNTAPIRtlWriteRegistryValue(IN ULONG RelativeTo, IN PCWSTR Path, IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength){ HANDLE KeyHandle; NTSTATUS Status; UNICODE_STRING Name; PAGED_CODE_RTL();
/* Call the helper */ Status = RtlpGetRegistryHandle(RelativeTo, Path, TRUE, &KeyHandle); if (!NT_SUCCESS(Status)) return Status;
/* Initialize the key name and set it */ RtlInitUnicodeString(&Name, ValueName); Status = ZwSetValueKey(KeyHandle, &Name, 0, ValueType, ValueData, ValueLength);
/* Close the handle and return status */ RtlpCloseRegistryHandle(RelativeTo, KeyHandle); return Status;}
/* * @implemented */NTSTATUSNTAPIRtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess, OUT PHANDLE KeyHandle){ OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING KeyPath; NTSTATUS Status; PAGED_CODE_RTL();
/* Get the user key */ Status = RtlFormatCurrentUserKeyPath(&KeyPath); if (NT_SUCCESS(Status)) { /* Initialize the attributes and open it */ InitializeObjectAttributes(&ObjectAttributes, &KeyPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
/* Free the path and return success if it worked */ RtlFreeUnicodeString(&KeyPath); if (NT_SUCCESS(Status)) return STATUS_SUCCESS; }
/* It didn't work, so use the default key */ RtlInitUnicodeString(&KeyPath, RtlpRegPaths[RTL_REGISTRY_USER]); InitializeObjectAttributes(&ObjectAttributes, &KeyPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
/* Return status */ return Status;}
/* * @implemented */NTSTATUSNTAPIRtlFormatCurrentUserKeyPath(OUT PUNICODE_STRING KeyPath){ HANDLE TokenHandle; UCHAR Buffer[256]; PSID_AND_ATTRIBUTES SidBuffer; ULONG Length; UNICODE_STRING SidString; NTSTATUS Status; PAGED_CODE_RTL();
/* Open the thread token */ Status = ZwOpenThreadTokenEx(NtCurrentThread(), TOKEN_QUERY, TRUE, OBJ_KERNEL_HANDLE, &TokenHandle); if (!NT_SUCCESS(Status)) { /* We failed, is it because we don't have a thread token? */ if (Status != STATUS_NO_TOKEN) return Status;
/* It is, so use the process token */ Status = ZwOpenProcessTokenEx(NtCurrentProcess(), TOKEN_QUERY, OBJ_KERNEL_HANDLE, &TokenHandle); if (!NT_SUCCESS(Status)) return Status; }
/* Now query the token information */ SidBuffer = (PSID_AND_ATTRIBUTES)Buffer; Status = ZwQueryInformationToken(TokenHandle, TokenUser, (PVOID)SidBuffer, sizeof(Buffer), &Length);
/* Close the handle and handle failure */ ZwClose(TokenHandle); if (!NT_SUCCESS(Status)) return Status;
/* Convert the SID */ Status = RtlConvertSidToUnicodeString(&SidString, SidBuffer[0].Sid, TRUE); if (!NT_SUCCESS(Status)) return Status;
/* Add the length of the prefix */ Length = SidString.Length + sizeof(L"\\REGISTRY\\USER\\");
/* Initialize a string */ RtlInitEmptyUnicodeString(KeyPath, RtlpAllocateStringMemory(Length, TAG_USTR), (USHORT)Length); if (!KeyPath->Buffer) { /* Free the string and fail */ RtlFreeUnicodeString(&SidString); return STATUS_NO_MEMORY; }
/* Append the prefix and SID */ RtlAppendUnicodeToString(KeyPath, L"\\REGISTRY\\USER\\"); RtlAppendUnicodeStringToString(KeyPath, &SidString);
/* Free the temporary string and return success */ RtlFreeUnicodeString(&SidString); return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSNTAPIRtlpNtCreateKey(OUT HANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG TitleIndex, IN PUNICODE_STRING Class, OUT PULONG Disposition){ /* Check if we have object attributes */ if (ObjectAttributes) { /* Mask out the unsupported flags */ ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE); }
/* Create the key */ return ZwCreateKey(KeyHandle, DesiredAccess, ObjectAttributes, 0, NULL, 0, Disposition);}
/* * @implemented */NTSTATUSNTAPIRtlpNtEnumerateSubKey(IN HANDLE KeyHandle, OUT PUNICODE_STRING SubKeyName, IN ULONG Index, IN ULONG Unused){ PKEY_BASIC_INFORMATION KeyInfo = NULL; ULONG BufferLength = 0; ULONG ReturnedLength; NTSTATUS Status;
/* Check if we have a name */ if (SubKeyName->MaximumLength) { /* Allocate a buffer for it */ BufferLength = SubKeyName->MaximumLength + sizeof(KEY_BASIC_INFORMATION); KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); if (!KeyInfo) return STATUS_NO_MEMORY; }
/* Enumerate the key */ Status = ZwEnumerateKey(KeyHandle, Index, KeyBasicInformation, KeyInfo, BufferLength, &ReturnedLength); if (NT_SUCCESS(Status) && (KeyInfo != NULL)) { /* Check if the name fits */ if (KeyInfo->NameLength <= SubKeyName->MaximumLength) { /* Set the length */ SubKeyName->Length = (USHORT)KeyInfo->NameLength;
/* Copy it */ RtlMoveMemory(SubKeyName->Buffer, KeyInfo->Name, SubKeyName->Length); } else { /* Otherwise, we ran out of buffer space */ Status = STATUS_BUFFER_OVERFLOW; } }
/* Free the buffer and return status */ if (KeyInfo) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo); return Status;}
/* * @implemented */NTSTATUSNTAPIRtlpNtMakeTemporaryKey(IN HANDLE KeyHandle){ /* This just deletes the key */ return ZwDeleteKey(KeyHandle);}
/* * @implemented */NTSTATUSNTAPIRtlpNtOpenKey(OUT HANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG Unused){ /* Check if we have object attributes */ if (ObjectAttributes) { /* Mask out the unsupported flags */ ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE); }
/* Open the key */ return ZwOpenKey(KeyHandle, DesiredAccess, ObjectAttributes);}
/* * @implemented */NTSTATUSNTAPIRtlpNtQueryValueKey(IN HANDLE KeyHandle, OUT PULONG Type OPTIONAL, OUT PVOID Data OPTIONAL, IN OUT PULONG DataLength OPTIONAL, IN ULONG Unused){ PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; UNICODE_STRING ValueName; ULONG BufferLength = 0; NTSTATUS Status;
/* Clear the value name */ RtlInitEmptyUnicodeString(&ValueName, NULL, 0);
/* Check if we were already given a length */ if (DataLength) BufferLength = *DataLength;
/* Add the size of the structure */ BufferLength += FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
/* Allocate memory for the value */ ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); if (!ValueInfo) return STATUS_NO_MEMORY;
/* Query the value */ Status = ZwQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, ValueInfo, BufferLength, &BufferLength); if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW)) { /* Return the length and type */ if (DataLength) *DataLength = ValueInfo->DataLength; if (Type) *Type = ValueInfo->Type; }
/* Check if the caller wanted data back, and we got it */ if ((NT_SUCCESS(Status)) && (Data)) { /* Copy it */ RtlMoveMemory(Data, ValueInfo->Data, ValueInfo->DataLength); }
/* Free the memory and return status */ RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo); return Status;}
/* * @implemented */NTSTATUSNTAPIRtlpNtSetValueKey(IN HANDLE KeyHandle, IN ULONG Type, IN PVOID Data, IN ULONG DataLength){ UNICODE_STRING ValueName;
/* Set the value */ RtlInitEmptyUnicodeString(&ValueName, NULL, 0); return ZwSetValueKey(KeyHandle, &ValueName, 0, Type, Data, DataLength);}
/* * @implemented */NTSTATUSNTAPIRtlQueryRegistryValues(IN ULONG RelativeTo, IN PCWSTR Path, IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context, IN PVOID Environment OPTIONAL){ NTSTATUS Status; PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL; HANDLE KeyHandle, CurrentKey; SIZE_T BufferSize, InfoSize; UNICODE_STRING KeyPath, KeyValueName; OBJECT_ATTRIBUTES ObjectAttributes; ULONG i, Value; ULONG ResultLength;
/* Get the registry handle */ Status = RtlpGetRegistryHandle(RelativeTo, Path, FALSE, &KeyHandle); if (!NT_SUCCESS(Status)) return Status;
/* Initialize the path */ RtlInitUnicodeString(&KeyPath, (RelativeTo & RTL_REGISTRY_HANDLE) ? NULL : Path);
/* Allocate a query buffer */ BufferSize = RtlpAllocDeallocQueryBufferSize; KeyValueInfo = RtlpAllocDeallocQueryBuffer(&BufferSize, NULL, 0, &Status); if (!KeyValueInfo) { /* Close the handle if we have one and fail */ RtlpCloseRegistryHandle(RelativeTo, KeyHandle); return Status; }
/* Set defaults */ KeyValueInfo->DataOffset = 0; InfoSize = BufferSize - sizeof(UNICODE_NULL); CurrentKey = KeyHandle;
/* Loop the query table */ while ((QueryTable->QueryRoutine) || (QueryTable->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_DIRECT))) { /* Check if the request is invalid */ if ((QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT) && (!(QueryTable->Name) || (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY) || (QueryTable->QueryRoutine))) { /* Fail */ Status = STATUS_INVALID_PARAMETER; break; }
/* Check if we want a specific key */ if (QueryTable->Flags & (RTL_QUERY_REGISTRY_TOPKEY | RTL_QUERY_REGISTRY_SUBKEY)) { /* Check if we're working with another handle */ if (CurrentKey != KeyHandle) { /* Close our current key and use the top */ NtClose(CurrentKey); CurrentKey = KeyHandle; } }
/* Check if we're querying the subkey */ if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY) { /* Make sure we have a name */ if (!QueryTable->Name) { /* Fail */ Status = STATUS_INVALID_PARAMETER; } else { /* Initialize the name */ RtlInitUnicodeString(&KeyPath, QueryTable->Name);
/* Get the key handle */ InitializeObjectAttributes(&ObjectAttributes, &KeyPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, KeyHandle, NULL); Status = ZwOpenKey(&CurrentKey, MAXIMUM_ALLOWED, &ObjectAttributes); if (NT_SUCCESS(Status)) { /* If we have a query routine, go enumerate values */ if (QueryTable->QueryRoutine) goto ProcessValues; } } } else if (QueryTable->Name) { /* Initialize the path */ RtlInitUnicodeString(&KeyValueName, QueryTable->Name);
/* Start query loop */ i = 0; while (TRUE) { /* Make sure we didn't retry too many times */ if (i++ > 4) { /* Fail */ DPRINT1("RtlQueryRegistryValues: Miscomputed buffer size " "at line %d\n", __LINE__); break; }
/* Query key information */ Status = ZwQueryValueKey(CurrentKey, &KeyValueName, KeyValueFullInformation, KeyValueInfo, (ULONG)InfoSize, &ResultLength); if (Status == STATUS_BUFFER_OVERFLOW) { /* Normalize status code */ Status = STATUS_BUFFER_TOO_SMALL; }
/* Check for failure */ if (!NT_SUCCESS(Status)) { /* Check if we didn't find it */ if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { /* Setup a default */ KeyValueInfo->Type = REG_NONE; KeyValueInfo->DataLength = 0; ResultLength = (ULONG)InfoSize;
/* Call the query routine */ Status = RtlpCallQueryRegistryRoutine(QueryTable, KeyValueInfo, &ResultLength, Context, Environment); }
/* Check for buffer being too small */ if (Status == STATUS_BUFFER_TOO_SMALL) { /* Increase allocation size */ BufferSize = ResultLength + sizeof(ULONG_PTR) + sizeof(UNICODE_NULL); KeyValueInfo = RtlpAllocDeallocQueryBuffer(&BufferSize, KeyValueInfo, BufferSize, &Status); if (!KeyValueInfo) break;
/* Update the data */ KeyValueInfo->DataOffset = 0; InfoSize = BufferSize - sizeof(UNICODE_NULL); continue; } } else { /* Check if this is a multi-string */ if (KeyValueInfo->Type == REG_MULTI_SZ) { /* Add a null-char */ ((PWCHAR)KeyValueInfo)[ResultLength / sizeof(WCHAR)] = UNICODE_NULL; KeyValueInfo->DataLength += sizeof(UNICODE_NULL); }
/* Call the query routine */ ResultLength = (ULONG)InfoSize; Status = RtlpCallQueryRegistryRoutine(QueryTable, KeyValueInfo, &ResultLength, Context, Environment);
/* Check for buffer being too small */ if (Status == STATUS_BUFFER_TOO_SMALL) { /* Increase allocation size */ BufferSize = ResultLength + sizeof(ULONG_PTR) + sizeof(UNICODE_NULL); KeyValueInfo = RtlpAllocDeallocQueryBuffer(&BufferSize, KeyValueInfo, BufferSize, &Status); if (!KeyValueInfo) break;
/* Update the data */ KeyValueInfo->DataOffset = 0; InfoSize = BufferSize - sizeof(UNICODE_NULL); continue; }
/* Check if we need to delete the key */ if ((NT_SUCCESS(Status)) && (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)) { /* Delete it */ ZwDeleteValueKey(CurrentKey, &KeyValueName); } }
/* We're done, break out */ break; } } else if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE) { /* Just call the query routine */ Status = QueryTable->QueryRoutine(NULL, REG_NONE, NULL, 0, Context, QueryTable->EntryContext); } else {ProcessValues: /* Loop every value */ i = Value = 0; while (TRUE) { /* Enumerate the keys */ Status = ZwEnumerateValueKey(CurrentKey, Value, KeyValueFullInformation, KeyValueInfo, (ULONG)InfoSize, &ResultLength); if (Status == STATUS_BUFFER_OVERFLOW) { /* Normalize the status */ Status = STATUS_BUFFER_TOO_SMALL; }
/* Check if we found all the entries */ if (Status == STATUS_NO_MORE_ENTRIES) { /* Check if this was the first entry and caller needs it */ if (!(Value) && (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)) { /* Fail */ Status = STATUS_OBJECT_NAME_NOT_FOUND; } else { /* Otherwise, it's ok */ Status = STATUS_SUCCESS; } break; }
/* Check if enumeration worked */ if (NT_SUCCESS(Status)) { /* Call the query routine */ ResultLength = (ULONG)InfoSize; Status = RtlpCallQueryRegistryRoutine(QueryTable, KeyValueInfo, &ResultLength, Context, Environment); }
/* Check if the query failed */ if (Status == STATUS_BUFFER_TOO_SMALL) { /* Increase allocation size */ BufferSize = ResultLength + sizeof(ULONG_PTR) + sizeof(UNICODE_NULL); KeyValueInfo = RtlpAllocDeallocQueryBuffer(&BufferSize, KeyValueInfo, BufferSize, &Status); if (!KeyValueInfo) break;
/* Update the data */ KeyValueInfo->DataOffset = 0; InfoSize = BufferSize - sizeof(UNICODE_NULL);
/* Try the value again unless it's been too many times */ if (i++ <= 4) continue; break; }
/* Break out if we failed */ if (!NT_SUCCESS(Status)) break;
/* Reset the number of retries and check if we need to delete */ i = 0; if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE) { /* Build the name */ RtlInitEmptyUnicodeString(&KeyValueName, KeyValueInfo->Name, (USHORT)KeyValueInfo->NameLength); KeyValueName.Length = KeyValueName.MaximumLength;
/* Delete the key */ Status = ZwDeleteValueKey(CurrentKey, &KeyValueName); if (NT_SUCCESS(Status)) Value--; }
/* Go to the next value */ Value++; } }
/* Check if we failed anywhere along the road */ if (!NT_SUCCESS(Status)) break;
/* Continue */ QueryTable++; }
/* Check if we need to close our handle */ if (KeyHandle) RtlpCloseRegistryHandle(RelativeTo, KeyHandle); if ((CurrentKey) && (CurrentKey != KeyHandle)) ZwClose(CurrentKey);
/* Free our buffer and return status */ RtlpAllocDeallocQueryBuffer(NULL, KeyValueInfo, BufferSize, NULL); return Status;}
/* EOF */