ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

registry.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.