Use Unicode strings in key objects.
[reactos.git] / reactos / ntoskrnl / cm / regobj.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/regobj.c
5 * PURPOSE: Registry object manipulation routines.
6 * UPDATE HISTORY:
7 */
8
9 #include <ddk/ntddk.h>
10 #include <roscfg.h>
11 #include <internal/ob.h>
12 #include <limits.h>
13 #include <string.h>
14 #include <internal/pool.h>
15 #include <internal/registry.h>
16 #include <ntos/minmax.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 #include "cm.h"
22
23
24 static NTSTATUS
25 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive,
26 PKEY_CELL KeyCell,
27 PUNICODE_STRING TargetPath);
28
29 /* FUNCTONS *****************************************************************/
30
31 NTSTATUS STDCALL
32 CmiObjectParse(PVOID ParsedObject,
33 PVOID *NextObject,
34 PUNICODE_STRING FullPath,
35 PWSTR *Path,
36 ULONG Attributes)
37 {
38 BLOCK_OFFSET BlockOffset;
39 PKEY_OBJECT FoundObject;
40 PKEY_OBJECT ParsedKey;
41 PKEY_CELL SubKeyCell;
42 CHAR cPath[MAX_PATH];
43 NTSTATUS Status;
44 PWSTR StartPtr;
45 PWSTR EndPtr;
46 ULONG Length;
47 UNICODE_STRING LinkPath;
48 UNICODE_STRING TargetPath;
49
50 ParsedKey = ParsedObject;
51
52 VERIFY_KEY_OBJECT(ParsedKey);
53
54 *NextObject = NULL;
55
56 if ((*Path) == NULL)
57 {
58 DPRINT("*Path is NULL\n");
59 return STATUS_UNSUCCESSFUL;
60 }
61
62 DPRINT("Path '%S'\n", *Path);
63
64 /* Extract relevant path name */
65 StartPtr = *Path;
66 if (*StartPtr == L'\\')
67 StartPtr++;
68
69 EndPtr = wcschr(StartPtr, L'\\');
70 if (EndPtr != NULL)
71 Length = ((PCHAR)EndPtr - (PCHAR)StartPtr) / sizeof(WCHAR);
72 else
73 Length = wcslen(StartPtr);
74
75 wcstombs(cPath, StartPtr, Length);
76 cPath[Length] = 0;
77
78
79 FoundObject = CmiScanKeyList(ParsedKey, cPath, Attributes);
80 if (FoundObject == NULL)
81 {
82 Status = CmiScanForSubKey(ParsedKey->RegistryHive,
83 ParsedKey->KeyCell,
84 &SubKeyCell,
85 &BlockOffset,
86 cPath,
87 0,
88 Attributes);
89 if (!NT_SUCCESS(Status) || (SubKeyCell == NULL))
90 {
91 return(STATUS_UNSUCCESSFUL);
92 }
93
94 if ((SubKeyCell->Flags & REG_KEY_LINK_CELL) &&
95 !((Attributes & OBJ_OPENLINK) && (EndPtr == NULL) /*(end == NULL)*/))
96 {
97 RtlInitUnicodeString(&LinkPath, NULL);
98 Status = CmiGetLinkTarget(ParsedKey->RegistryHive,
99 SubKeyCell,
100 &LinkPath);
101 if (NT_SUCCESS(Status))
102 {
103 DPRINT("LinkPath '%wZ'\n", &LinkPath);
104
105 /* build new FullPath for reparsing */
106 TargetPath.MaximumLength = LinkPath.MaximumLength;
107 if (EndPtr != NULL)
108 {
109 TargetPath.MaximumLength += (wcslen(EndPtr) * sizeof(WCHAR));
110 }
111 TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
112 TargetPath.Buffer = ExAllocatePool(NonPagedPool,
113 TargetPath.MaximumLength);
114 wcscpy(TargetPath.Buffer, LinkPath.Buffer);
115 if (EndPtr != NULL)
116 {
117 wcscat(TargetPath.Buffer, EndPtr);
118 }
119
120 RtlFreeUnicodeString(FullPath);
121 RtlFreeUnicodeString(&LinkPath);
122 FullPath->Length = TargetPath.Length;
123 FullPath->MaximumLength = TargetPath.MaximumLength;
124 FullPath->Buffer = TargetPath.Buffer;
125
126 DPRINT("FullPath '%wZ'\n", FullPath);
127
128 /* reinitialize Path for reparsing */
129 *Path = FullPath->Buffer;
130
131 *NextObject = NULL;
132 return(STATUS_REPARSE);
133 }
134 }
135
136 /* Create new key object and put into linked list */
137 DPRINT("CmiObjectParse: %s\n", cPath);
138 Status = ObCreateObject(NULL,
139 STANDARD_RIGHTS_REQUIRED,
140 NULL,
141 CmiKeyType,
142 (PVOID*)&FoundObject);
143 if (!NT_SUCCESS(Status))
144 {
145 return(Status);
146 }
147
148 FoundObject->Flags = 0;
149
150 FoundObject->Name.Length = Length * sizeof(WCHAR);
151 FoundObject->Name.MaximumLength = FoundObject->Name.Length + sizeof(WCHAR);
152 FoundObject->Name.Buffer = ExAllocatePool(NonPagedPool, FoundObject->Name.MaximumLength);
153 RtlCopyMemory(FoundObject->Name.Buffer, StartPtr, FoundObject->Name.Length);
154 FoundObject->Name.Buffer[FoundObject->Name.Length / sizeof(WCHAR)] = 0;
155
156 FoundObject->KeyCell = SubKeyCell;
157 FoundObject->BlockOffset = BlockOffset;
158 FoundObject->RegistryHive = ParsedKey->RegistryHive;
159 CmiAddKeyToList(ParsedKey, FoundObject);
160 DPRINT("Created object 0x%x\n", FoundObject);
161 }
162 else
163 {
164 if ((FoundObject->KeyCell->Flags & REG_KEY_LINK_CELL) &&
165 !((Attributes & OBJ_OPENLINK) && (EndPtr == NULL)/*(end == NULL)*/))
166 {
167 DPRINT("Found link\n");
168
169 RtlInitUnicodeString(&LinkPath, NULL);
170 Status = CmiGetLinkTarget(FoundObject->RegistryHive,
171 FoundObject->KeyCell,
172 &LinkPath);
173 if (NT_SUCCESS(Status))
174 {
175 DPRINT("LinkPath '%wZ'\n", &LinkPath);
176
177 /* build new FullPath for reparsing */
178 TargetPath.MaximumLength = LinkPath.MaximumLength;
179 if (EndPtr != NULL)
180 {
181 TargetPath.MaximumLength += (wcslen(EndPtr) * sizeof(WCHAR));
182 }
183 TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
184 TargetPath.Buffer = ExAllocatePool(NonPagedPool,
185 TargetPath.MaximumLength);
186 wcscpy(TargetPath.Buffer, LinkPath.Buffer);
187 if (EndPtr != NULL)
188 {
189 wcscat(TargetPath.Buffer, EndPtr);
190 }
191
192 RtlFreeUnicodeString(FullPath);
193 RtlFreeUnicodeString(&LinkPath);
194 FullPath->Length = TargetPath.Length;
195 FullPath->MaximumLength = TargetPath.MaximumLength;
196 FullPath->Buffer = TargetPath.Buffer;
197
198 DPRINT("FullPath '%wZ'\n", FullPath);
199
200 /* reinitialize Path for reparsing */
201 *Path = FullPath->Buffer;
202
203 *NextObject = NULL;
204 return(STATUS_REPARSE);
205 }
206 }
207
208 ObReferenceObjectByPointer(FoundObject,
209 STANDARD_RIGHTS_REQUIRED,
210 NULL,
211 UserMode);
212 }
213
214 DPRINT("CmiObjectParse: %s\n", FoundObject->Name);
215
216 *Path = EndPtr;
217
218 VERIFY_KEY_OBJECT(FoundObject);
219
220 *NextObject = FoundObject;
221
222 return(STATUS_SUCCESS);
223 }
224
225
226 NTSTATUS STDCALL
227 CmiObjectCreate(PVOID ObjectBody,
228 PVOID Parent,
229 PWSTR RemainingPath,
230 POBJECT_ATTRIBUTES ObjectAttributes)
231 {
232 PKEY_OBJECT KeyObject = ObjectBody;
233 PWSTR Start;
234
235 KeyObject->ParentKey = Parent;
236 if (RemainingPath)
237 {
238 Start = RemainingPath;
239 if(*Start == L'\\')
240 Start++;
241 RtlCreateUnicodeString(&KeyObject->Name,
242 Start);
243 }
244 else
245 {
246 RtlInitUnicodeString(&KeyObject->Name,
247 NULL);
248 }
249
250 return STATUS_SUCCESS;
251 }
252
253
254 VOID STDCALL
255 CmiObjectDelete(PVOID DeletedObject)
256 {
257 PKEY_OBJECT KeyObject;
258
259 DPRINT("Delete object key\n");
260
261 KeyObject = (PKEY_OBJECT) DeletedObject;
262
263 if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject)))
264 {
265 DPRINT1("Key not found in parent list ???\n");
266 }
267
268 RtlFreeUnicodeString(&KeyObject->Name);
269
270 if (KeyObject->Flags & KO_MARKED_FOR_DELETE)
271 {
272 DPRINT("delete really key\n");
273
274 CmiRemoveSubKey(KeyObject->RegistryHive,
275 KeyObject->ParentKey,
276 KeyObject);
277
278 if (!IsVolatileHive(KeyObject->RegistryHive))
279 {
280 CmiSyncHives();
281 }
282 }
283 }
284
285
286 NTSTATUS STDCALL
287 CmiObjectSecurity(PVOID ObjectBody,
288 SECURITY_OPERATION_CODE OperationCode,
289 SECURITY_INFORMATION SecurityInformation,
290 PSECURITY_DESCRIPTOR SecurityDescriptor,
291 PULONG BufferLength)
292 {
293 DPRINT1("CmiObjectSecurity() called\n");
294
295 return(STATUS_SUCCESS);
296 }
297
298
299 VOID
300 CmiAddKeyToList(PKEY_OBJECT ParentKey,
301 PKEY_OBJECT NewKey)
302 {
303 KIRQL OldIrql;
304
305 DPRINT("ParentKey %.08x\n", ParentKey);
306
307 KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
308
309 if (ParentKey->SizeOfSubKeys <= ParentKey->NumberOfSubKeys)
310 {
311 PKEY_OBJECT *tmpSubKeys = ExAllocatePool(NonPagedPool,
312 (ParentKey->NumberOfSubKeys + 1) * sizeof(ULONG));
313
314 if (ParentKey->NumberOfSubKeys > 0)
315 {
316 RtlCopyMemory (tmpSubKeys,
317 ParentKey->SubKeys,
318 ParentKey->NumberOfSubKeys * sizeof(ULONG));
319 }
320
321 if (ParentKey->SubKeys)
322 ExFreePool(ParentKey->SubKeys);
323
324 ParentKey->SubKeys = tmpSubKeys;
325 ParentKey->SizeOfSubKeys = ParentKey->NumberOfSubKeys + 1;
326 }
327
328 /* FIXME: Please maintain the list in alphabetic order */
329 /* to allow a dichotomic search */
330 ParentKey->SubKeys[ParentKey->NumberOfSubKeys++] = NewKey;
331
332 DPRINT("Reference parent key: 0x%x\n", ParentKey);
333
334 ObReferenceObjectByPointer(ParentKey,
335 STANDARD_RIGHTS_REQUIRED,
336 NULL,
337 UserMode);
338 NewKey->ParentKey = ParentKey;
339 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
340 }
341
342
343 NTSTATUS
344 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove)
345 {
346 PKEY_OBJECT ParentKey;
347 KIRQL OldIrql;
348 DWORD Index;
349
350 ParentKey = KeyToRemove->ParentKey;
351 KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
352 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
353 for (Index = 0; Index < ParentKey->NumberOfSubKeys; Index++)
354 {
355 if (ParentKey->SubKeys[Index] == KeyToRemove)
356 {
357 if (Index < ParentKey->NumberOfSubKeys-1)
358 RtlMoveMemory(&ParentKey->SubKeys[Index],
359 &ParentKey->SubKeys[Index + 1],
360 (ParentKey->NumberOfSubKeys - Index - 1) * sizeof(PKEY_OBJECT));
361 ParentKey->NumberOfSubKeys--;
362 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
363
364 DPRINT("Dereference parent key: 0x%x\n", ParentKey);
365
366 ObDereferenceObject(ParentKey);
367 return STATUS_SUCCESS;
368 }
369 }
370 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
371
372 return STATUS_UNSUCCESSFUL;
373 }
374
375
376 PKEY_OBJECT
377 CmiScanKeyList(PKEY_OBJECT Parent,
378 PCHAR KeyName,
379 ULONG Attributes)
380 {
381 PKEY_OBJECT CurKey;
382 KIRQL OldIrql;
383 ULONG Index;
384 UNICODE_STRING UName;
385
386 DPRINT("Scanning key list for: %s (Parent: %wZ)\n",
387 KeyName, &Parent->Name);
388
389 RtlCreateUnicodeStringFromAsciiz(&UName,
390 KeyName);
391
392 KeAcquireSpinLock(&CmiKeyListLock, &OldIrql);
393 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
394 for (Index=0; Index < Parent->NumberOfSubKeys; Index++)
395 {
396 CurKey = Parent->SubKeys[Index];
397 if (Attributes & OBJ_CASE_INSENSITIVE)
398 {
399 if ((UName.Length == CurKey->Name.Length)
400 && (_wcsicmp(UName.Buffer, CurKey->Name.Buffer) == 0))
401 {
402 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
403 RtlFreeUnicodeString(&UName);
404 return CurKey;
405 }
406 }
407 else
408 {
409 if ((UName.Length == CurKey->Name.Length)
410 && (wcscmp(UName.Buffer, CurKey->Name.Buffer) == 0))
411 {
412 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
413 RtlFreeUnicodeString(&UName);
414 return CurKey;
415 }
416 }
417 }
418 KeReleaseSpinLock(&CmiKeyListLock, OldIrql);
419 RtlFreeUnicodeString(&UName);
420
421 return NULL;
422 }
423
424
425 static NTSTATUS
426 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive,
427 PKEY_CELL KeyCell,
428 PUNICODE_STRING TargetPath)
429 {
430 UNICODE_STRING LinkName = UNICODE_STRING_INITIALIZER(L"SymbolicLinkValue");
431 PVALUE_CELL ValueCell;
432 PDATA_CELL DataCell;
433 NTSTATUS Status;
434
435 DPRINT("CmiGetLinkTarget() called\n");
436
437 /* Get Value block of interest */
438 Status = CmiScanKeyForValue(RegistryHive,
439 KeyCell,
440 &LinkName,
441 &ValueCell,
442 NULL);
443 if (!NT_SUCCESS(Status))
444 {
445 DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status);
446 return(Status);
447 }
448
449 if (ValueCell->DataType != REG_LINK)
450 {
451 DPRINT1("Type != REG_LINK\n!");
452 return(STATUS_UNSUCCESSFUL);
453 }
454
455 if (TargetPath->Buffer == NULL && TargetPath->MaximumLength == 0)
456 {
457 TargetPath->Length = 0;
458 TargetPath->MaximumLength = ValueCell->DataSize + sizeof(WCHAR);
459 TargetPath->Buffer = ExAllocatePool(NonPagedPool,
460 TargetPath->MaximumLength);
461 }
462
463 TargetPath->Length = min(TargetPath->MaximumLength - sizeof(WCHAR),
464 (ULONG) ValueCell->DataSize);
465
466 if (ValueCell->DataSize > 0)
467 {
468 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
469 RtlCopyMemory(TargetPath->Buffer,
470 DataCell->Data,
471 TargetPath->Length);
472 TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0;
473 }
474 else
475 {
476 RtlCopyMemory(TargetPath->Buffer,
477 &ValueCell->DataOffset,
478 TargetPath->Length);
479 TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0;
480 }
481
482 DPRINT("TargetPath '%wZ'\n", TargetPath);
483
484 return(STATUS_SUCCESS);
485 }
486
487 /* EOF */