xref: /reactos/win32ss/user/ntuser/misc/registry.c (revision 3768f089)
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
RegOpenKey(LPCWSTR pwszKeyName,PHKEY phkey)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
RegQueryValue(IN HKEY hkey,IN PCWSTR pwszValueName,IN ULONG ulType,OUT PVOID pvData,IN OUT PULONG pcbValue)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
RegWriteSZ(HKEY hkey,PCWSTR pwszValue,PWSTR pwszData)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
RegWriteDWORD(HKEY hkey,PCWSTR pwszValue,DWORD dwData)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
RegReadDWORD(HKEY hkey,PCWSTR pwszValue,PDWORD pdwData)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
RegOpenSectionKey(LPCWSTR pszSection,PHKEY phkey)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
RegGetSectionDWORD(LPCWSTR pszSection,PCWSTR pszValue,DWORD dwDefault)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
RegWriteUserSetting(_In_z_ PCWSTR pwszKeyName,_In_z_ PCWSTR pwszValueName,_In_ ULONG ulType,_In_reads_bytes_ (cjDataSize)const VOID * pvData,_In_ ULONG cbDataSize)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