xref: /reactos/win32ss/user/ntuser/misc/registry.c (revision 10e7643c)
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 
126 VOID
127 NTAPI
128 RegWriteSZ(HKEY hkey, PWSTR pwszValue, PWSTR pwszData)
129 {
130     UNICODE_STRING ustrValue;
131     UNICODE_STRING ustrData;
132 
133     RtlInitUnicodeString(&ustrValue, pwszValue);
134     RtlInitUnicodeString(&ustrData, pwszData);
135     ZwSetValueKey(hkey, &ustrValue, 0, REG_SZ, &ustrData, ustrData.Length + sizeof(WCHAR));
136 }
137 
138 VOID
139 NTAPI
140 RegWriteDWORD(HKEY hkey, PWSTR pwszValue, DWORD dwData)
141 {
142     UNICODE_STRING ustrValue;
143 
144     RtlInitUnicodeString(&ustrValue, pwszValue);
145     ZwSetValueKey(hkey, &ustrValue, 0, REG_DWORD, &dwData, sizeof(DWORD));
146 }
147 
148 BOOL
149 NTAPI
150 RegReadDWORD(HKEY hkey, PWSTR pwszValue, PDWORD pdwData)
151 {
152     NTSTATUS Status;
153     ULONG cbSize = sizeof(DWORD);
154     Status = RegQueryValue(hkey, pwszValue, REG_DWORD, pdwData, &cbSize);
155     return NT_SUCCESS(Status);
156 }
157 
158 NTSTATUS
159 NTAPI
160 RegOpenSectionKey(
161     LPCWSTR pszSection,
162     PHKEY phkey)
163 {
164     WCHAR szKey[MAX_PATH] =
165         L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\";
166 
167     RtlStringCchCatW(szKey, _countof(szKey), pszSection);
168     return RegOpenKey(szKey, phkey);
169 }
170 
171 DWORD
172 NTAPI
173 RegGetSectionDWORD(LPCWSTR pszSection, LPWSTR pszValue, DWORD dwDefault)
174 {
175     HKEY hKey;
176     DWORD dwValue;
177 
178     if (NT_ERROR(RegOpenSectionKey(pszSection, &hKey)))
179         return dwDefault;
180 
181     if (!RegReadDWORD(hKey, pszValue, &dwValue))
182         dwValue = dwDefault;
183 
184     ZwClose(hKey);
185     return dwValue;
186 }
187 
188 _Success_(return!=FALSE)
189 BOOL
190 NTAPI
191 RegReadUserSetting(
192     _In_z_ PCWSTR pwszKeyName,
193     _In_z_ PCWSTR pwszValueName,
194     _In_ ULONG ulType,
195     _Out_writes_(cbDataSize) _When_(ulType == REG_SZ, _Post_z_) PVOID pvData,
196     _In_ ULONG cbDataSize)
197 {
198     NTSTATUS Status;
199     OBJECT_ATTRIBUTES ObjectAttributes;
200     UNICODE_STRING usCurrentUserKey, usKeyName, usValueName;
201     WCHAR awcBuffer[MAX_PATH];
202     HKEY hkey;
203     PKEY_VALUE_PARTIAL_INFORMATION pInfo;
204     ULONG cbInfoSize, cbReqSize;
205 
206     /* Get the path of the current user's profile */
207     Status = RtlFormatCurrentUserKeyPath(&usCurrentUserKey);
208     if (!NT_SUCCESS(Status))
209     {
210         return FALSE;
211     }
212 
213     /* Initialize empty key name */
214     RtlInitEmptyUnicodeString(&usKeyName, awcBuffer, sizeof(awcBuffer));
215 
216     /* Append the current user key name */
217     Status = RtlAppendUnicodeStringToString(&usKeyName, &usCurrentUserKey);
218 
219     /* Free the current user key name */
220     RtlFreeUnicodeString(&usCurrentUserKey);
221 
222     /* Check for success */
223     if (!NT_SUCCESS(Status))
224     {
225         return FALSE;
226     }
227 
228     /* Append a '\', we can trust in enough space left. */
229     usKeyName.Buffer[usKeyName.Length / sizeof(WCHAR)] = '\\';
230     usKeyName.Length += sizeof(WCHAR);
231 
232     /* Append the subkey name */
233     Status = RtlAppendUnicodeToString(&usKeyName, pwszKeyName);
234     if (!NT_SUCCESS(Status))
235     {
236         return FALSE;
237     }
238 
239     /* Initialize object attributes */
240     InitializeObjectAttributes(&ObjectAttributes,
241                                &usKeyName,
242                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
243                                NULL,
244                                NULL);
245 
246     /* Open the key */
247     Status = ZwOpenKey((PHANDLE)&hkey, KEY_READ, &ObjectAttributes);
248     if (!NT_SUCCESS(Status))
249     {
250         return FALSE;
251     }
252 
253     /* Check if the local buffer is sufficient */
254     cbInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + cbDataSize;
255     if (cbInfoSize <= sizeof(awcBuffer))
256     {
257         pInfo = (PVOID)awcBuffer;
258     }
259     else
260     {
261         /* It's not, allocate a sufficient buffer */
262         pInfo = ExAllocatePoolWithTag(PagedPool, cbInfoSize, TAG_TEMP);
263         if (!pInfo)
264         {
265             ZwClose(hkey);
266             return FALSE;
267         }
268     }
269 
270     /* Query the value */
271     RtlInitUnicodeString(&usValueName, pwszValueName);
272     Status = ZwQueryValueKey(hkey,
273                              &usValueName,
274                              KeyValuePartialInformation,
275                              (PVOID)pInfo,
276                              cbInfoSize,
277                              &cbReqSize);
278     if (NT_SUCCESS(Status))
279     {
280         /* Did we get the right type */
281         if (pInfo->Type == ulType)
282         {
283             /* Copy the contents to the caller */
284             RtlCopyMemory(pvData, pInfo->Data, cbDataSize);
285         }
286     }
287 
288     /* Cleanup */
289     ZwClose(hkey);
290     if (pInfo != (PVOID)awcBuffer)
291         ExFreePoolWithTag(pInfo, TAG_TEMP);
292 
293     return NT_SUCCESS(Status);
294 }
295 
296 _Success_(return != FALSE)
297 BOOL
298 NTAPI
299 RegWriteUserSetting(
300     _In_z_ PCWSTR pwszKeyName,
301     _In_z_ PCWSTR pwszValueName,
302     _In_ ULONG ulType,
303     _In_reads_bytes_(cjDataSize) const VOID *pvData,
304     _In_ ULONG cbDataSize)
305 {
306     NTSTATUS Status;
307     OBJECT_ATTRIBUTES ObjectAttributes;
308     UNICODE_STRING usCurrentUserKey, usKeyName, usValueName;
309     WCHAR awcBuffer[MAX_PATH];
310     HKEY hkey;
311 
312     // FIXME: Logged in user versus current process user?
313     /* Get the path of the current user's profile */
314     Status = RtlFormatCurrentUserKeyPath(&usCurrentUserKey);
315     if (!NT_SUCCESS(Status))
316     {
317         DPRINT1("RtlFormatCurrentUserKeyPath failed\n");
318         return FALSE;
319     }
320 
321     /* Initialize empty key name */
322     RtlInitEmptyUnicodeString(&usKeyName, awcBuffer, sizeof(awcBuffer));
323 
324     /* Append the current user key name */
325     Status = RtlAppendUnicodeStringToString(&usKeyName, &usCurrentUserKey);
326     if (!NT_SUCCESS(Status))
327     {
328         return FALSE;
329     }
330 
331     /* Free the current user key name */
332     RtlFreeUnicodeString(&usCurrentUserKey);
333 
334     /* Append a '\', we can trust in enough space left. */
335     usKeyName.Buffer[usKeyName.Length / sizeof(WCHAR)] = '\\';
336     usKeyName.Length += sizeof(WCHAR);
337 
338     /* Append the subkey name */
339     Status = RtlAppendUnicodeToString(&usKeyName, pwszKeyName);
340     if (!NT_SUCCESS(Status))
341     {
342         DPRINT1("RtlAppendUnicodeToString failed with Status=0x%lx, buf:%u,%u\n",
343                 Status, usKeyName.Length, usKeyName.MaximumLength);
344         return FALSE;
345     }
346 
347     /* Initialize object attributes */
348     InitializeObjectAttributes(&ObjectAttributes,
349                                &usKeyName,
350                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
351                                NULL,
352                                NULL);
353 
354     /* Open or create the key */
355     Status = ZwCreateKey((PHANDLE)&hkey,
356                          KEY_READ | KEY_WRITE,
357                          &ObjectAttributes,
358                          0,
359                          NULL,
360                          0,
361                          NULL);
362     if(!NT_SUCCESS(Status))
363     {
364         DPRINT1("Failed to create key: 0x%x\n", Status);
365         return FALSE;
366     }
367 
368     /* Initialize the value name string */
369     RtlInitUnicodeString(&usValueName, pwszValueName);
370 
371     Status = ZwSetValueKey(hkey, &usValueName, 0, ulType, (PVOID)pvData, cbDataSize);
372     if(!NT_SUCCESS(Status))
373     {
374         DPRINT1("Failed to write reg key '%S' value '%S', Status = %lx\n",
375                 pwszKeyName, pwszValueName, Status);
376     }
377 
378     /* Cleanup */
379     ZwClose(hkey);
380 
381     return NT_SUCCESS(Status);
382 }
383 
384