[project] Rename winvblock__uint32 back to UINT32
[people/sha0/winvblock.git] / src / winvblock / registry.c
1 /**
2  * Copyright (C) 2009-2011, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3  * Copyright (C) 2008, Michael Brown <mbrown@fensystems.co.uk>.
4  * Copyright 2006-2008, V.
5  * For WinAoE contact information, see http://winaoe.org/
6  *
7  * This file is part of WinVBlock, derived from WinAoE.
8  * Contains functions from "sanbootconf" by Michael Brown.
9  *
10  * WinVBlock is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * WinVBlock is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 /**
25  * @file
26  *
27  * Registry specifics.
28  */
29
30 #include <ntddk.h>
31
32 #include "winvblock.h"
33 #include "wv_stdlib.h"
34 #include "portable.h"
35 #include "debug.h"
36 #include "driver.h"
37 #include "registry.h"
38
39 /**
40  * Open registry key.
41  *
42  * @v RegKeyName        Registry key name.
43  * @v RegKey            Registry key handle to fill in.
44  * @ret NTSTATUS        The status of the operation.
45  */
46 WVL_M_LIB NTSTATUS STDCALL WvlRegOpenKey(
47     LPCWSTR RegKeyName,
48     PHANDLE RegKey
49   ) {
50     UNICODE_STRING unicode_string;
51     OBJECT_ATTRIBUTES object_attrs;
52     NTSTATUS status;
53
54     RtlInitUnicodeString(&unicode_string, RegKeyName);
55     InitializeObjectAttributes(
56         &object_attrs,
57         &unicode_string,
58         OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
59         NULL,
60         NULL
61       );
62     status = ZwOpenKey(RegKey, KEY_ALL_ACCESS, &object_attrs);
63     if (!NT_SUCCESS(status)) {
64         DBG("Could not open %S: %x\n", RegKeyName, status);
65         return status;
66       }
67
68     return STATUS_SUCCESS;
69   }
70
71 /**
72  * Close a registry key handle.
73  *
74  * @v RegKey            Registry key handle to close.
75  */
76 WVL_M_LIB void STDCALL WvlRegCloseKey(HANDLE RegKey) {
77     ZwClose(RegKey);
78   }
79
80 /**
81  * Fetch registry key value information.
82  *
83  * @v RegKey            Registry key to fetch KVI for.
84  * @v ValueName         Registry value name to fetch KVI for.
85  * @v Kvi               Key value information block to allocate and fill in.
86  * @ret NTSTATUS        The status of the operation.
87  *
88  * The caller must eventually free the allocated key value information
89  * block.
90  */
91 WVL_M_LIB NTSTATUS STDCALL WvlRegFetchKvi(
92     HANDLE RegKey,
93     LPCWSTR ValueName,
94     PKEY_VALUE_PARTIAL_INFORMATION * Kvi
95   ) {
96     UNICODE_STRING u_value_name;
97     UINT32 kvi_len;
98     NTSTATUS status;
99
100     /* Get value length. */
101     RtlInitUnicodeString(&u_value_name, ValueName);
102     status = ZwQueryValueKey(
103         RegKey,
104         &u_value_name,
105         KeyValuePartialInformation,
106         NULL,
107         0,
108         &kvi_len
109       );
110     if (!(
111         (status == STATUS_SUCCESS) ||
112         (status == STATUS_BUFFER_OVERFLOW) ||
113         (status == STATUS_BUFFER_TOO_SMALL)
114       )) {
115         DBG("Could not get KVI length for \"%S\": %x\n", ValueName, status);
116         goto err_zwqueryvaluekey_len;
117       }
118
119     /* Allocate value buffer. */
120     *Kvi = wv_malloc(kvi_len);
121     if (!*Kvi) {
122         DBG("Could not allocate KVI for \"%S\": %x\n", ValueName, status);
123         goto err_kvi;
124       }
125
126     /* Fetch value. */
127     status = ZwQueryValueKey(
128         RegKey,
129         &u_value_name,
130         KeyValuePartialInformation,
131         *Kvi,
132         kvi_len,
133         &kvi_len
134       );
135     if (!NT_SUCCESS(status)) {
136         DBG("Could not get KVI for \"%S\": %x\n", ValueName, status);
137         goto err_zwqueryvaluekey;
138       }
139
140     return STATUS_SUCCESS;
141
142     err_zwqueryvaluekey:
143
144     wv_free(*Kvi);
145     err_kvi:
146
147     err_zwqueryvaluekey_len:
148
149     return status;
150   }
151
152 /**
153  * Fetch registry string value.
154  *
155  * @v RegKey            Handle for the registry key with the value.
156  * @v ValueName         Registry value name.
157  * @v Value             String value to allocate and fill in.
158  * @ret NTSTATUS        The status of the operation.
159  *
160  * The caller must eventually free the allocated value.
161  */
162 WVL_M_LIB NTSTATUS STDCALL WvlRegFetchSz(
163     HANDLE RegKey,
164     LPCWSTR ValueName,
165     LPWSTR * Value
166   ) {
167     PKEY_VALUE_PARTIAL_INFORMATION kvi;
168     UINT32 value_len;
169     NTSTATUS status;
170
171     /* Fetch key value information. */
172     status = WvlRegFetchKvi(RegKey, ValueName, &kvi);
173     if (!NT_SUCCESS(status))
174       goto err_fetchkvi;
175
176     /* Allocate and populate string. */
177     value_len = (kvi->DataLength + sizeof **Value);
178     *Value = wv_mallocz(value_len);
179     if (!*Value) {
180         DBG("Could not allocate value for \"%S\"\n", ValueName);
181         status = STATUS_UNSUCCESSFUL;
182         goto err_value;
183       }
184     RtlCopyMemory(*Value, kvi->Data, kvi->DataLength);
185
186     err_value:
187
188     wv_free(kvi);
189     err_fetchkvi:
190
191     return status;
192   }
193
194 /**
195  * Fetch registry multiple-string value.
196  *
197  * @v RegKey            Handle for the registry key with the value.
198  * @v ValueName         Registry value name.
199  * @v Values            Array of string values to allocate and fill in.
200  * @ret NTSTATUS        The status of the operation.
201  *
202  * The caller must eventually free the allocated value array.
203  */
204 WVL_M_LIB NTSTATUS STDCALL WvlRegFetchMultiSz(
205     HANDLE RegKey,
206     LPCWSTR ValueName,
207     LPWSTR ** Values
208   ) {
209     PKEY_VALUE_PARTIAL_INFORMATION kvi;
210     LPWSTR string;
211     UINT32 num_strings;
212     UINT32 values_len;
213     UINT32 i;
214     NTSTATUS status;
215
216     /* Fetch key value information. */
217     status = WvlRegFetchKvi(RegKey, ValueName, &kvi);
218     if (!NT_SUCCESS(status))
219       goto err_fetchkvi;
220
221     /*
222      * Count number of strings in the array.  This is a
223      * potential(ly harmless) overestimate.
224      */
225     num_strings = 0;
226     for (
227         string = ((LPWSTR) kvi->Data);
228         string < ((LPWSTR) (kvi->Data + kvi->DataLength));
229         string++
230       ) {
231         if (!*string)
232           num_strings++;
233       }
234
235     /* Allocate and populate string array. */
236     values_len = (
237         /* The LPWSTR[] with a NULL terminator. */
238         ((num_strings + 1) * sizeof **Values) +
239         /* The data. */
240         kvi->DataLength +
241         /* A null terminator for the data. */
242         sizeof ***Values
243       );
244     *Values = wv_mallocz(values_len);
245     if (!*Values) {
246         DBG("Could not allocate value array for \"%S\"\n", ValueName);
247         status = STATUS_UNSUCCESSFUL;
248         goto err_value;
249       }
250     /* We know that LPWSTR alignment is a multiple of WCHAR alignment. */
251     string = ((LPWSTR) (*Values + num_strings + 1));
252     /* Copy the data. */
253     RtlCopyMemory(string, kvi->Data, kvi->DataLength);
254     /* Walk the data, filling the LPWSTR[] with values. */
255     for (i = 0; i < num_strings; i++) {
256         (*Values)[i] = string;
257         while (*string)
258           string++;
259         while (!*string)
260           string++;
261       }
262
263     err_value:
264
265     wv_free(kvi);
266     err_fetchkvi:
267
268     return status;
269   }
270
271 /**
272  * Fetch registry DWORD value.
273  *
274  * @v RegKey            Handle for the registry key with the value.
275  * @v ValueName         Registry value name.
276  * @v Value             DWORD value to fill in.
277  * @ret NTSTATUS        The status of the operation.
278  */
279 WVL_M_LIB NTSTATUS STDCALL WvlRegFetchDword(
280     IN HANDLE RegKey,
281     IN LPCWSTR ValueName,
282     OUT UINT32 * Value
283   ) {
284     PKEY_VALUE_PARTIAL_INFORMATION kvi;
285     NTSTATUS status;
286
287     if (!Value) {
288         DBG("No DWORD provided.\n");
289         status = STATUS_INVALID_PARAMETER;
290         goto err_value;
291       }
292
293     /* Fetch key value information. */
294     status = WvlRegFetchKvi(RegKey, ValueName, &kvi);
295     if (!NT_SUCCESS(status))
296       goto err_fetchkvi;
297
298     /* Copy the value. */
299     if (kvi->DataLength != sizeof *Value) {
300         DBG("Registry value is not a DWORD.");
301         status = STATUS_INVALID_PARAMETER;
302         goto err_datalen;
303       }
304
305     RtlCopyMemory(Value, kvi->Data, kvi->DataLength);
306
307     err_datalen:
308
309     wv_free(kvi);
310     err_fetchkvi:
311
312     err_value:
313
314     return status;
315   }
316
317 /**
318  * Store registry string value.
319  *
320  * @v RegKey            Handle for the registry key to store the value in.
321  * @v ValueName         Registry value name.
322  * @v Value             String value to store.
323  * @ret NTSTATUS        The status of the operation.
324  */
325 WVL_M_LIB NTSTATUS STDCALL WvlRegStoreSz(
326     HANDLE RegKey,
327     LPCWSTR ValueName,
328     LPWSTR Value
329    ) {
330     UNICODE_STRING u_value_name;
331     SIZE_T value_len;
332     NTSTATUS status;
333
334     RtlInitUnicodeString(&u_value_name, ValueName);
335     value_len = ((wcslen(Value) + 1) * sizeof Value[0]);
336     status = ZwSetValueKey(
337         RegKey,
338         &u_value_name,
339         0,
340         REG_SZ,
341         Value,
342         (UINT32) value_len
343       );
344     if (!NT_SUCCESS(status)) {
345         DBG("Could not store value \"%S\": %x\n", ValueName, status);
346         return status;
347       }
348
349     return STATUS_SUCCESS;
350   }
351
352 /**
353  * Store registry DWORD value.
354  *
355  * @v RegKey            Handle for the registry key to store the value in.
356  * @v ValueName         Registry value name.
357  * @v Value             DWORD value to store, or NULL.
358  * @ret NTSTATUS        The status of the operation.
359  */
360 WVL_M_LIB NTSTATUS STDCALL WvlRegStoreDword(
361     HANDLE RegKey,
362     LPCWSTR ValueName,
363     UINT32 Value
364   ) {
365     UNICODE_STRING u_value_name;
366     NTSTATUS status;
367
368     RtlInitUnicodeString(&u_value_name, ValueName);
369     status = ZwSetValueKey(
370         RegKey,
371         &u_value_name,
372         0,
373         REG_DWORD,
374         &Value,
375         sizeof Value
376       );
377     if (!NT_SUCCESS(status)) {
378         DBG("Could not store value \"%S\": %x\n", ValueName, status);
379         return status;
380       }
381
382     return STATUS_SUCCESS;
383   }
384
385 /**
386  * Note BOOT.INI-/TXTSETUP.SIF-style OsLoadOptions from registry.
387  *
388  * @v WStr              Pointer to pointer to wide-char string to hold options.
389  * @ret NTSTATUS        The status of the operation.
390  *
391  * The caller must eventually free the wide-char string.
392  */
393 WVL_M_LIB NTSTATUS STDCALL WvlRegNoteOsLoadOpts(LPWSTR * WStr) {
394     NTSTATUS status;
395     HANDLE control_key;
396
397     /* Open the Control key. */
398     status = WvlRegOpenKey(
399         L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\",
400         &control_key
401       );
402     if (!NT_SUCCESS(status))
403       goto err_keyopen;
404
405     /* Put the SystemStartOptions value into w_str. */
406     status = WvlRegFetchSz(control_key, L"SystemStartOptions", WStr);
407     if (!NT_SUCCESS(status))
408       goto err_fetchsz;
409
410     DBG("OsLoadOptions: %S\n", *WStr);
411
412     err_fetchsz:
413
414     WvlRegCloseKey(control_key);
415     err_keyopen:
416
417     return status;
418   }