xref: /reactos/win32ss/user/ntuser/misc/registry.c (revision 5140a990)
1 /*
2  * COPYRIGHT:        GPL, see COPYING in the top level directory
3  * PROJECT:          ReactOS win32 kernel mode subsystem server
4  * PURPOSE:          Registry loading and storing
5  * FILE:             win32ss/user/ntuser/misc/registry.c
6  * PROGRAMER:        Timo Kreuzer (timo.kreuzer@reactos.org)
7  */
8 
9 #include <win32k.h>
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 NTSTATUS
15 NTAPI
16 RegOpenKey(
17     LPCWSTR pwszKeyName,
18     PHKEY phkey)
19 {
20     NTSTATUS Status;
21     OBJECT_ATTRIBUTES ObjectAttributes;
22     UNICODE_STRING ustrKeyName;
23     HKEY hkey;
24 
25     /* Initialize the key name */
26     RtlInitUnicodeString(&ustrKeyName, pwszKeyName);
27 
28     /* Initialize object attributes */
29     InitializeObjectAttributes(&ObjectAttributes,
30                                &ustrKeyName,
31                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
32                                NULL,
33                                NULL);
34 
35     /* Open the key */
36     Status = ZwOpenKey((PHANDLE)&hkey, KEY_READ, &ObjectAttributes);
37     if (NT_SUCCESS(Status))
38     {
39         *phkey = hkey;
40     }
41 
42     return Status;
43 }
44 
45 NTSTATUS
46 NTAPI
47 RegQueryValue(
48     IN HKEY hkey,
49     IN PCWSTR pwszValueName,
50     IN ULONG ulType,
51     OUT PVOID pvData,
52     IN OUT PULONG pcbValue)
53 {
54     NTSTATUS Status;
55     UNICODE_STRING ustrValueName;
56     BYTE ajBuffer[100];
57     PKEY_VALUE_PARTIAL_INFORMATION pInfo;
58     ULONG cbInfoSize, cbDataSize;
59 
60     /* Check if the local buffer is sufficient */
61     cbInfoSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[*pcbValue]);
62     if (cbInfoSize <= sizeof(ajBuffer))
63     {
64         pInfo = (PVOID)ajBuffer;
65     }
66     else
67     {
68         /* It's not, allocate a sufficient buffer */
69         pInfo = ExAllocatePoolWithTag(PagedPool, cbInfoSize, TAG_TEMP);
70         if (!pInfo)
71         {
72             return STATUS_INSUFFICIENT_RESOURCES;
73         }
74     }
75 
76     /* Query the value */
77     RtlInitUnicodeString(&ustrValueName, pwszValueName);
78     Status = ZwQueryValueKey(hkey,
79                              &ustrValueName,
80                              KeyValuePartialInformation,
81                              (PVOID)pInfo,
82                              cbInfoSize,
83                              &cbInfoSize);
84 
85     /* Note: STATUS_BUFFER_OVERFLOW is not a success */
86     if (NT_SUCCESS(Status))
87     {
88         cbDataSize = pInfo->DataLength;
89 
90         /* Did we get the right type */
91         if (pInfo->Type != ulType)
92         {
93             Status = STATUS_OBJECT_TYPE_MISMATCH;
94         }
95         else if (cbDataSize > *pcbValue)
96         {
97             Status = STATUS_BUFFER_TOO_SMALL;
98         }
99         else
100         {
101             /* Copy the contents to the caller */
102             RtlCopyMemory(pvData, pInfo->Data, cbDataSize);
103         }
104     }
105     else if ((Status == STATUS_BUFFER_OVERFLOW) || (Status == STATUS_BUFFER_TOO_SMALL))
106     {
107         _PRAGMA_WARNING_SUPPRESS(6102); /* cbInfoSize is initialized here! */
108         cbDataSize = cbInfoSize - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
109     }
110     else
111     {
112         cbDataSize = 0;
113     }
114 
115     /* Return the data size to the caller */
116     *pcbValue = cbDataSize;
117 
118     /* Cleanup */
119     if (pInfo != (PVOID)ajBuffer)
120         ExFreePoolWithTag(pInfo, TAG_TEMP);
121 
122     return Status;
123 }
124 
125 VOID
126 NTAPI
127 RegWriteSZ(HKEY hkey, PCWSTR pwszValue, PWSTR pwszData)
128 {
129     UNICODE_STRING ustrValue;
130     UNICODE_STRING ustrData;
131 
132     RtlInitUnicodeString(&ustrValue, pwszValue);
133     RtlInitUnicodeString(&ustrData, pwszData);
134     ZwSetValueKey(hkey, &ustrValue, 0, REG_SZ, &ustrData, ustrData.Length + sizeof(WCHAR));
135 }
136 
137 VOID
138 NTAPI
139 RegWriteDWORD(HKEY hkey, PCWSTR pwszValue, DWORD dwData)
140 {
141     UNICODE_STRING ustrValue;
142 
143     RtlInitUnicodeString(&ustrValue, pwszValue);
144     ZwSetValueKey(hkey, &ustrValue, 0, REG_DWORD, &dwData, sizeof(DWORD));
145 }
146 
147 BOOL
148 NTAPI
149 RegReadDWORD(HKEY hkey, PCWSTR pwszValue, PDWORD pdwData)
150 {
151     NTSTATUS Status;
152     ULONG cbSize = sizeof(DWORD);
153     Status = RegQueryValue(hkey, pwszValue, REG_DWORD, pdwData, &cbSize);
154     return NT_SUCCESS(Status);
155 }
156 
157 NTSTATUS
158 NTAPI
159 RegOpenSectionKey(
160     LPCWSTR pszSection,
161     PHKEY phkey)
162 {
163     WCHAR szKey[MAX_PATH] =
164         L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\";
165 
166     RtlStringCchCatW(szKey, _countof(szKey), pszSection);
167     return RegOpenKey(szKey, phkey);
168 }
169 
170 DWORD
171 NTAPI
172 RegGetSectionDWORD(LPCWSTR pszSection, PCWSTR pszValue, DWORD dwDefault)
173 {
174     HKEY hKey;
175     DWORD dwValue;
176 
177     if (NT_ERROR(RegOpenSectionKey(pszSection, &hKey)))
178         return dwDefault;
179 
180     if (!RegReadDWORD(hKey, pszValue, &dwValue))
181         dwValue = dwDefault;
182 
183     ZwClose(hKey);
184     return dwValue;
185 }
186 
187 _Success_(return!=FALSE)
188 BOOL
189 NTAPI
190 RegReadUserSetting(
191     _In_z_ PCWSTR pwszKeyName,
192     _In_z_ PCWSTR pwszValueName,
193     _In_ ULONG ulType,
194     _Out_writes_(cbDataSize) _When_(ulType == REG_SZ, _Post_z_) PVOID pvData,
195     _In_ ULONG cbDataSize)
196 {
197     NTSTATUS Status;
198     OBJECT_ATTRIBUTES ObjectAttributes;
199     UNICODE_STRING usCurrentUserKey, usKeyName, usValueName;
200     WCHAR awcBuffer[MAX_PATH];
201     HKEY hkey;
202     PKEY_VALUE_PARTIAL_INFORMATION pInfo;
203     ULONG cbInfoSize, cbReqSize;
204 
205     /* Get the path of the current user's profile */
206     Status = RtlFormatCurrentUserKeyPath(&usCurrentUserKey);
207     if (!NT_SUCCESS(Status))
208     {
209         return FALSE;
210     }
211 
212     /* Initialize empty key name */
213     RtlInitEmptyUnicodeString(&usKeyName, awcBuffer, sizeof(awcBuffer));
214 
215     /* Append the current user key name */
216     Status = RtlAppendUnicodeStringToString(&usKeyName, &usCurrentUserKey);
217 
218     /* Free the current user key name */
219     RtlFreeUnicodeString(&usCurrentUserKey);
220 
221     /* Check for success */
222     if (!NT_SUCCESS(Status))
223     {
224         return FALSE;
225     }
226 
227     /* Append a '\', we can trust in enough space left. */
228     usKeyName.Buffer[usKeyName.Length / sizeof(WCHAR)] = '\\';
229     usKeyName.Length += sizeof(WCHAR);
230 
231     /* Append the subkey name */
232     Status = RtlAppendUnicodeToString(&usKeyName, pwszKeyName);
233     if (!NT_SUCCESS(Status))
234     {
235         return FALSE;
236     }
237 
238     /* Initialize object attributes */
239     InitializeObjectAttributes(&ObjectAttributes,
240                                &usKeyName,
241                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
242                                NULL,
243                                NULL);
244 
245     /* Open the key */
246     Status = ZwOpenKey((PHANDLE)&hkey, KEY_READ, &ObjectAttributes);
247     if (!NT_SUCCESS(Status))
248     {
249         return FALSE;
250     }
251 
252     /* Check if the local buffer is sufficient */
253     cbInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + cbDataSize;
254     if (cbInfoSize <= sizeof(awcBuffer))
255     {
256         pInfo = (PVOID)awcBuffer;
257     }
258     else
259     {
260         /* It's not, allocate a sufficient buffer */
261         pInfo = ExAllocatePoolWithTag(PagedPool, cbInfoSize, TAG_TEMP);
262         if (!pInfo)
263         {
264             ZwClose(hkey);
265             return FALSE;
266         }
267     }
268 
269     /* Query the value */
270     RtlInitUnicodeString(&usValueName, pwszValueName);
271     Status = ZwQueryValueKey(hkey,
272                              &usValueName,
273                              KeyValuePartialInformation,
274                              (PVOID)pInfo,
275                              cbInfoSize,
276                              &cbReqSize);
277     if (NT_SUCCESS(Status))
278     {
279         /* Did we get the right type */
280         if (pInfo->Type == ulType)
281         {
282             /* Copy the contents to the caller */
283             RtlCopyMemory(pvData, pInfo->Data, cbDataSize);
284         }
285     }
286 
287     /* Cleanup */
288     ZwClose(hkey);
289     if (pInfo != (PVOID)awcBuffer)
290         ExFreePoolWithTag(pInfo, TAG_TEMP);
291 
292     return NT_SUCCESS(Status);
293 }
294 
295 _Success_(return != FALSE)
296 BOOL
297 NTAPI
298 RegWriteUserSetting(
299     _In_z_ PCWSTR pwszKeyName,
300     _In_z_ PCWSTR pwszValueName,
301     _In_ ULONG ulType,
302     _In_reads_bytes_(cjDataSize) const VOID *pvData,
303     _In_ ULONG cbDataSize)
304 {
305     NTSTATUS Status;
306     OBJECT_ATTRIBUTES ObjectAttributes;
307     UNICODE_STRING usCurrentUserKey, usKeyName, usValueName;
308     WCHAR awcBuffer[MAX_PATH];
309     HKEY hkey;
310 
311     // FIXME: Logged in user versus current process user?
312     /* Get the path of the current user's profile */
313     Status = RtlFormatCurrentUserKeyPath(&usCurrentUserKey);
314     if (!NT_SUCCESS(Status))
315     {
316         DPRINT1("RtlFormatCurrentUserKeyPath failed\n");
317         return FALSE;
318     }
319 
320     /* Initialize empty key name */
321     RtlInitEmptyUnicodeString(&usKeyName, awcBuffer, sizeof(awcBuffer));
322 
323     /* Append the current user key name */
324     Status = RtlAppendUnicodeStringToString(&usKeyName, &usCurrentUserKey);
325     if (!NT_SUCCESS(Status))
326     {
327         return FALSE;
328     }
329 
330     /* Free the current user key name */
331     RtlFreeUnicodeString(&usCurrentUserKey);
332 
333     /* Append a '\', we can trust in enough space left. */
334     usKeyName.Buffer[usKeyName.Length / sizeof(WCHAR)] = '\\';
335     usKeyName.Length += sizeof(WCHAR);
336 
337     /* Append the subkey name */
338     Status = RtlAppendUnicodeToString(&usKeyName, pwszKeyName);
339     if (!NT_SUCCESS(Status))
340     {
341         DPRINT1("RtlAppendUnicodeToString failed with Status=0x%lx, buf:%u,%u\n",
342                 Status, usKeyName.Length, usKeyName.MaximumLength);
343         return FALSE;
344     }
345 
346     /* Initialize object attributes */
347     InitializeObjectAttributes(&ObjectAttributes,
348                                &usKeyName,
349                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
350                                NULL,
351                                NULL);
352 
353     /* Open or create the key */
354     Status = ZwCreateKey((PHANDLE)&hkey,
355                          KEY_READ | KEY_WRITE,
356                          &ObjectAttributes,
357                          0,
358                          NULL,
359                          0,
360                          NULL);
361     if(!NT_SUCCESS(Status))
362     {
363         DPRINT1("Failed to create key: 0x%x\n", Status);
364         return FALSE;
365     }
366 
367     /* Initialize the value name string */
368     RtlInitUnicodeString(&usValueName, pwszValueName);
369 
370     Status = ZwSetValueKey(hkey, &usValueName, 0, ulType, (PVOID)pvData, cbDataSize);
371     if(!NT_SUCCESS(Status))
372     {
373         DPRINT1("Failed to write reg key '%S' value '%S', Status = %lx\n",
374                 pwszKeyName, pwszValueName, Status);
375     }
376 
377     /* Cleanup */
378     ZwClose(hkey);
379 
380     return NT_SUCCESS(Status);
381 }
382 
383