[device] Introduce device header and move details there
[people/sha0/winvblock.git] / src / winvblock / registry.c
1 /**
2  * Copyright (C) 2009-2010, 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 "portable.h"
34 #include "debug.h"
35 #include "irp.h"
36 #include "driver.h"
37 #include "registry.h"
38
39 /**
40  * Open registry key
41  *
42  * @v reg_key_name  Registry key name
43  * @v reg_key       Registry key to fill in
44  * @ret ntstatus    NT status
45  */
46 winvblock__lib_func NTSTATUS
47 registry__open_key (
48   LPCWSTR reg_key_name,
49   PHANDLE reg_key
50  )
51 {
52   UNICODE_STRING unicode_string;
53   OBJECT_ATTRIBUTES object_attrs;
54   NTSTATUS status;
55
56   RtlInitUnicodeString ( &unicode_string, reg_key_name );
57   InitializeObjectAttributes ( &object_attrs, &unicode_string,
58                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL,
59                                NULL );
60   status = ZwOpenKey ( reg_key, KEY_ALL_ACCESS, &object_attrs );
61   if ( !NT_SUCCESS ( status ) )
62     {
63       DBG ( "Could not open %S: %x\n", reg_key_name, status );
64       return status;
65     }
66
67   return STATUS_SUCCESS;
68 }
69
70 /**
71  * Close registry key
72  *
73  * @v reg_key   Registry key
74  */
75 winvblock__lib_func void
76 registry__close_key (
77   HANDLE reg_key
78  )
79 {
80   ZwClose ( reg_key );
81 }
82
83 /**
84  * Fetch registry key value information
85  *
86  * @v reg_key     Registry key
87  * @v value_name  Registry value name
88  * @v kvi         Key value information block to allocate and fill in
89  * @ret ntstatus  NT status
90  *
91  * The caller must eventually free the allocated key value information
92  * block.
93  */
94 winvblock__lib_func NTSTATUS
95 registry__fetch_kvi (
96   HANDLE reg_key,
97   LPCWSTR value_name,
98   PKEY_VALUE_PARTIAL_INFORMATION * kvi
99  )
100 {
101   UNICODE_STRING u_value_name;
102   winvblock__uint32 kvi_len;
103   NTSTATUS status;
104
105   /*
106    * Get value length 
107    */
108   RtlInitUnicodeString ( &u_value_name, value_name );
109   status =
110     ZwQueryValueKey ( reg_key, &u_value_name, KeyValuePartialInformation, NULL,
111                       0, &kvi_len );
112   if ( !
113        ( ( status == STATUS_SUCCESS ) || ( status == STATUS_BUFFER_OVERFLOW )
114          || ( status == STATUS_BUFFER_TOO_SMALL ) ) )
115     {
116       DBG ( "Could not get KVI length for \"%S\": %x\n", value_name, status );
117       goto err_zwqueryvaluekey_len;
118     }
119
120   /*
121    * Allocate value buffer 
122    */
123   *kvi = ExAllocatePool ( NonPagedPool, kvi_len );
124   if ( !*kvi )
125     {
126       DBG ( "Could not allocate KVI for \"%S\": %x\n", value_name, status );
127       goto err_exallocatepoolwithtag_kvi;
128     }
129
130   /*
131    * Fetch value 
132    */
133   status =
134     ZwQueryValueKey ( reg_key, &u_value_name, KeyValuePartialInformation, *kvi,
135                       kvi_len, &kvi_len );
136   if ( !NT_SUCCESS ( status ) )
137     {
138       DBG ( "Could not get KVI for \"%S\": %x\n", value_name, status );
139       goto err_zwqueryvaluekey;
140     }
141
142   return STATUS_SUCCESS;
143
144 err_zwqueryvaluekey:
145   ExFreePool ( kvi );
146 err_exallocatepoolwithtag_kvi:
147 err_zwqueryvaluekey_len:
148   return status;
149 }
150
151 /**
152  * Fetch registry string value
153  *
154  * @v reg_key     Registry key
155  * @v value_name  Registry value name
156  * @v value       String value to allocate and fill in
157  * @ret ntstatus  NT status
158  *
159  * The caller must eventually free the allocated value.
160  */
161 winvblock__lib_func NTSTATUS
162 registry__fetch_sz (
163   HANDLE reg_key,
164   LPCWSTR value_name,
165   LPWSTR * value
166  )
167 {
168   PKEY_VALUE_PARTIAL_INFORMATION kvi;
169   winvblock__uint32 value_len;
170   NTSTATUS status;
171
172   /*
173    * Fetch key value information 
174    */
175   status = registry__fetch_kvi ( reg_key, value_name, &kvi );
176   if ( !NT_SUCCESS ( status ) )
177     goto err_fetchkvi;
178
179   /*
180    * Allocate and populate string 
181    */
182   value_len = ( kvi->DataLength + sizeof ( value[0] ) );
183   *value = ExAllocatePool ( NonPagedPool, value_len );
184   if ( !*value )
185     {
186       DBG ( "Could not allocate value for \"%S\"\n", value_name );
187       status = STATUS_UNSUCCESSFUL;
188       goto err_exallocatepoolwithtag_value;
189     }
190   RtlZeroMemory ( *value, value_len );
191   RtlCopyMemory ( *value, kvi->Data, kvi->DataLength );
192
193 err_exallocatepoolwithtag_value:
194   ExFreePool ( kvi );
195 err_fetchkvi:
196   return status;
197 }
198
199 /**
200  * Fetch registry multiple-string value
201  *
202  * @v reg_key     Registry key
203  * @v value_name  Registry value name
204  * @v values      Array of string values to allocate and fill in
205  * @ret ntstatus  NT status
206  *
207  * The caller must eventually free the allocated values.
208  */
209 winvblock__lib_func NTSTATUS
210 registry__fetch_multi_sz (
211   HANDLE reg_key,
212   LPCWSTR value_name,
213   LPWSTR ** values
214  )
215 {
216   PKEY_VALUE_PARTIAL_INFORMATION kvi;
217   LPWSTR string;
218   winvblock__uint32 num_strings;
219   winvblock__uint32 values_len;
220   winvblock__uint32 i;
221   NTSTATUS status;
222
223   /*
224    * Fetch key value information 
225    */
226   status = registry__fetch_kvi ( reg_key, value_name, &kvi );
227   if ( !NT_SUCCESS ( status ) )
228     goto err_fetchkvi;
229
230   /*
231    * Count number of strings in the array.  This is a
232    * potential(ly harmless) overestimate.
233    */
234   num_strings = 0;
235   for ( string = ( ( LPWSTR ) kvi->Data );
236         string < ( ( LPWSTR ) ( kvi->Data + kvi->DataLength ) ); string++ )
237     {
238       if ( !*string )
239         num_strings++;
240     }
241
242   /*
243    * Allocate and populate string array 
244    */
245   values_len =
246     ( ( ( num_strings + 1 ) * sizeof ( values[0] ) ) + kvi->DataLength +
247       sizeof ( values[0][0] ) );
248   *values = ExAllocatePool ( NonPagedPool, values_len );
249   if ( !*values )
250     {
251       DBG ( "Could not allocate value array for \"%S\"\n", value_name );
252       status = STATUS_UNSUCCESSFUL;
253       goto err_exallocatepoolwithtag_value;
254     }
255   RtlZeroMemory ( *values, values_len );
256   string = ( ( LPWSTR ) ( *values + num_strings + 1 ) );
257   RtlCopyMemory ( string, kvi->Data, kvi->DataLength );
258   for ( i = 0; i < num_strings; i++ )
259     {
260       ( *values )[i] = string;
261       while ( *string )
262         string++;
263       while ( !*string )
264         string++;
265     }
266
267 err_exallocatepoolwithtag_value:
268   ExFreePool ( kvi );
269 err_fetchkvi:
270   return status;
271 }
272
273 /**
274  * Store registry string value
275  *
276  * @v reg_key     Registry key
277  * @v value_name  Registry value name
278  * @v value       String value to store
279  * @ret ntstatus  NT status
280  */
281 winvblock__lib_func NTSTATUS
282 registry__store_sz (
283   HANDLE reg_key,
284   LPCWSTR value_name,
285   LPWSTR value
286  )
287 {
288   UNICODE_STRING u_value_name;
289   SIZE_T value_len;
290   NTSTATUS status;
291
292   RtlInitUnicodeString ( &u_value_name, value_name );
293   value_len = ( ( wcslen ( value ) + 1 ) * sizeof ( value[0] ) );
294   status =
295     ZwSetValueKey ( reg_key, &u_value_name, 0, REG_SZ, value,
296                     ( ( winvblock__uint32 ) value_len ) );
297   if ( !NT_SUCCESS ( status ) )
298     {
299       DBG ( "Could not store value \"%S\": %x\n", value_name, status );
300       return status;
301     }
302
303   return STATUS_SUCCESS;
304 }
305
306 /**
307  * Store registry dword value
308  *
309  * @v reg_key     Registry key
310  * @v value_name  Registry value name
311  * @v value       String value to store, or NULL
312  * @ret ntstatus  NT status
313  */
314 winvblock__lib_func NTSTATUS
315 registry__store_dword (
316   HANDLE reg_key,
317   LPCWSTR value_name,
318   winvblock__uint32 value
319  )
320 {
321   UNICODE_STRING u_value_name;
322   NTSTATUS status;
323
324   RtlInitUnicodeString ( &u_value_name, value_name );
325   status =
326     ZwSetValueKey ( reg_key, &u_value_name, 0, REG_DWORD, &value,
327                     sizeof ( value ) );
328   if ( !NT_SUCCESS ( status ) )
329     {
330       DBG ( "Could not store value \"%S\": %x\n", value_name, status );
331       return status;
332     }
333
334   return STATUS_SUCCESS;
335 }
336
337 /**
338  * Note BOOT.INI-style OsLoadOptions from registry
339  *
340  * @v w_str_ptr         Pointer to pointer to wide-char string to hold options
341  * @ret ntstatus        NT status
342  *
343  * The caller must eventually free the wide-char string.
344  */
345 NTSTATUS
346 registry__note_os_load_opts (
347   LPWSTR * w_str_ptr
348  )
349 {
350   NTSTATUS status;
351   HANDLE control_key;
352
353   /*
354    * Open the Control key 
355    */
356   status =
357     registry__open_key
358     ( L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\",
359       &control_key );
360   if ( !NT_SUCCESS ( status ) )
361     goto err_keyopen;
362
363   /*
364    * Put the SystemStartOptions value into a global 
365    */
366   status =
367     registry__fetch_sz ( control_key, L"SystemStartOptions", w_str_ptr );
368   if ( !NT_SUCCESS ( status ) )
369     goto err_fetchsz;
370
371   DBG ( "OsLoadOptions: %S\n", *w_str_ptr );
372
373 err_fetchsz:
374
375   registry__close_key ( control_key );
376 err_keyopen:
377
378   return status;
379 }