Storing an IP address in a signed int results in bugs if it starts
[wine] / dlls / ntdll / reg.c
1 /*
2  * Registry functions
3  *
4  * Copyright (C) 1999 Juergen Schmied
5  * Copyright (C) 2000 Alexandre Julliard
6  *
7  * NOTES:
8  *      HKEY_LOCAL_MACHINE      \\REGISTRY\\MACHINE
9  *      HKEY_USERS              \\REGISTRY\\USER
10  *      HKEY_CURRENT_CONFIG     \\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT
11   *     HKEY_CLASSES            \\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES
12  */
13
14 #include <string.h>
15 #include "debugtools.h"
16 #include "winreg.h"
17 #include "winerror.h"
18 #include "wine/unicode.h"
19 #include "wine/server.h"
20 #include "ntddk.h"
21 #include "ntdll_misc.h"
22
23 DEFAULT_DEBUG_CHANNEL(reg);
24
25 /* maximum length of a key/value name in bytes (without terminating null) */
26 #define MAX_NAME_LENGTH ((MAX_PATH-1) * sizeof(WCHAR))
27
28
29 /******************************************************************************
30  * NtCreateKey [NTDLL.@]
31  * ZwCreateKey [NTDLL.@]
32  */
33 NTSTATUS WINAPI NtCreateKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
34                              ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
35                              PULONG dispos )
36 {
37     NTSTATUS ret;
38
39     TRACE( "(0x%x,%s,%s,%lx,%lx,%p)\n", attr->RootDirectory, debugstr_us(attr->ObjectName),
40            debugstr_us(class), options, access, retkey );
41
42     if (attr->ObjectName->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
43     if (!retkey) return STATUS_INVALID_PARAMETER;
44
45     SERVER_START_REQ( create_key )
46     {
47         req->parent  = attr->RootDirectory;
48         req->access  = access;
49         req->options = options;
50         req->modif   = 0;
51         req->namelen = attr->ObjectName->Length;
52         wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
53         if (class) wine_server_add_data( req, class->Buffer, class->Length );
54         if (!(ret = wine_server_call( req )))
55         {
56             *retkey = reply->hkey;
57             if (dispos) *dispos = reply->created ? REG_CREATED_NEW_KEY : REG_OPENED_EXISTING_KEY;
58         }
59     }
60     SERVER_END_REQ;
61     TRACE("<- 0x%04x\n", *retkey);
62     return ret;
63 }
64
65
66 /******************************************************************************
67  * NtOpenKey [NTDLL.@]
68  * ZwOpenKey [NTDLL.@]
69  *
70  *   OUT        PHANDLE                 retkey (returns 0 when failure)
71  *   IN         ACCESS_MASK             access
72  *   IN         POBJECT_ATTRIBUTES      attr 
73  */
74 NTSTATUS WINAPI NtOpenKey( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
75 {
76     NTSTATUS ret;
77     DWORD len = attr->ObjectName->Length;
78
79     TRACE( "(0x%x,%s,%lx,%p)\n", attr->RootDirectory,
80            debugstr_us(attr->ObjectName), access, retkey );
81
82     if (len > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
83     if (!retkey) return STATUS_INVALID_PARAMETER;
84
85     SERVER_START_REQ( open_key )
86     {
87         req->parent = attr->RootDirectory;
88         req->access = access;
89         wine_server_add_data( req, attr->ObjectName->Buffer, len );
90         ret = wine_server_call( req );
91         *retkey = reply->hkey;
92     }
93     SERVER_END_REQ;
94     TRACE("<- 0x%04x\n", *retkey);
95     return ret;
96 }
97
98
99 /******************************************************************************
100  * NtDeleteKey [NTDLL.@]
101  * ZwDeleteKey [NTDLL.@]
102  */
103 NTSTATUS WINAPI NtDeleteKey( HANDLE hkey )
104 {
105     NTSTATUS ret;
106
107     TRACE( "(%x)\n", hkey );
108
109     SERVER_START_REQ( delete_key )
110     {
111         req->hkey = hkey;
112         ret = wine_server_call( req );
113     }
114     SERVER_END_REQ;
115     return ret;
116 }
117
118
119 /******************************************************************************
120  * NtDeleteValueKey [NTDLL.@]
121  * ZwDeleteValueKey [NTDLL.@]
122  */
123 NTSTATUS WINAPI NtDeleteValueKey( HANDLE hkey, const UNICODE_STRING *name )
124 {
125     NTSTATUS ret;
126
127     TRACE( "(0x%x,%s)\n", hkey, debugstr_us(name) );
128     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
129
130     SERVER_START_REQ( delete_key_value )
131     {
132         req->hkey = hkey;
133         wine_server_add_data( req, name->Buffer, name->Length );
134         ret = wine_server_call( req );
135     }
136     SERVER_END_REQ;
137     return ret;
138 }
139
140
141 /******************************************************************************
142  *     enumerate_key
143  *
144  * Implementation of NtQueryKey and NtEnumerateKey
145  */
146 static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS info_class,
147                                void *info, DWORD length, DWORD *result_len )
148
149 {
150     NTSTATUS ret;
151     void *data_ptr;
152     size_t fixed_size;
153
154     switch(info_class)
155     {
156     case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break;
157     case KeyFullInformation:  data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break;
158     case KeyNodeInformation:  data_ptr = ((KEY_NODE_INFORMATION *)info)->Name;  break;
159     default:
160         FIXME( "Information class %d not implemented\n", info_class );
161         return STATUS_INVALID_PARAMETER;
162     }
163     fixed_size = (char *)data_ptr - (char *)info;
164
165     SERVER_START_REQ( enum_key )
166     {
167         req->hkey       = handle;
168         req->index      = index;
169         req->info_class = info_class;
170         if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
171         if (!(ret = wine_server_call( req )))
172         {
173             LARGE_INTEGER modif;
174
175             RtlSecondsSince1970ToTime( reply->modif, (FILETIME *)&modif );
176
177             switch(info_class)
178             {
179             case KeyBasicInformation:
180                 {
181                     KEY_BASIC_INFORMATION keyinfo;
182                     fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
183                     keyinfo.LastWriteTime = modif;
184                     keyinfo.TitleIndex = 0;
185                     keyinfo.NameLength = reply->namelen;
186                     memcpy( info, &keyinfo, min( length, fixed_size ) );
187                 }
188                 break;
189             case KeyFullInformation:
190                 {
191                     KEY_FULL_INFORMATION keyinfo;
192                     fixed_size = (char *)keyinfo.Class - (char *)&keyinfo;
193                     keyinfo.LastWriteTime = modif;
194                     keyinfo.TitleIndex = 0;
195                     keyinfo.ClassLength = wine_server_reply_size(reply);
196                     keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1;
197                     keyinfo.SubKeys = reply->subkeys;
198                     keyinfo.MaxNameLen = reply->max_subkey;
199                     keyinfo.MaxClassLen = reply->max_class;
200                     keyinfo.Values = reply->values;
201                     keyinfo.MaxValueNameLen = reply->max_value;
202                     keyinfo.MaxValueDataLen = reply->max_data;
203                     memcpy( info, &keyinfo, min( length, fixed_size ) );
204                 }
205                 break;
206             case KeyNodeInformation:
207                 {
208                     KEY_NODE_INFORMATION keyinfo;
209                     fixed_size = (char *)keyinfo.Name - (char *)&keyinfo;
210                     keyinfo.LastWriteTime = modif;
211                     keyinfo.TitleIndex = 0;
212                     keyinfo.ClassLength = max( 0, wine_server_reply_size(reply) - reply->namelen );
213                     keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size + reply->namelen : -1;
214                     keyinfo.NameLength = reply->namelen;
215                     memcpy( info, &keyinfo, min( length, fixed_size ) );
216                 }
217                 break;
218             }
219             *result_len = fixed_size + reply->total;
220             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
221         }
222     }
223     SERVER_END_REQ;
224     return ret;
225 }
226
227
228
229 /******************************************************************************
230  * NtEnumerateKey [NTDLL.@]
231  * ZwEnumerateKey [NTDLL.@]
232  *
233  * NOTES
234  *  the name copied into the buffer is NOT 0-terminated 
235  */
236 NTSTATUS WINAPI NtEnumerateKey( HANDLE handle, ULONG index, KEY_INFORMATION_CLASS info_class,
237                                 void *info, DWORD length, DWORD *result_len )
238 {
239     /* -1 means query key, so avoid it here */
240     if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES;
241     return enumerate_key( handle, index, info_class, info, length, result_len );
242 }
243
244
245 /******************************************************************************
246  * NtQueryKey [NTDLL.@]
247  * ZwQueryKey [NTDLL.@]
248  */
249 NTSTATUS WINAPI NtQueryKey( HANDLE handle, KEY_INFORMATION_CLASS info_class,
250                             void *info, DWORD length, DWORD *result_len )
251 {
252     return enumerate_key( handle, -1, info_class, info, length, result_len );
253 }
254
255
256 /* fill the key value info structure for a specific info class */
257 static void copy_key_value_info( KEY_VALUE_INFORMATION_CLASS info_class, void *info,
258                                  DWORD length, int type, int name_len, int data_len )
259 {
260     switch(info_class)
261     {
262     case KeyValueBasicInformation:
263         {
264             KEY_VALUE_BASIC_INFORMATION keyinfo;
265             keyinfo.TitleIndex = 0;
266             keyinfo.Type       = type;
267             keyinfo.NameLength = name_len;
268             length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
269             memcpy( info, &keyinfo, length );
270             break;
271         }
272     case KeyValueFullInformation:
273         {
274             KEY_VALUE_FULL_INFORMATION keyinfo;
275             keyinfo.TitleIndex = 0;
276             keyinfo.Type       = type;
277             keyinfo.DataOffset = (char *)keyinfo.Name - (char *)&keyinfo + name_len;
278             keyinfo.DataLength = data_len;
279             keyinfo.NameLength = name_len;
280             length = min( length, (char *)keyinfo.Name - (char *)&keyinfo );
281             memcpy( info, &keyinfo, length );
282             break;
283         }
284     case KeyValuePartialInformation:
285         {
286             KEY_VALUE_PARTIAL_INFORMATION keyinfo;
287             keyinfo.TitleIndex = 0;
288             keyinfo.Type       = type;
289             keyinfo.DataLength = data_len;
290             length = min( length, (char *)keyinfo.Data - (char *)&keyinfo );
291             memcpy( info, &keyinfo, length );
292             break;
293         }
294     default:
295         break;
296     }
297 }
298
299
300 /******************************************************************************
301  *  NtEnumerateValueKey [NTDLL.@]
302  *  ZwEnumerateValueKey [NTDLL.@]
303  */
304 NTSTATUS WINAPI NtEnumerateValueKey( HANDLE handle, ULONG index,
305                                      KEY_VALUE_INFORMATION_CLASS info_class,
306                                      void *info, DWORD length, DWORD *result_len )
307 {
308     NTSTATUS ret;
309     void *ptr;
310     size_t fixed_size;
311
312     TRACE( "(0x%x,%lu,%d,%p,%ld)\n", handle, index, info_class, info, length );
313
314     /* compute the length we want to retrieve */
315     switch(info_class)
316     {
317     case KeyValueBasicInformation:   ptr = ((KEY_VALUE_BASIC_INFORMATION *)info)->Name; break;
318     case KeyValueFullInformation:    ptr = ((KEY_VALUE_FULL_INFORMATION *)info)->Name; break;
319     case KeyValuePartialInformation: ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data; break;
320     default:
321         FIXME( "Information class %d not implemented\n", info_class );
322         return STATUS_INVALID_PARAMETER;
323     }
324     fixed_size = (char *)ptr - (char *)info;
325
326     SERVER_START_REQ( enum_key_value )
327     {
328         req->hkey       = handle;
329         req->index      = index;
330         req->info_class = info_class;
331         if (length > fixed_size) wine_server_set_reply( req, ptr, length - fixed_size );
332         if (!(ret = wine_server_call( req )))
333         {
334             copy_key_value_info( info_class, info, length, reply->type, reply->namelen,
335                                  wine_server_reply_size(reply) - reply->namelen );
336             *result_len = fixed_size + reply->total;
337             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
338         }
339     }
340     SERVER_END_REQ;
341     return ret;
342 }
343
344
345 /******************************************************************************
346  * NtQueryValueKey [NTDLL.@]
347  * ZwQueryValueKey [NTDLL.@]
348  *
349  * NOTES
350  *  the name in the KeyValueInformation is never set
351  */
352 NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name,
353                                  KEY_VALUE_INFORMATION_CLASS info_class,
354                                  void *info, DWORD length, DWORD *result_len )
355 {
356     NTSTATUS ret;
357     UCHAR *data_ptr;
358     int fixed_size = 0;
359
360     TRACE( "(0x%x,%s,%d,%p,%ld)\n", handle, debugstr_us(name), info_class, info, length );
361
362     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
363
364     /* compute the length we want to retrieve */
365     switch(info_class)
366     {
367     case KeyValueBasicInformation:
368         fixed_size = (char *)((KEY_VALUE_BASIC_INFORMATION *)info)->Name - (char *)info;
369         data_ptr = NULL;
370         break;
371     case KeyValueFullInformation:
372         data_ptr = (UCHAR *)((KEY_VALUE_FULL_INFORMATION *)info)->Name;
373         fixed_size = (char *)data_ptr - (char *)info;
374         break;
375     case KeyValuePartialInformation:
376         data_ptr = ((KEY_VALUE_PARTIAL_INFORMATION *)info)->Data;
377         fixed_size = (char *)data_ptr - (char *)info;
378         break;
379     default:
380         FIXME( "Information class %d not implemented\n", info_class );
381         return STATUS_INVALID_PARAMETER;
382     }
383
384     SERVER_START_REQ( get_key_value )
385     {
386         req->hkey = handle;
387         wine_server_add_data( req, name->Buffer, name->Length );
388         if (length > fixed_size) wine_server_set_reply( req, data_ptr, length - fixed_size );
389         if (!(ret = wine_server_call( req )))
390         {
391             copy_key_value_info( info_class, info, length, reply->type,
392                                  0, wine_server_reply_size(reply) );
393             *result_len = fixed_size + reply->total;
394             if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
395         }
396     }
397     SERVER_END_REQ;
398     return ret;
399 }
400
401
402 /******************************************************************************
403  *  NtFlushKey  [NTDLL.@]
404  *  ZwFlushKey  [NTDLL.@]
405  */
406 NTSTATUS WINAPI NtFlushKey(HANDLE KeyHandle)
407 {
408         FIXME("(0x%08x) stub!\n",
409         KeyHandle);
410         return 1;
411 }
412
413 /******************************************************************************
414  *  NtLoadKey   [NTDLL.@]
415  *  ZwLoadKey   [NTDLL.@]
416  */
417 NTSTATUS WINAPI NtLoadKey( const OBJECT_ATTRIBUTES *attr, const OBJECT_ATTRIBUTES *file )
418 {
419     FIXME("stub!\n");
420     dump_ObjectAttributes(attr);
421     dump_ObjectAttributes(file);
422     return STATUS_SUCCESS;
423 }
424
425 /******************************************************************************
426  *  NtNotifyChangeKey   [NTDLL.@]
427  *  ZwNotifyChangeKey   [NTDLL.@]
428  */
429 NTSTATUS WINAPI NtNotifyChangeKey(
430         IN HANDLE KeyHandle,
431         IN HANDLE Event,
432         IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
433         IN PVOID ApcContext OPTIONAL,
434         OUT PIO_STATUS_BLOCK IoStatusBlock,
435         IN ULONG CompletionFilter,
436         IN BOOLEAN Asynchroneous,
437         OUT PVOID ChangeBuffer,
438         IN ULONG Length,
439         IN BOOLEAN WatchSubtree)
440 {
441         FIXME("(0x%08x,0x%08x,%p,%p,%p,0x%08lx, 0x%08x,%p,0x%08lx,0x%08x) stub!\n",
442         KeyHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter,
443         Asynchroneous, ChangeBuffer, Length, WatchSubtree);
444         return STATUS_SUCCESS;
445 }
446
447 /******************************************************************************
448  * NtQueryMultipleValueKey [NTDLL]
449  * ZwQueryMultipleValueKey
450  */
451
452 NTSTATUS WINAPI NtQueryMultipleValueKey(
453         HANDLE KeyHandle,
454         PVALENTW ListOfValuesToQuery,
455         ULONG NumberOfItems,
456         PVOID MultipleValueInformation,
457         ULONG Length,
458         PULONG  ReturnLength)
459 {
460         FIXME("(0x%08x,%p,0x%08lx,%p,0x%08lx,%p) stub!\n",
461         KeyHandle, ListOfValuesToQuery, NumberOfItems, MultipleValueInformation,
462         Length,ReturnLength);
463         return STATUS_SUCCESS;
464 }
465
466 /******************************************************************************
467  * NtReplaceKey [NTDLL.@]
468  * ZwReplaceKey [NTDLL.@]
469  */
470 NTSTATUS WINAPI NtReplaceKey(
471         IN POBJECT_ATTRIBUTES ObjectAttributes,
472         IN HANDLE Key,
473         IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
474 {
475         FIXME("(0x%08x),stub!\n", Key);
476         dump_ObjectAttributes(ObjectAttributes);
477         dump_ObjectAttributes(ReplacedObjectAttributes);
478         return STATUS_SUCCESS;
479 }
480 /******************************************************************************
481  * NtRestoreKey [NTDLL.@]
482  * ZwRestoreKey [NTDLL.@]
483  */
484 NTSTATUS WINAPI NtRestoreKey(
485         HANDLE KeyHandle,
486         HANDLE FileHandle,
487         ULONG RestoreFlags)
488 {
489         FIXME("(0x%08x,0x%08x,0x%08lx) stub\n",
490         KeyHandle, FileHandle, RestoreFlags);
491         return STATUS_SUCCESS;
492 }
493 /******************************************************************************
494  * NtSaveKey [NTDLL.@]
495  * ZwSaveKey [NTDLL.@]
496  */
497 NTSTATUS WINAPI NtSaveKey(
498         IN HANDLE KeyHandle,
499         IN HANDLE FileHandle)
500 {
501         FIXME("(0x%08x,0x%08x) stub\n",
502         KeyHandle, FileHandle);
503         return STATUS_SUCCESS;
504 }
505 /******************************************************************************
506  * NtSetInformationKey [NTDLL.@]
507  * ZwSetInformationKey [NTDLL.@]
508  */
509 NTSTATUS WINAPI NtSetInformationKey(
510         IN HANDLE KeyHandle,
511         IN const int KeyInformationClass,
512         IN PVOID KeyInformation,
513         IN ULONG KeyInformationLength)
514 {
515         FIXME("(0x%08x,0x%08x,%p,0x%08lx) stub\n",
516         KeyHandle, KeyInformationClass, KeyInformation, KeyInformationLength);
517         return STATUS_SUCCESS;
518 }
519
520
521 /******************************************************************************
522  * NtSetValueKey [NTDLL.@]
523  * ZwSetValueKey [NTDLL.@]
524  *
525  * NOTES
526  *   win95 does not care about count for REG_SZ and finds out the len by itself (js) 
527  *   NT does definitely care (aj)
528  */
529 NTSTATUS WINAPI NtSetValueKey( HANDLE hkey, const UNICODE_STRING *name, ULONG TitleIndex,
530                                ULONG type, const void *data, ULONG count )
531 {
532     NTSTATUS ret;
533
534     TRACE( "(0x%x,%s,%ld,%p,%ld)\n", hkey, debugstr_us(name), type, data, count );
535
536     if (name->Length > MAX_NAME_LENGTH) return STATUS_BUFFER_OVERFLOW;
537
538     SERVER_START_REQ( set_key_value )
539     {
540         req->hkey    = hkey;
541         req->type    = type;
542         req->namelen = name->Length;
543         wine_server_add_data( req, name->Buffer, name->Length );
544         wine_server_add_data( req, data, count );
545         ret = wine_server_call( req );
546     }
547     SERVER_END_REQ;
548     return ret;
549 }
550
551 /******************************************************************************
552  * NtUnloadKey [NTDLL.@]
553  * ZwUnloadKey [NTDLL.@]
554  */
555 NTSTATUS WINAPI NtUnloadKey(
556         IN HANDLE KeyHandle)
557 {
558         FIXME("(0x%08x) stub\n",
559         KeyHandle);
560         return STATUS_SUCCESS;
561 }
562
563 /******************************************************************************
564  *  RtlFormatCurrentUserKeyPath         [NTDLL.@]
565  */
566 NTSTATUS WINAPI RtlFormatCurrentUserKeyPath(
567         IN OUT PUNICODE_STRING KeyPath)
568 {
569 /*      LPSTR Path = "\\REGISTRY\\USER\\S-1-5-21-0000000000-000000000-0000000000-500";*/
570         LPSTR Path = "\\REGISTRY\\USER\\.DEFAULT";
571         ANSI_STRING AnsiPath;
572
573         FIXME("(%p) stub\n",KeyPath);
574         RtlInitAnsiString(&AnsiPath, Path);
575         return RtlAnsiStringToUnicodeString(KeyPath, &AnsiPath, TRUE);
576 }
577
578 /******************************************************************************
579  *  RtlOpenCurrentUser          [NTDLL.@]
580  *
581  * if we return just HKEY_CURRENT_USER the advapi tries to find a remote
582  * registry (odd handle) and fails
583  *
584  */
585 DWORD WINAPI RtlOpenCurrentUser(
586         IN ACCESS_MASK DesiredAccess, /* [in] */
587         OUT PHANDLE KeyHandle)        /* [out] handle of HKEY_CURRENT_USER */
588 {
589         OBJECT_ATTRIBUTES ObjectAttributes;
590         UNICODE_STRING ObjectName;
591         NTSTATUS ret;
592
593         TRACE("(0x%08lx, %p) stub\n",DesiredAccess, KeyHandle);
594
595         RtlFormatCurrentUserKeyPath(&ObjectName);
596         InitializeObjectAttributes(&ObjectAttributes,&ObjectName,OBJ_CASE_INSENSITIVE,0, NULL);
597         ret = NtOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
598         RtlFreeUnicodeString(&ObjectName);
599         return ret;
600 }