Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenregistry.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS system libraries 00004 * PURPOSE: Rtl registry functions 00005 * FILE: lib/rtl/registry.c 00006 * PROGRAMER: Alex Ionescu (alex.ionescu@reactos.org) 00007 * Eric Kohl 00008 */ 00009 00010 /* INCLUDES *****************************************************************/ 00011 00012 #include <rtl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 #define TAG_RTLREGISTRY 'vrqR' 00017 00018 extern SIZE_T RtlpAllocDeallocQueryBufferSize; 00019 00020 /* DATA **********************************************************************/ 00021 00022 PCWSTR RtlpRegPaths[RTL_REGISTRY_MAXIMUM] = 00023 { 00024 NULL, 00025 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services", 00026 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control", 00027 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion", 00028 L"\\Registry\\Machine\\Hardware\\DeviceMap", 00029 L"\\Registry\\User\\.Default", 00030 }; 00031 00032 /* PRIVATE FUNCTIONS *********************************************************/ 00033 00034 NTSTATUS 00035 NTAPI 00036 RtlpQueryRegistryDirect(IN ULONG ValueType, 00037 IN PVOID ValueData, 00038 IN ULONG ValueLength, 00039 IN PVOID Buffer) 00040 { 00041 USHORT ActualLength = (USHORT)ValueLength; 00042 PUNICODE_STRING ReturnString = Buffer; 00043 PULONG Length = Buffer; 00044 ULONG RealLength; 00045 00046 /* Check if this is a string */ 00047 if ((ValueType == REG_SZ) || 00048 (ValueType == REG_EXPAND_SZ) || 00049 (ValueType == REG_MULTI_SZ)) 00050 { 00051 /* Normalize the length */ 00052 if (ValueLength > MAXUSHORT) ValueLength = MAXUSHORT; 00053 00054 /* Check if the return string has been allocated */ 00055 if (!ReturnString->Buffer) 00056 { 00057 /* Allocate it */ 00058 ReturnString->Buffer = RtlpAllocateMemory(ActualLength, TAG_RTLREGISTRY); 00059 if (!ReturnString->Buffer) return STATUS_NO_MEMORY; 00060 ReturnString->MaximumLength = ActualLength; 00061 } 00062 else if (ActualLength > ReturnString->MaximumLength) 00063 { 00064 /* The string the caller allocated is too small */ 00065 return STATUS_BUFFER_TOO_SMALL; 00066 } 00067 00068 /* Copy the data */ 00069 RtlCopyMemory(ReturnString->Buffer, ValueData, ActualLength); 00070 ReturnString->Length = ActualLength - sizeof(UNICODE_NULL); 00071 } 00072 else if (ValueLength <= sizeof(ULONG)) 00073 { 00074 /* Check if we can just copy the data */ 00075 if ((Buffer != ValueData) && (ValueLength)) 00076 { 00077 /* Copy it */ 00078 RtlCopyMemory(Buffer, ValueData, ValueLength); 00079 } 00080 } 00081 else 00082 { 00083 /* Check if the length is negative */ 00084 if ((LONG)*Length < 0) 00085 { 00086 /* Get the real length and copy the buffer */ 00087 RealLength = -(LONG)*Length; 00088 if (RealLength < ValueLength) return STATUS_BUFFER_TOO_SMALL; 00089 RtlCopyMemory(Buffer, ValueData, ValueLength); 00090 } 00091 else 00092 { 00093 /* Check if there's space for the length and type, plus data */ 00094 if (*Length < (2 * sizeof(ULONG) + ValueLength)) 00095 { 00096 /* Nope, fail */ 00097 return STATUS_BUFFER_TOO_SMALL; 00098 } 00099 00100 /* Return the data */ 00101 *Length++ = ValueLength; 00102 *Length++ = ValueType; 00103 RtlCopyMemory(Length, ValueData, ValueLength); 00104 } 00105 } 00106 00107 /* All done */ 00108 return STATUS_SUCCESS; 00109 } 00110 00111 NTSTATUS 00112 NTAPI 00113 RtlpCallQueryRegistryRoutine(IN PRTL_QUERY_REGISTRY_TABLE QueryTable, 00114 IN PKEY_VALUE_FULL_INFORMATION KeyValueInfo, 00115 IN OUT PULONG InfoSize, 00116 IN PVOID Context, 00117 IN PVOID Environment) 00118 { 00119 ULONG InfoLength; 00120 SIZE_T Length, SpareLength, c; 00121 ULONG RequiredLength; 00122 PCHAR SpareData, DataEnd; 00123 ULONG Type; 00124 PWCHAR Name, p, ValueEnd; 00125 PVOID Data; 00126 NTSTATUS Status; 00127 BOOLEAN FoundExpander = FALSE; 00128 UNICODE_STRING Source, Destination; 00129 00130 /* Setup defaults */ 00131 InfoLength = *InfoSize; 00132 *InfoSize = 0; 00133 00134 /* Check if there's no data */ 00135 if (KeyValueInfo->DataOffset == MAXULONG) 00136 { 00137 /* Return proper status code */ 00138 return (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED) ? 00139 STATUS_OBJECT_NAME_NOT_FOUND : STATUS_SUCCESS; 00140 } 00141 00142 /* Setup spare data pointers */ 00143 SpareData = (PCHAR)KeyValueInfo; 00144 SpareLength = InfoLength; 00145 DataEnd = SpareData + SpareLength; 00146 00147 /* Check if there's no value or data */ 00148 if ((KeyValueInfo->Type == REG_NONE) || 00149 (!(KeyValueInfo->DataLength) && 00150 (KeyValueInfo->Type == QueryTable->DefaultType))) 00151 { 00152 /* Check if there's no value */ 00153 if (QueryTable->DefaultType == REG_NONE) 00154 { 00155 /* Return proper status code */ 00156 return (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED) ? 00157 STATUS_OBJECT_NAME_NOT_FOUND : STATUS_SUCCESS; 00158 } 00159 00160 /* We can setup a default value... capture the defaults */ 00161 Name = (PWCHAR)QueryTable->Name; 00162 Type = QueryTable->DefaultType; 00163 Data = QueryTable->DefaultData; 00164 Length = QueryTable->DefaultLength; 00165 if (!Length) 00166 { 00167 /* No default length given, try to calculate it */ 00168 p = Data; 00169 if ((Type == REG_SZ) || (Type == REG_EXPAND_SZ)) 00170 { 00171 /* This is a string, count the characters */ 00172 while (*p++); 00173 Length = (ULONG_PTR)p - (ULONG_PTR)Data; 00174 } 00175 else if (Type == REG_MULTI_SZ) 00176 { 00177 /* This is a multi-string, calculate all characters */ 00178 while (*p) while (*p++); 00179 Length = (ULONG_PTR)p - (ULONG_PTR)Data + sizeof(UNICODE_NULL); 00180 } 00181 } 00182 } 00183 else 00184 { 00185 /* Check if this isn't a direct return */ 00186 if (!(QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT)) 00187 { 00188 /* Check if we have length */ 00189 if (KeyValueInfo->DataLength) 00190 { 00191 /* Increase the spare data */ 00192 SpareData += KeyValueInfo->DataOffset + 00193 KeyValueInfo->DataLength; 00194 } 00195 else 00196 { 00197 /* Otherwise, the spare data only has the name data */ 00198 SpareData += FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) + 00199 KeyValueInfo->NameLength; 00200 } 00201 00202 /* Align the pointer and get new size of spare data */ 00203 SpareData = (PVOID)(((ULONG_PTR)SpareData + 7) & ~7); 00204 SpareLength = DataEnd - SpareData; 00205 00206 /* Check if we have space to copy the data */ 00207 RequiredLength = KeyValueInfo->NameLength + sizeof(UNICODE_NULL); 00208 if (SpareLength < RequiredLength) 00209 { 00210 /* Fail and return the missing length */ 00211 *InfoSize = (ULONG)(SpareData - (PCHAR)KeyValueInfo) + RequiredLength; 00212 return STATUS_BUFFER_TOO_SMALL; 00213 } 00214 00215 /* Copy the data and null-terminate it */ 00216 Name = (PWCHAR)SpareData; 00217 RtlCopyMemory(Name, KeyValueInfo->Name, KeyValueInfo->NameLength); 00218 Name[KeyValueInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL; 00219 00220 /* Update the spare data information */ 00221 SpareData += RequiredLength; 00222 SpareData = (PVOID)(((ULONG_PTR)SpareData + 7) & ~7); 00223 SpareLength = DataEnd - SpareData; 00224 } 00225 else 00226 { 00227 /* Just return the name */ 00228 Name = (PWCHAR)QueryTable->Name; 00229 } 00230 00231 /* Capture key data */ 00232 Type = KeyValueInfo->Type; 00233 Data = (PVOID)((ULONG_PTR)KeyValueInfo + KeyValueInfo->DataOffset); 00234 Length = KeyValueInfo->DataLength; 00235 } 00236 00237 /* Check if we're expanding */ 00238 if (!(QueryTable->Flags & RTL_QUERY_REGISTRY_NOEXPAND)) 00239 { 00240 /* Check if it's a multi-string */ 00241 if (Type == REG_MULTI_SZ) 00242 { 00243 /* Prepare defaults */ 00244 Status = STATUS_SUCCESS; 00245 ValueEnd = (PWSTR)((ULONG_PTR)Data + Length) - sizeof(UNICODE_NULL); 00246 p = Data; 00247 00248 /* Loop all strings */ 00249 while (p < ValueEnd) 00250 { 00251 /* Go to the next string */ 00252 while (*p++); 00253 00254 /* Get the length and check if this is direct */ 00255 Length = (ULONG_PTR)p - (ULONG_PTR)Data; 00256 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT) 00257 { 00258 /* Do the query */ 00259 Status = RtlpQueryRegistryDirect(REG_SZ, 00260 Data, 00261 (ULONG)Length, 00262 QueryTable->EntryContext); 00263 QueryTable->EntryContext = (PVOID)((ULONG_PTR)QueryTable-> 00264 EntryContext + 00265 sizeof(UNICODE_STRING)); 00266 } 00267 else 00268 { 00269 /* Call the custom routine */ 00270 Status = QueryTable->QueryRoutine(Name, 00271 REG_SZ, 00272 Data, 00273 (ULONG)Length, 00274 Context, 00275 QueryTable->EntryContext); 00276 } 00277 00278 /* Normalize status */ 00279 if (Status == STATUS_BUFFER_TOO_SMALL) Status = STATUS_SUCCESS; 00280 if (!NT_SUCCESS(Status)) break; 00281 00282 /* Update data pointer */ 00283 Data = p; 00284 } 00285 00286 /* Return */ 00287 return Status; 00288 } 00289 00290 /* Check if this is an expand string */ 00291 if ((Type == REG_EXPAND_SZ) && (Length >= sizeof(WCHAR))) 00292 { 00293 /* Try to find the expander */ 00294 c = Length - sizeof(UNICODE_NULL); 00295 p = (PWCHAR)Data; 00296 while (c) 00297 { 00298 /* Check if this is one */ 00299 if (*p == L'%') 00300 { 00301 /* Yup! */ 00302 FoundExpander = TRUE; 00303 break; 00304 } 00305 00306 /* Continue in the buffer */ 00307 p++; 00308 c -= sizeof(WCHAR); 00309 } 00310 00311 /* So check if we have one */ 00312 if (FoundExpander) 00313 { 00314 /* Setup the source string */ 00315 RtlInitEmptyUnicodeString(&Source, Data, (USHORT)Length); 00316 Source.Length = Source.MaximumLength - sizeof(UNICODE_NULL); 00317 00318 /* Setup the desination string */ 00319 RtlInitEmptyUnicodeString(&Destination, (PWCHAR)SpareData, 0); 00320 00321 /* Check if we're out of space */ 00322 if (SpareLength <= 0) 00323 { 00324 /* Then we don't have any space in our string */ 00325 Destination.MaximumLength = 0; 00326 } 00327 else if (SpareLength <= MAXUSHORT) 00328 { 00329 /* This is the good case, where we fit into a string */ 00330 Destination.MaximumLength = (USHORT)SpareLength; 00331 Destination.Buffer[SpareLength / 2 - 1] = UNICODE_NULL; 00332 } 00333 else 00334 { 00335 /* We can't fit into a string, so truncate */ 00336 Destination.MaximumLength = MAXUSHORT; 00337 Destination.Buffer[MAXUSHORT / 2 - 1] = UNICODE_NULL; 00338 } 00339 00340 /* Expand the strings and set our type as one string */ 00341 Status = RtlExpandEnvironmentStrings_U(Environment, 00342 &Source, 00343 &Destination, 00344 &RequiredLength); 00345 Type = REG_SZ; 00346 00347 /* Check for success */ 00348 if (NT_SUCCESS(Status)) 00349 { 00350 /* Set the value name and length to our string */ 00351 Data = Destination.Buffer; 00352 Length = Destination.Length + sizeof(UNICODE_NULL); 00353 } 00354 else 00355 { 00356 /* Check if our buffer is too small */ 00357 if (Status == STATUS_BUFFER_TOO_SMALL) 00358 { 00359 /* Set the required missing length */ 00360 *InfoSize = (ULONG)(SpareData - (PCHAR)KeyValueInfo) + 00361 RequiredLength; 00362 00363 /* Notify debugger */ 00364 DPRINT1("RTL: Expand variables for %wZ failed - " 00365 "Status == %lx Size %x > %x <%x>\n", 00366 &Source, 00367 Status, 00368 *InfoSize, 00369 InfoLength, 00370 Destination.MaximumLength); 00371 } 00372 else 00373 { 00374 /* Notify debugger */ 00375 DPRINT1("RTL: Expand variables for %wZ failed - " 00376 "Status == %lx\n", 00377 &Source, 00378 Status); 00379 } 00380 00381 /* Return the status */ 00382 return Status; 00383 } 00384 } 00385 } 00386 } 00387 00388 /* Check if this is a direct query */ 00389 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT) 00390 { 00391 /* Return the data */ 00392 Status = RtlpQueryRegistryDirect(Type, 00393 Data, 00394 (ULONG)Length, 00395 QueryTable->EntryContext); 00396 } 00397 else 00398 { 00399 /* Call the query routine */ 00400 Status = QueryTable->QueryRoutine(Name, 00401 Type, 00402 Data, 00403 (ULONG)Length, 00404 Context, 00405 QueryTable->EntryContext); 00406 } 00407 00408 /* Normalize and return status */ 00409 return (Status == STATUS_BUFFER_TOO_SMALL) ? STATUS_SUCCESS : Status; 00410 } 00411 00412 PVOID 00413 NTAPI 00414 RtlpAllocDeallocQueryBuffer(IN OUT PSIZE_T BufferSize, 00415 IN PVOID OldBuffer, 00416 IN SIZE_T OldBufferSize, 00417 OUT PNTSTATUS Status) 00418 { 00419 PVOID Buffer = NULL; 00420 00421 /* Assume success */ 00422 if (Status) *Status = STATUS_SUCCESS; 00423 00424 /* Free the old buffer */ 00425 if (OldBuffer) RtlpFreeMemory(OldBuffer, TAG_RTLREGISTRY); 00426 00427 /* Check if we need to allocate a new one */ 00428 if (BufferSize) 00429 { 00430 /* Allocate */ 00431 Buffer = RtlpAllocateMemory(*BufferSize, TAG_RTLREGISTRY); 00432 if (!(Buffer) && (Status)) *Status = STATUS_NO_MEMORY; 00433 } 00434 00435 /* Return the pointer */ 00436 return Buffer; 00437 } 00438 00439 NTSTATUS 00440 NTAPI 00441 RtlpGetRegistryHandle(IN ULONG RelativeTo, 00442 IN PCWSTR Path, 00443 IN BOOLEAN Create, 00444 IN PHANDLE KeyHandle) 00445 { 00446 UNICODE_STRING KeyPath, KeyName; 00447 WCHAR KeyBuffer[MAX_PATH]; 00448 OBJECT_ATTRIBUTES ObjectAttributes; 00449 NTSTATUS Status; 00450 00451 /* Check if we just want the handle */ 00452 if (RelativeTo & RTL_REGISTRY_HANDLE) 00453 { 00454 *KeyHandle = (HANDLE)Path; 00455 return STATUS_SUCCESS; 00456 } 00457 00458 /* Check for optional flag */ 00459 if (RelativeTo & RTL_REGISTRY_OPTIONAL) 00460 { 00461 /* Mask it out */ 00462 RelativeTo &= ~RTL_REGISTRY_OPTIONAL; 00463 } 00464 00465 /* Fail on invalid parameter */ 00466 if (RelativeTo >= RTL_REGISTRY_MAXIMUM) return STATUS_INVALID_PARAMETER; 00467 00468 /* Initialize the key name */ 00469 RtlInitEmptyUnicodeString(&KeyName, KeyBuffer, sizeof(KeyBuffer)); 00470 00471 /* Check if we have to lookup a path to prefix */ 00472 if (RelativeTo != RTL_REGISTRY_ABSOLUTE) 00473 { 00474 /* Check if we need the current user key */ 00475 if (RelativeTo == RTL_REGISTRY_USER) 00476 { 00477 /* Get the user key path */ 00478 Status = RtlFormatCurrentUserKeyPath(&KeyPath); 00479 00480 /* Check if it worked */ 00481 if (NT_SUCCESS(Status)) 00482 { 00483 /* Append the user key path */ 00484 Status = RtlAppendUnicodeStringToString(&KeyName, &KeyPath); 00485 00486 /* Free the user key path */ 00487 RtlFreeUnicodeString (&KeyPath); 00488 } 00489 else 00490 { 00491 /* It didn't work so fall back to the default user key */ 00492 Status = RtlAppendUnicodeToString(&KeyName, RtlpRegPaths[RTL_REGISTRY_USER]); 00493 } 00494 } 00495 else 00496 { 00497 /* Get one of the prefixes */ 00498 Status = RtlAppendUnicodeToString(&KeyName, 00499 RtlpRegPaths[RelativeTo]); 00500 } 00501 00502 /* Check for failure, otherwise, append the path separator */ 00503 if (!NT_SUCCESS(Status)) return Status; 00504 Status = RtlAppendUnicodeToString(&KeyName, L"\\"); 00505 if (!NT_SUCCESS(Status)) return Status; 00506 } 00507 00508 /* And now append the path */ 00509 if (Path[0] == L'\\' && RelativeTo != RTL_REGISTRY_ABSOLUTE) Path++; // HACK! 00510 Status = RtlAppendUnicodeToString(&KeyName, Path); 00511 if (!NT_SUCCESS(Status)) return Status; 00512 00513 /* Initialize the object attributes */ 00514 InitializeObjectAttributes(&ObjectAttributes, 00515 &KeyName, 00516 OBJ_CASE_INSENSITIVE, 00517 NULL, 00518 NULL); 00519 00520 /* Check if we want to create it */ 00521 if (Create) 00522 { 00523 /* Create the key with write privileges */ 00524 Status = ZwCreateKey(KeyHandle, 00525 GENERIC_WRITE, 00526 &ObjectAttributes, 00527 0, 00528 NULL, 00529 0, 00530 NULL); 00531 } 00532 else 00533 { 00534 /* Otherwise, just open it with read access */ 00535 Status = ZwOpenKey(KeyHandle, 00536 MAXIMUM_ALLOWED | GENERIC_READ, 00537 &ObjectAttributes); 00538 } 00539 00540 /* Return status */ 00541 return Status; 00542 } 00543 00544 /* PUBLIC FUNCTIONS **********************************************************/ 00545 00546 /* 00547 * @implemented 00548 */ 00549 NTSTATUS 00550 NTAPI 00551 RtlCheckRegistryKey(IN ULONG RelativeTo, 00552 IN PWSTR Path) 00553 { 00554 HANDLE KeyHandle; 00555 NTSTATUS Status; 00556 PAGED_CODE_RTL(); 00557 00558 /* Call the helper */ 00559 Status = RtlpGetRegistryHandle(RelativeTo, 00560 Path, 00561 FALSE, 00562 &KeyHandle); 00563 if (!NT_SUCCESS(Status)) return Status; 00564 00565 /* All went well, close the handle and return success */ 00566 ZwClose(KeyHandle); 00567 return STATUS_SUCCESS; 00568 } 00569 00570 /* 00571 * @implemented 00572 */ 00573 NTSTATUS 00574 NTAPI 00575 RtlCreateRegistryKey(IN ULONG RelativeTo, 00576 IN PWSTR Path) 00577 { 00578 HANDLE KeyHandle; 00579 NTSTATUS Status; 00580 PAGED_CODE_RTL(); 00581 00582 /* Call the helper */ 00583 Status = RtlpGetRegistryHandle(RelativeTo, 00584 Path, 00585 TRUE, 00586 &KeyHandle); 00587 if (!NT_SUCCESS(Status)) return Status; 00588 00589 /* All went well, close the handle and return success */ 00590 ZwClose(KeyHandle); 00591 return STATUS_SUCCESS; 00592 } 00593 00594 /* 00595 * @implemented 00596 */ 00597 NTSTATUS 00598 NTAPI 00599 RtlDeleteRegistryValue(IN ULONG RelativeTo, 00600 IN PCWSTR Path, 00601 IN PCWSTR ValueName) 00602 { 00603 HANDLE KeyHandle; 00604 NTSTATUS Status; 00605 UNICODE_STRING Name; 00606 PAGED_CODE_RTL(); 00607 00608 /* Call the helper */ 00609 Status = RtlpGetRegistryHandle(RelativeTo, 00610 Path, 00611 TRUE, 00612 &KeyHandle); 00613 if (!NT_SUCCESS(Status)) return Status; 00614 00615 /* Initialize the key name and delete it */ 00616 RtlInitUnicodeString(&Name, ValueName); 00617 Status = ZwDeleteValueKey(KeyHandle, &Name); 00618 00619 /* All went well, close the handle and return status */ 00620 ZwClose(KeyHandle); 00621 return Status; 00622 } 00623 00624 /* 00625 * @implemented 00626 */ 00627 NTSTATUS 00628 NTAPI 00629 RtlWriteRegistryValue(IN ULONG RelativeTo, 00630 IN PCWSTR Path, 00631 IN PCWSTR ValueName, 00632 IN ULONG ValueType, 00633 IN PVOID ValueData, 00634 IN ULONG ValueLength) 00635 { 00636 HANDLE KeyHandle; 00637 NTSTATUS Status; 00638 UNICODE_STRING Name; 00639 PAGED_CODE_RTL(); 00640 00641 /* Call the helper */ 00642 Status = RtlpGetRegistryHandle(RelativeTo, 00643 Path, 00644 TRUE, 00645 &KeyHandle); 00646 if (!NT_SUCCESS(Status)) return Status; 00647 00648 /* Initialize the key name and set it */ 00649 RtlInitUnicodeString(&Name, ValueName); 00650 Status = ZwSetValueKey(KeyHandle, 00651 &Name, 00652 0, 00653 ValueType, 00654 ValueData, 00655 ValueLength); 00656 00657 /* All went well, close the handle and return status */ 00658 ZwClose(KeyHandle); 00659 return Status; 00660 } 00661 00662 /* 00663 * @implemented 00664 */ 00665 NTSTATUS 00666 NTAPI 00667 RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess, 00668 OUT PHANDLE KeyHandle) 00669 { 00670 OBJECT_ATTRIBUTES ObjectAttributes; 00671 UNICODE_STRING KeyPath; 00672 NTSTATUS Status; 00673 PAGED_CODE_RTL(); 00674 00675 /* Get the user key */ 00676 Status = RtlFormatCurrentUserKeyPath(&KeyPath); 00677 if (NT_SUCCESS(Status)) 00678 { 00679 /* Initialize the attributes and open it */ 00680 InitializeObjectAttributes(&ObjectAttributes, 00681 &KeyPath, 00682 OBJ_CASE_INSENSITIVE, 00683 NULL, 00684 NULL); 00685 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes); 00686 00687 /* Free the path and return success if it worked */ 00688 RtlFreeUnicodeString(&KeyPath); 00689 if (NT_SUCCESS(Status)) return STATUS_SUCCESS; 00690 } 00691 00692 /* It didn't work, so use the default key */ 00693 RtlInitUnicodeString(&KeyPath, RtlpRegPaths[RTL_REGISTRY_USER]); 00694 InitializeObjectAttributes(&ObjectAttributes, 00695 &KeyPath, 00696 OBJ_CASE_INSENSITIVE, 00697 NULL, 00698 NULL); 00699 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes); 00700 00701 /* Return status */ 00702 return Status; 00703 } 00704 00705 /* 00706 * @implemented 00707 */ 00708 NTSTATUS 00709 NTAPI 00710 RtlFormatCurrentUserKeyPath(OUT PUNICODE_STRING KeyPath) 00711 { 00712 HANDLE TokenHandle; 00713 UCHAR Buffer[256]; 00714 PSID_AND_ATTRIBUTES SidBuffer; 00715 ULONG Length; 00716 UNICODE_STRING SidString; 00717 NTSTATUS Status; 00718 PAGED_CODE_RTL(); 00719 00720 /* Open the thread token */ 00721 Status = ZwOpenThreadToken(NtCurrentThread(), 00722 TOKEN_QUERY, 00723 TRUE, 00724 &TokenHandle); 00725 if (!NT_SUCCESS(Status)) 00726 { 00727 /* We failed, is it because we don't have a thread token? */ 00728 if (Status != STATUS_NO_TOKEN) return Status; 00729 00730 /* It is, so use the process token */ 00731 Status = ZwOpenProcessToken(NtCurrentProcess(), 00732 TOKEN_QUERY, 00733 &TokenHandle); 00734 if (!NT_SUCCESS(Status)) return Status; 00735 } 00736 00737 /* Now query the token information */ 00738 SidBuffer = (PSID_AND_ATTRIBUTES)Buffer; 00739 Status = ZwQueryInformationToken(TokenHandle, 00740 TokenUser, 00741 (PVOID)SidBuffer, 00742 sizeof(Buffer), 00743 &Length); 00744 00745 /* Close the handle and handle failure */ 00746 ZwClose(TokenHandle); 00747 if (!NT_SUCCESS(Status)) return Status; 00748 00749 /* Convert the SID */ 00750 Status = RtlConvertSidToUnicodeString(&SidString, SidBuffer[0].Sid, TRUE); 00751 if (!NT_SUCCESS(Status)) return Status; 00752 00753 /* Add the length of the prefix */ 00754 Length = SidString.Length + sizeof(L"\\REGISTRY\\USER\\"); 00755 00756 /* Initialize a string */ 00757 RtlInitEmptyUnicodeString(KeyPath, 00758 RtlpAllocateStringMemory(Length, TAG_USTR), 00759 (USHORT)Length); 00760 if (!KeyPath->Buffer) 00761 { 00762 /* Free the string and fail */ 00763 RtlFreeUnicodeString(&SidString); 00764 return STATUS_NO_MEMORY; 00765 } 00766 00767 /* Append the prefix and SID */ 00768 RtlAppendUnicodeToString(KeyPath, L"\\REGISTRY\\USER\\"); 00769 RtlAppendUnicodeStringToString(KeyPath, &SidString); 00770 00771 /* Free the temporary string and return success */ 00772 RtlFreeUnicodeString(&SidString); 00773 return STATUS_SUCCESS; 00774 } 00775 00776 /* 00777 * @implemented 00778 */ 00779 NTSTATUS 00780 NTAPI 00781 RtlpNtCreateKey(OUT HANDLE KeyHandle, 00782 IN ACCESS_MASK DesiredAccess, 00783 IN POBJECT_ATTRIBUTES ObjectAttributes, 00784 IN ULONG TitleIndex, 00785 IN PUNICODE_STRING Class, 00786 OUT PULONG Disposition) 00787 { 00788 /* Check if we have object attributes */ 00789 if (ObjectAttributes) 00790 { 00791 /* Mask out the unsupported flags */ 00792 ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE); 00793 } 00794 00795 /* Create the key */ 00796 return ZwCreateKey(KeyHandle, 00797 DesiredAccess, 00798 ObjectAttributes, 00799 0, 00800 NULL, 00801 0, 00802 Disposition); 00803 } 00804 00805 /* 00806 * @implemented 00807 */ 00808 NTSTATUS 00809 NTAPI 00810 RtlpNtEnumerateSubKey(IN HANDLE KeyHandle, 00811 OUT PUNICODE_STRING SubKeyName, 00812 IN ULONG Index, 00813 IN ULONG Unused) 00814 { 00815 PKEY_BASIC_INFORMATION KeyInfo = NULL; 00816 ULONG BufferLength = 0; 00817 ULONG ReturnedLength; 00818 NTSTATUS Status; 00819 00820 /* Check if we have a name */ 00821 if (SubKeyName->MaximumLength) 00822 { 00823 /* Allocate a buffer for it */ 00824 BufferLength = SubKeyName->MaximumLength + 00825 sizeof(KEY_BASIC_INFORMATION); 00826 KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 00827 if (!KeyInfo) return STATUS_NO_MEMORY; 00828 } 00829 00830 /* Enumerate the key */ 00831 Status = ZwEnumerateKey(KeyHandle, 00832 Index, 00833 KeyBasicInformation, 00834 KeyInfo, 00835 BufferLength, 00836 &ReturnedLength); 00837 if (NT_SUCCESS(Status)) 00838 { 00839 /* Check if the name fits */ 00840 if (KeyInfo->NameLength <= SubKeyName->MaximumLength) 00841 { 00842 /* Set the length */ 00843 SubKeyName->Length = (USHORT)KeyInfo->NameLength; 00844 00845 /* Copy it */ 00846 RtlMoveMemory(SubKeyName->Buffer, 00847 KeyInfo->Name, 00848 SubKeyName->Length); 00849 } 00850 else 00851 { 00852 /* Otherwise, we ran out of buffer space */ 00853 Status = STATUS_BUFFER_OVERFLOW; 00854 } 00855 } 00856 00857 /* Free the buffer and return status */ 00858 if (KeyInfo) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo); 00859 return Status; 00860 } 00861 00862 /* 00863 * @implemented 00864 */ 00865 NTSTATUS 00866 NTAPI 00867 RtlpNtMakeTemporaryKey(IN HANDLE KeyHandle) 00868 { 00869 /* This just deletes the key */ 00870 return ZwDeleteKey(KeyHandle); 00871 } 00872 00873 /* 00874 * @implemented 00875 */ 00876 NTSTATUS 00877 NTAPI 00878 RtlpNtOpenKey(OUT HANDLE KeyHandle, 00879 IN ACCESS_MASK DesiredAccess, 00880 IN POBJECT_ATTRIBUTES ObjectAttributes, 00881 IN ULONG Unused) 00882 { 00883 /* Check if we have object attributes */ 00884 if (ObjectAttributes) 00885 { 00886 /* Mask out the unsupported flags */ 00887 ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE); 00888 } 00889 00890 /* Open the key */ 00891 return ZwOpenKey(KeyHandle, DesiredAccess, ObjectAttributes); 00892 } 00893 00894 /* 00895 * @implemented 00896 */ 00897 NTSTATUS 00898 NTAPI 00899 RtlpNtQueryValueKey(IN HANDLE KeyHandle, 00900 OUT PULONG Type OPTIONAL, 00901 OUT PVOID Data OPTIONAL, 00902 IN OUT PULONG DataLength OPTIONAL, 00903 IN ULONG Unused) 00904 { 00905 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; 00906 UNICODE_STRING ValueName; 00907 ULONG BufferLength = 0; 00908 NTSTATUS Status; 00909 00910 /* Clear the value name */ 00911 RtlInitEmptyUnicodeString(&ValueName, NULL, 0); 00912 00913 /* Check if we were already given a length */ 00914 if (DataLength) BufferLength = *DataLength; 00915 00916 /* Add the size of the structure */ 00917 BufferLength += FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); 00918 00919 /* Allocate memory for the value */ 00920 ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 00921 if (!ValueInfo) return STATUS_NO_MEMORY; 00922 00923 /* Query the value */ 00924 Status = ZwQueryValueKey(KeyHandle, 00925 &ValueName, 00926 KeyValuePartialInformation, 00927 ValueInfo, 00928 BufferLength, 00929 &BufferLength); 00930 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW)) 00931 { 00932 /* Return the length and type */ 00933 if (DataLength) *DataLength = ValueInfo->DataLength; 00934 if (Type) *Type = ValueInfo->Type; 00935 } 00936 00937 /* Check if the caller wanted data back, and we got it */ 00938 if ((NT_SUCCESS(Status)) && (Data)) 00939 { 00940 /* Copy it */ 00941 RtlMoveMemory(Data, ValueInfo->Data, ValueInfo->DataLength); 00942 } 00943 00944 /* Free the memory and return status */ 00945 RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo); 00946 return Status; 00947 } 00948 00949 /* 00950 * @implemented 00951 */ 00952 NTSTATUS 00953 NTAPI 00954 RtlpNtSetValueKey(IN HANDLE KeyHandle, 00955 IN ULONG Type, 00956 IN PVOID Data, 00957 IN ULONG DataLength) 00958 { 00959 UNICODE_STRING ValueName; 00960 00961 /* Set the value */ 00962 RtlInitEmptyUnicodeString(&ValueName, NULL, 0); 00963 return ZwSetValueKey(KeyHandle, 00964 &ValueName, 00965 0, 00966 Type, 00967 Data, 00968 DataLength); 00969 } 00970 00971 /* 00972 * @implemented 00973 */ 00974 NTSTATUS 00975 NTAPI 00976 RtlQueryRegistryValues(IN ULONG RelativeTo, 00977 IN PCWSTR Path, 00978 IN PRTL_QUERY_REGISTRY_TABLE QueryTable, 00979 IN PVOID Context, 00980 IN PVOID Environment OPTIONAL) 00981 { 00982 NTSTATUS Status; 00983 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL; 00984 HANDLE KeyHandle, CurrentKey; 00985 SIZE_T BufferSize, InfoSize; 00986 UNICODE_STRING KeyPath, KeyValueName; 00987 OBJECT_ATTRIBUTES ObjectAttributes; 00988 ULONG i, Value; 00989 ULONG ResultLength; 00990 00991 /* Get the registry handle */ 00992 Status = RtlpGetRegistryHandle(RelativeTo, Path, FALSE, &KeyHandle); 00993 if (!NT_SUCCESS(Status)) return Status; 00994 00995 /* Initialize the path */ 00996 RtlInitUnicodeString(&KeyPath, 00997 (RelativeTo & RTL_REGISTRY_HANDLE) ? NULL : Path); 00998 00999 /* Allocate a query buffer */ 01000 BufferSize = RtlpAllocDeallocQueryBufferSize; 01001 KeyValueInfo = RtlpAllocDeallocQueryBuffer(&BufferSize, NULL, 0, &Status); 01002 if (!KeyValueInfo) 01003 { 01004 /* Close the handle if we have one and fail */ 01005 if (!(RelativeTo & RTL_REGISTRY_HANDLE)) ZwClose(KeyHandle); 01006 return Status; 01007 } 01008 01009 /* Set defaults */ 01010 KeyValueInfo->DataOffset = 0; 01011 InfoSize = BufferSize - sizeof(UNICODE_NULL); 01012 CurrentKey = KeyHandle; 01013 01014 /* Loop the query table */ 01015 while ((QueryTable->QueryRoutine) || 01016 (QueryTable->Flags & (RTL_QUERY_REGISTRY_SUBKEY | 01017 RTL_QUERY_REGISTRY_DIRECT))) 01018 { 01019 /* Check if the request is invalid */ 01020 if ((QueryTable->Flags & RTL_QUERY_REGISTRY_DIRECT) && 01021 (!(QueryTable->Name) || 01022 (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY) || 01023 (QueryTable->QueryRoutine))) 01024 { 01025 /* Fail */ 01026 Status = STATUS_INVALID_PARAMETER; 01027 break; 01028 } 01029 01030 /* Check if we want a specific key */ 01031 if (QueryTable->Flags & (RTL_QUERY_REGISTRY_TOPKEY | 01032 RTL_QUERY_REGISTRY_SUBKEY)) 01033 { 01034 /* Check if we're working with another handle */ 01035 if (CurrentKey != KeyHandle) 01036 { 01037 /* Close our current key and use the top */ 01038 NtClose(CurrentKey); 01039 CurrentKey = KeyHandle; 01040 } 01041 } 01042 01043 /* Check if we're querying the subkey */ 01044 if (QueryTable->Flags & RTL_QUERY_REGISTRY_SUBKEY) 01045 { 01046 /* Make sure we have a name */ 01047 if (!QueryTable->Name) 01048 { 01049 /* Fail */ 01050 Status = STATUS_INVALID_PARAMETER; 01051 } 01052 else 01053 { 01054 /* Initialize the name */ 01055 RtlInitUnicodeString(&KeyPath, QueryTable->Name); 01056 01057 /* Get the key handle */ 01058 InitializeObjectAttributes(&ObjectAttributes, 01059 &KeyPath, 01060 OBJ_CASE_INSENSITIVE | 01061 OBJ_KERNEL_HANDLE, 01062 KeyHandle, 01063 NULL); 01064 Status = ZwOpenKey(&CurrentKey, 01065 MAXIMUM_ALLOWED, 01066 &ObjectAttributes); 01067 if (NT_SUCCESS(Status)) 01068 { 01069 /* If we have a query routine, go enumerate values */ 01070 if (QueryTable->QueryRoutine) goto ProcessValues; 01071 } 01072 } 01073 } 01074 else if (QueryTable->Name) 01075 { 01076 /* Initialize the path */ 01077 RtlInitUnicodeString(&KeyValueName, QueryTable->Name); 01078 01079 /* Start query loop */ 01080 i = 0; 01081 while (TRUE) 01082 { 01083 /* Make sure we didn't retry too many times */ 01084 if (i++ > 4) 01085 { 01086 /* Fail */ 01087 DPRINT1("RtlQueryRegistryValues: Miscomputed buffer size " 01088 "at line %d\n", __LINE__); 01089 break; 01090 } 01091 01092 /* Query key information */ 01093 Status = ZwQueryValueKey(CurrentKey, 01094 &KeyValueName, 01095 KeyValueFullInformation, 01096 KeyValueInfo, 01097 (ULONG)InfoSize, 01098 &ResultLength); 01099 if (Status == STATUS_BUFFER_OVERFLOW) 01100 { 01101 /* Normalize status code */ 01102 Status = STATUS_BUFFER_TOO_SMALL; 01103 } 01104 01105 /* Check for failure */ 01106 if (!NT_SUCCESS(Status)) 01107 { 01108 /* Check if we didn't find it */ 01109 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 01110 { 01111 /* Setup a default */ 01112 KeyValueInfo->Type = REG_NONE; 01113 KeyValueInfo->DataLength = 0; 01114 ResultLength = (ULONG)InfoSize; 01115 01116 /* Call the query routine */ 01117 Status = RtlpCallQueryRegistryRoutine(QueryTable, 01118 KeyValueInfo, 01119 &ResultLength, 01120 Context, 01121 Environment); 01122 } 01123 01124 /* Check for buffer being too small */ 01125 if (Status == STATUS_BUFFER_TOO_SMALL) 01126 { 01127 /* Increase allocation size */ 01128 BufferSize = ResultLength + 01129 sizeof(ULONG_PTR) + 01130 sizeof(UNICODE_NULL); 01131 KeyValueInfo = RtlpAllocDeallocQueryBuffer(&BufferSize, 01132 KeyValueInfo, 01133 BufferSize, 01134 &Status); 01135 if (!KeyValueInfo) break; 01136 01137 /* Update the data */ 01138 KeyValueInfo->DataOffset = 0; 01139 InfoSize = BufferSize - sizeof(UNICODE_NULL); 01140 continue; 01141 } 01142 } 01143 else 01144 { 01145 /* Check if this is a multi-string */ 01146 if (KeyValueInfo->Type == REG_MULTI_SZ) 01147 { 01148 /* Add a null-char */ 01149 ((PWCHAR)KeyValueInfo)[ResultLength / 2] = UNICODE_NULL; 01150 KeyValueInfo->DataLength += sizeof(UNICODE_NULL); 01151 } 01152 01153 /* Call the query routine */ 01154 ResultLength = (ULONG)InfoSize; 01155 Status = RtlpCallQueryRegistryRoutine(QueryTable, 01156 KeyValueInfo, 01157 &ResultLength, 01158 Context, 01159 Environment); 01160 01161 /* Check for buffer being too small */ 01162 if (Status == STATUS_BUFFER_TOO_SMALL) 01163 { 01164 /* Increase allocation size */ 01165 BufferSize = ResultLength + 01166 sizeof(ULONG_PTR) + 01167 sizeof(UNICODE_NULL); 01168 KeyValueInfo = RtlpAllocDeallocQueryBuffer(&BufferSize, 01169 KeyValueInfo, 01170 BufferSize, 01171 &Status); 01172 if (!KeyValueInfo) break; 01173 01174 /* Update the data */ 01175 KeyValueInfo->DataOffset = 0; 01176 InfoSize = BufferSize - sizeof(UNICODE_NULL); 01177 continue; 01178 } 01179 01180 /* Check if we need to delete the key */ 01181 if ((NT_SUCCESS(Status)) && 01182 (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE)) 01183 { 01184 /* Delete it */ 01185 ZwDeleteValueKey(CurrentKey, &KeyValueName); 01186 } 01187 } 01188 01189 /* We're done, break out */ 01190 break; 01191 } 01192 } 01193 else if (QueryTable->Flags & RTL_QUERY_REGISTRY_NOVALUE) 01194 { 01195 /* Just call the query routine */ 01196 Status = QueryTable->QueryRoutine(NULL, 01197 REG_NONE, 01198 NULL, 01199 0, 01200 Context, 01201 QueryTable->EntryContext); 01202 } 01203 else 01204 { 01205 ProcessValues: 01206 /* Loop every value */ 01207 i = Value = 0; 01208 while (TRUE) 01209 { 01210 /* Enumerate the keys */ 01211 Status = ZwEnumerateValueKey(CurrentKey, 01212 Value, 01213 KeyValueFullInformation, 01214 KeyValueInfo, 01215 (ULONG)InfoSize, 01216 &ResultLength); 01217 if (Status == STATUS_BUFFER_OVERFLOW) 01218 { 01219 /* Normalize the status */ 01220 Status = STATUS_BUFFER_TOO_SMALL; 01221 } 01222 01223 /* Check if we found all the entries */ 01224 if (Status == STATUS_NO_MORE_ENTRIES) 01225 { 01226 /* Check if this was the first entry and caller needs it */ 01227 if (!(Value) && 01228 (QueryTable->Flags & RTL_QUERY_REGISTRY_REQUIRED)) 01229 { 01230 /* Fail */ 01231 Status = STATUS_OBJECT_NAME_NOT_FOUND; 01232 } 01233 else 01234 { 01235 /* Otherwise, it's ok */ 01236 Status = STATUS_SUCCESS; 01237 } 01238 break; 01239 } 01240 01241 /* Check if enumeration worked */ 01242 if (NT_SUCCESS(Status)) 01243 { 01244 /* Call the query routine */ 01245 ResultLength = (ULONG)InfoSize; 01246 Status = RtlpCallQueryRegistryRoutine(QueryTable, 01247 KeyValueInfo, 01248 &ResultLength, 01249 Context, 01250 Environment); 01251 } 01252 01253 /* Check if the query failed */ 01254 if (Status == STATUS_BUFFER_TOO_SMALL) 01255 { 01256 /* Increase allocation size */ 01257 BufferSize = ResultLength + 01258 sizeof(ULONG_PTR) + 01259 sizeof(UNICODE_NULL); 01260 KeyValueInfo = RtlpAllocDeallocQueryBuffer(&BufferSize, 01261 KeyValueInfo, 01262 BufferSize, 01263 &Status); 01264 if (!KeyValueInfo) break; 01265 01266 /* Update the data */ 01267 KeyValueInfo->DataOffset = 0; 01268 InfoSize = BufferSize - sizeof(UNICODE_NULL); 01269 01270 /* Try the value again unless it's been too many times */ 01271 if (i++ <= 4) continue; 01272 break; 01273 } 01274 01275 /* Break out if we failed */ 01276 if (!NT_SUCCESS(Status)) break; 01277 01278 /* Reset the number of retries and check if we need to delete */ 01279 i = 0; 01280 if (QueryTable->Flags & RTL_QUERY_REGISTRY_DELETE) 01281 { 01282 /* Build the name */ 01283 RtlInitEmptyUnicodeString(&KeyValueName, 01284 KeyValueInfo->Name, 01285 (USHORT)KeyValueInfo->NameLength); 01286 KeyValueName.Length = KeyValueName.MaximumLength; 01287 01288 /* Delete the key */ 01289 Status = ZwDeleteValueKey(CurrentKey, &KeyValueName); 01290 if (NT_SUCCESS(Status)) Value--; 01291 } 01292 01293 /* Go to the next value */ 01294 Value++; 01295 } 01296 } 01297 01298 /* Check if we failed anywhere along the road */ 01299 if (!NT_SUCCESS(Status)) break; 01300 01301 /* Continue */ 01302 QueryTable++; 01303 } 01304 01305 /* Check if we need to close our handle */ 01306 if ((KeyHandle) && !(RelativeTo & RTL_REGISTRY_HANDLE)) ZwClose(KeyHandle); 01307 if ((CurrentKey) && (CurrentKey != KeyHandle)) ZwClose(CurrentKey); 01308 01309 /* Free our buffer and return status */ 01310 RtlpAllocDeallocQueryBuffer(NULL, KeyValueInfo, BufferSize, NULL); 01311 return Status; 01312 } 01313 01314 /* EOF */ Generated on Sun May 27 2012 04:17:08 for ReactOS by
1.7.6.1
|