xref: /reactos/win32ss/user/ntuser/misc/registry.c (revision 2196a06f)
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 _Success_(return!=FALSE)
159 BOOL
160 NTAPI
161 RegReadUserSetting(
162     _In_z_ PCWSTR pwszKeyName,
163     _In_z_ PCWSTR pwszValueName,
164     _In_ ULONG ulType,
165     _Out_writes_(cbDataSize) _When_(ulType == REG_SZ, _Post_z_) PVOID pvData,
166     _In_ ULONG cbDataSize)
167 {
168     NTSTATUS Status;
169     OBJECT_ATTRIBUTES ObjectAttributes;
170     UNICODE_STRING usCurrentUserKey, usKeyName, usValueName;
171     WCHAR awcBuffer[MAX_PATH];
172     HKEY hkey;
173     PKEY_VALUE_PARTIAL_INFORMATION pInfo;
174     ULONG cbInfoSize, cbReqSize;
175 
176     /* Get the path of the current user's profile */
177     Status = RtlFormatCurrentUserKeyPath(&usCurrentUserKey);
178     if (!NT_SUCCESS(Status))
179     {
180         return FALSE;
181     }
182 
183     /* Initialize empty key name */
184     RtlInitEmptyUnicodeString(&usKeyName, awcBuffer, sizeof(awcBuffer));
185 
186     /* Append the current user key name */
187     Status = RtlAppendUnicodeStringToString(&usKeyName, &usCurrentUserKey);
188 
189     /* Free the current user key name */
190     RtlFreeUnicodeString(&usCurrentUserKey);
191 
192     /* Check for success */
193     if (!NT_SUCCESS(Status))
194     {
195         return FALSE;
196     }
197 
198     /* Append a '\', we can trust in enough space left. */
199     usKeyName.Buffer[usKeyName.Length / sizeof(WCHAR)] = '\\';
200     usKeyName.Length += sizeof(WCHAR);
201 
202     /* Append the subkey name */
203     Status = RtlAppendUnicodeToString(&usKeyName, pwszKeyName);
204     if (!NT_SUCCESS(Status))
205     {
206         return FALSE;
207     }
208 
209     /* Initialize object attributes */
210     InitializeObjectAttributes(&ObjectAttributes,
211                                &usKeyName,
212                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
213                                NULL,
214                                NULL);
215 
216     /* Open the key */
217     Status = ZwOpenKey((PHANDLE)&hkey, KEY_READ, &ObjectAttributes);
218     if (!NT_SUCCESS(Status))
219     {
220         return FALSE;
221     }
222 
223     /* Check if the local buffer is sufficient */
224     cbInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + cbDataSize;
225     if (cbInfoSize <= sizeof(awcBuffer))
226     {
227         pInfo = (PVOID)awcBuffer;
228     }
229     else
230     {
231         /* It's not, allocate a sufficient buffer */
232         pInfo = ExAllocatePoolWithTag(PagedPool, cbInfoSize, TAG_TEMP);
233         if (!pInfo)
234         {
235             ZwClose(hkey);
236             return FALSE;
237         }
238     }
239 
240     /* Query the value */
241     RtlInitUnicodeString(&usValueName, pwszValueName);
242     Status = ZwQueryValueKey(hkey,
243                              &usValueName,
244                              KeyValuePartialInformation,
245                              (PVOID)pInfo,
246                              cbInfoSize,
247                              &cbReqSize);
248     if (NT_SUCCESS(Status))
249     {
250         /* Did we get the right type */
251         if (pInfo->Type == ulType)
252         {
253             /* Copy the contents to the caller */
254             RtlCopyMemory(pvData, pInfo->Data, cbDataSize);
255         }
256     }
257 
258     /* Cleanup */
259     ZwClose(hkey);
260     if (pInfo != (PVOID)awcBuffer)
261         ExFreePoolWithTag(pInfo, TAG_TEMP);
262 
263     return NT_SUCCESS(Status);
264 }
265 
266 _Success_(return != FALSE)
267 BOOL
268 NTAPI
269 RegWriteUserSetting(
270     _In_z_ PCWSTR pwszKeyName,
271     _In_z_ PCWSTR pwszValueName,
272     _In_ ULONG ulType,
273     _In_reads_bytes_(cjDataSize) const VOID *pvData,
274     _In_ ULONG cbDataSize)
275 {
276     NTSTATUS Status;
277     OBJECT_ATTRIBUTES ObjectAttributes;
278     UNICODE_STRING usCurrentUserKey, usKeyName, usValueName;
279     WCHAR awcBuffer[MAX_PATH];
280     HKEY hkey;
281 
282     // FIXME: Logged in user versus current process user?
283     /* Get the path of the current user's profile */
284     Status = RtlFormatCurrentUserKeyPath(&usCurrentUserKey);
285     if (!NT_SUCCESS(Status))
286     {
287         DPRINT1("RtlFormatCurrentUserKeyPath failed\n");
288         return FALSE;
289     }
290 
291     /* Initialize empty key name */
292     RtlInitEmptyUnicodeString(&usKeyName, awcBuffer, sizeof(awcBuffer));
293 
294     /* Append the current user key name */
295     Status = RtlAppendUnicodeStringToString(&usKeyName, &usCurrentUserKey);
296     if (!NT_SUCCESS(Status))
297     {
298         return FALSE;
299     }
300 
301     /* Free the current user key name */
302     RtlFreeUnicodeString(&usCurrentUserKey);
303 
304     /* Append a '\', we can trust in enough space left. */
305     usKeyName.Buffer[usKeyName.Length / sizeof(WCHAR)] = '\\';
306     usKeyName.Length += sizeof(WCHAR);
307 
308     /* Append the subkey name */
309     Status = RtlAppendUnicodeToString(&usKeyName, pwszKeyName);
310     if (!NT_SUCCESS(Status))
311     {
312         DPRINT1("RtlAppendUnicodeToString failed with Status=0x%lx, buf:%u,%u\n",
313                 Status, usKeyName.Length, usKeyName.MaximumLength);
314         return FALSE;
315     }
316 
317     /* Initialize object attributes */
318     InitializeObjectAttributes(&ObjectAttributes,
319                                &usKeyName,
320                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
321                                NULL,
322                                NULL);
323 
324     /* Open or create the key */
325     Status = ZwCreateKey((PHANDLE)&hkey,
326                          KEY_READ | KEY_WRITE,
327                          &ObjectAttributes,
328                          0,
329                          NULL,
330                          0,
331                          NULL);
332     if(!NT_SUCCESS(Status))
333     {
334         DPRINT1("Failed to create key: 0x%x\n", Status);
335         return FALSE;
336     }
337 
338     /* Initialize the value name string */
339     RtlInitUnicodeString(&usValueName, pwszValueName);
340 
341     Status = ZwSetValueKey(hkey, &usValueName, 0, ulType, (PVOID)pvData, cbDataSize);
342     if(!NT_SUCCESS(Status))
343     {
344         DPRINT1("Failed to write reg key '%S' value '%S', Status = %lx\n",
345                 pwszKeyName, pwszValueName, Status);
346     }
347 
348     /* Cleanup */
349     ZwClose(hkey);
350 
351     return NT_SUCCESS(Status);
352 }
353 
354