Object Manager Patch. This patch continues the work done in the previous patch and...
[reactos.git] / reactos / ntoskrnl / ob / namespc.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/namespc.c
6 * PURPOSE: Manages the system namespace
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES ***************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17
18 /* GLOBALS ****************************************************************/
19
20 POBJECT_TYPE ObDirectoryType = NULL;
21 POBJECT_TYPE ObTypeObjectType = NULL;
22
23 PDIRECTORY_OBJECT NameSpaceRoot = NULL;
24 PDIRECTORY_OBJECT ObpTypeDirectoryObject = NULL;
25 /* FIXME: Move this somewhere else once devicemap support is in */
26 PDEVICE_MAP ObSystemDeviceMap = NULL;
27
28
29 static GENERIC_MAPPING ObpDirectoryMapping = {
30 STANDARD_RIGHTS_READ|DIRECTORY_QUERY|DIRECTORY_TRAVERSE,
31 STANDARD_RIGHTS_WRITE|DIRECTORY_CREATE_OBJECT|DIRECTORY_CREATE_SUBDIRECTORY,
32 STANDARD_RIGHTS_EXECUTE|DIRECTORY_QUERY|DIRECTORY_TRAVERSE,
33 DIRECTORY_ALL_ACCESS};
34
35 static GENERIC_MAPPING ObpTypeMapping = {
36 STANDARD_RIGHTS_READ,
37 STANDARD_RIGHTS_WRITE,
38 STANDARD_RIGHTS_EXECUTE,
39 0x000F0001};
40
41 NTSTATUS
42 STDCALL
43 ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo,
44 PUNICODE_STRING ObjectName,
45 POBJECT_TYPE ObjectType,
46 ULONG ObjectSize,
47 POBJECT_HEADER *ObjectHeader);
48
49 /* FUNCTIONS **************************************************************/
50
51 /*
52 * @implemented
53 */
54 NTSTATUS STDCALL
55 ObReferenceObjectByName(PUNICODE_STRING ObjectPath,
56 ULONG Attributes,
57 PACCESS_STATE PassedAccessState,
58 ACCESS_MASK DesiredAccess,
59 POBJECT_TYPE ObjectType,
60 KPROCESSOR_MODE AccessMode,
61 PVOID ParseContext,
62 PVOID* ObjectPtr)
63 {
64 PVOID Object = NULL;
65 UNICODE_STRING RemainingPath;
66 UNICODE_STRING ObjectName;
67 OBJECT_ATTRIBUTES ObjectAttributes;
68 OBJECT_CREATE_INFORMATION ObjectCreateInfo;
69 NTSTATUS Status;
70
71 PAGED_CODE();
72
73 InitializeObjectAttributes(&ObjectAttributes,
74 ObjectPath,
75 Attributes | OBJ_OPENIF,
76 NULL,
77 NULL);
78
79 /* Capture all the info */
80 DPRINT("Capturing Create Info\n");
81 Status = ObpCaptureObjectAttributes(&ObjectAttributes,
82 AccessMode,
83 ObjectType,
84 &ObjectCreateInfo,
85 &ObjectName);
86 if (!NT_SUCCESS(Status))
87 {
88 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
89 return Status;
90 }
91
92 Status = ObFindObject(&ObjectCreateInfo,
93 &ObjectName,
94 &Object,
95 &RemainingPath,
96 ObjectType);
97
98 if (!NT_SUCCESS(Status))
99 {
100 return(Status);
101 }
102 CHECKPOINT;
103 DPRINT("RemainingPath.Buffer '%S' Object %p\n", RemainingPath.Buffer, Object);
104
105 if (RemainingPath.Buffer != NULL || Object == NULL)
106 {
107 CHECKPOINT;
108 DPRINT("Object %p\n", Object);
109 *ObjectPtr = NULL;
110 RtlFreeUnicodeString (&RemainingPath);
111 return(STATUS_OBJECT_NAME_NOT_FOUND);
112 }
113 *ObjectPtr = Object;
114 RtlFreeUnicodeString (&RemainingPath);
115 return(STATUS_SUCCESS);
116 }
117
118
119 /**********************************************************************
120 * NAME EXPORTED
121 * ObOpenObjectByName
122 *
123 * DESCRIPTION
124 * Obtain a handle to an existing object.
125 *
126 * ARGUMENTS
127 * ObjectAttributes
128 * ...
129 * ObjectType
130 * ...
131 * ParseContext
132 * ...
133 * AccessMode
134 * ...
135 * DesiredAccess
136 * ...
137 * PassedAccessState
138 * ...
139 * Handle
140 * Handle to close.
141 *
142 * RETURN VALUE
143 * Status.
144 *
145 * @implemented
146 */
147 NTSTATUS STDCALL
148 ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
149 IN POBJECT_TYPE ObjectType,
150 IN OUT PVOID ParseContext,
151 IN KPROCESSOR_MODE AccessMode,
152 IN ACCESS_MASK DesiredAccess,
153 IN PACCESS_STATE PassedAccessState,
154 OUT PHANDLE Handle)
155 {
156 UNICODE_STRING RemainingPath;
157 PVOID Object = NULL;
158 UNICODE_STRING ObjectName;
159 OBJECT_CREATE_INFORMATION ObjectCreateInfo;
160 NTSTATUS Status;
161
162 PAGED_CODE();
163
164 DPRINT("ObOpenObjectByName(...)\n");
165
166 /* Capture all the info */
167 DPRINT("Capturing Create Info\n");
168 Status = ObpCaptureObjectAttributes(ObjectAttributes,
169 AccessMode,
170 ObjectType,
171 &ObjectCreateInfo,
172 &ObjectName);
173 if (!NT_SUCCESS(Status))
174 {
175 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
176 return Status;
177 }
178
179 Status = ObFindObject(&ObjectCreateInfo,
180 &ObjectName,
181 &Object,
182 &RemainingPath,
183 ObjectType);
184 if (!NT_SUCCESS(Status))
185 {
186 DPRINT("ObFindObject() failed (Status %lx)\n", Status);
187 return Status;
188 }
189
190 DPRINT("OBject: %x, Remaining Path: %wZ\n", Object, &RemainingPath);
191 if (Object == NULL)
192 {
193 RtlFreeUnicodeString(&RemainingPath);
194 ObpReleaseCapturedAttributes(&ObjectCreateInfo);
195 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
196 return STATUS_UNSUCCESSFUL;
197 }
198 if (RemainingPath.Buffer != NULL)
199 {
200 if (wcschr(RemainingPath.Buffer + 1, L'\\') == NULL)
201 Status = STATUS_OBJECT_NAME_NOT_FOUND;
202 else
203 Status =STATUS_OBJECT_PATH_NOT_FOUND;
204 RtlFreeUnicodeString(&RemainingPath);
205 ObDereferenceObject(Object);
206 ObpReleaseCapturedAttributes(&ObjectCreateInfo);
207 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
208 return Status;
209 }
210
211 Status = ObpCreateHandle(PsGetCurrentProcess(),
212 Object,
213 DesiredAccess,
214 FALSE,
215 Handle);
216
217 ObDereferenceObject(Object);
218 RtlFreeUnicodeString(&RemainingPath);
219 ObpReleaseCapturedAttributes(&ObjectCreateInfo);
220 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
221
222 return Status;
223 }
224
225 VOID
226 STDCALL
227 ObQueryDeviceMapInformation(PEPROCESS Process,
228 PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo)
229 {
230 //KIRQL OldIrql ;
231
232 /*
233 * FIXME: This is an ugly hack for now, to always return the System Device Map
234 * instead of returning the Process Device Map. Not important yet since we don't use it
235 */
236
237 /* FIXME: Acquire the DeviceMap Spinlock */
238 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
239
240 /* Make a copy */
241 DeviceMapInfo->Query.DriveMap = ObSystemDeviceMap->DriveMap;
242 RtlMoveMemory(DeviceMapInfo->Query.DriveType, ObSystemDeviceMap->DriveType, sizeof(ObSystemDeviceMap->DriveType));
243
244 /* FIXME: Release the DeviceMap Spinlock */
245 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
246 }
247
248 VOID
249 ObpAddEntryDirectory(PDIRECTORY_OBJECT Parent,
250 POBJECT_HEADER Header,
251 PWSTR Name)
252 /*
253 * FUNCTION: Add an entry to a namespace directory
254 * ARGUMENTS:
255 * Parent = directory to add in
256 * Header = Header of the object to add the entry for
257 * Name = Name to give the entry
258 */
259 {
260 KIRQL oldlvl;
261
262 Header->NameInfo->Directory = Parent;
263
264 KeAcquireSpinLock(&Parent->Lock, &oldlvl);
265 InsertTailList(&Parent->head, &Header->Entry);
266 KeReleaseSpinLock(&Parent->Lock, oldlvl);
267 }
268
269
270 VOID
271 ObpRemoveEntryDirectory(POBJECT_HEADER Header)
272 /*
273 * FUNCTION: Remove an entry from a namespace directory
274 * ARGUMENTS:
275 * Header = Header of the object to remove
276 */
277 {
278 KIRQL oldlvl;
279
280 DPRINT("ObpRemoveEntryDirectory(Header %x)\n",Header);
281
282 KeAcquireSpinLock(&(Header->NameInfo->Directory->Lock),&oldlvl);
283 if (Header->Entry.Flink && Header->Entry.Blink)
284 {
285 RemoveEntryList(&(Header->Entry));
286 Header->Entry.Flink = Header->Entry.Blink = NULL;
287 }
288 KeReleaseSpinLock(&(Header->NameInfo->Directory->Lock),oldlvl);
289 }
290
291 NTSTATUS
292 STDCALL
293 ObpCreateDirectory(OB_OPEN_REASON Reason,
294 PVOID ObjectBody,
295 PEPROCESS Process,
296 ULONG HandleCount,
297 ACCESS_MASK GrantedAccess)
298 {
299 PDIRECTORY_OBJECT Directory = ObjectBody;
300
301 if (Reason == ObCreateHandle)
302 {
303 InitializeListHead(&Directory->head);
304 KeInitializeSpinLock(&Directory->Lock);
305 }
306
307 return STATUS_SUCCESS;
308 }
309
310 PVOID
311 ObpFindEntryDirectory(PDIRECTORY_OBJECT DirectoryObject,
312 PWSTR Name,
313 ULONG Attributes)
314 {
315 PLIST_ENTRY current = DirectoryObject->head.Flink;
316 POBJECT_HEADER current_obj;
317
318 DPRINT("ObFindEntryDirectory(dir %x, name %S)\n",DirectoryObject, Name);
319
320 if (Name[0]==0)
321 {
322 return(DirectoryObject);
323 }
324 if (Name[0]=='.' && Name[1]==0)
325 {
326 return(DirectoryObject);
327 }
328 if (Name[0]=='.' && Name[1]=='.' && Name[2]==0)
329 {
330 return(BODY_TO_HEADER(DirectoryObject)->NameInfo->Directory);
331 }
332 while (current!=(&(DirectoryObject->head)))
333 {
334 current_obj = CONTAINING_RECORD(current,OBJECT_HEADER,Entry);
335 DPRINT(" Scanning: %S for: %S\n",current_obj->NameInfo->Name.Buffer, Name);
336 if (Attributes & OBJ_CASE_INSENSITIVE)
337 {
338 if (_wcsicmp(current_obj->NameInfo->Name.Buffer, Name)==0)
339 {
340 DPRINT("Found it %x\n",HEADER_TO_BODY(current_obj));
341 return(HEADER_TO_BODY(current_obj));
342 }
343 }
344 else
345 {
346 if ( wcscmp(current_obj->NameInfo->Name.Buffer, Name)==0)
347 {
348 DPRINT("Found it %x\n",HEADER_TO_BODY(current_obj));
349 return(HEADER_TO_BODY(current_obj));
350 }
351 }
352 current = current->Flink;
353 }
354 DPRINT(" Not Found: %s() = NULL\n",__FUNCTION__);
355 return(NULL);
356 }
357
358
359 NTSTATUS STDCALL
360 ObpParseDirectory(PVOID Object,
361 PVOID * NextObject,
362 PUNICODE_STRING FullPath,
363 PWSTR * Path,
364 ULONG Attributes)
365 {
366 PWSTR Start;
367 PWSTR End;
368 PVOID FoundObject;
369
370 DPRINT("ObpParseDirectory(Object %x, Path %x, *Path %S)\n",
371 Object,Path,*Path);
372
373 *NextObject = NULL;
374
375 if ((*Path) == NULL)
376 {
377 return STATUS_UNSUCCESSFUL;
378 }
379
380 Start = *Path;
381 if (*Start == L'\\')
382 Start++;
383
384 End = wcschr(Start, L'\\');
385 if (End != NULL)
386 {
387 *End = 0;
388 }
389
390 FoundObject = ObpFindEntryDirectory(Object, Start, Attributes);
391 if (FoundObject == NULL)
392 {
393 if (End != NULL)
394 {
395 *End = L'\\';
396 }
397 return STATUS_UNSUCCESSFUL;
398 }
399
400 ObReferenceObjectByPointer(FoundObject,
401 STANDARD_RIGHTS_REQUIRED,
402 NULL,
403 UserMode);
404
405 if (End != NULL)
406 {
407 *End = L'\\';
408 *Path = End;
409 }
410 else
411 {
412 *Path = NULL;
413 }
414
415 *NextObject = FoundObject;
416
417 return STATUS_SUCCESS;
418 }
419
420 VOID
421 INIT_FUNCTION
422 ObInit(VOID)
423 {
424 OBJECT_ATTRIBUTES ObjectAttributes;
425 UNICODE_STRING Name;
426 SECURITY_DESCRIPTOR SecurityDescriptor;
427 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
428
429 /* Initialize the security descriptor cache */
430 ObpInitSdCache();
431
432 /* Create the Type Type */
433 DPRINT("Creating Type Type\n");
434 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
435 RtlInitUnicodeString(&Name, L"Type");
436 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
437 ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
438 ObjectTypeInitializer.UseDefaultObject = TRUE;
439 ObjectTypeInitializer.MaintainTypeList = TRUE;
440 ObjectTypeInitializer.PoolType = NonPagedPool;
441 ObjectTypeInitializer.GenericMapping = ObpTypeMapping;
442 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_TYPE);
443 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObTypeObjectType);
444
445 /* Create the Directory Type */
446 DPRINT("Creating Directory Type\n");
447 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
448 RtlInitUnicodeString(&Name, L"Directory");
449 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
450 ObjectTypeInitializer.ValidAccessMask = DIRECTORY_ALL_ACCESS;
451 ObjectTypeInitializer.UseDefaultObject = FALSE;
452 ObjectTypeInitializer.OpenProcedure = ObpCreateDirectory;
453 ObjectTypeInitializer.ParseProcedure = ObpParseDirectory;
454 ObjectTypeInitializer.MaintainTypeList = FALSE;
455 ObjectTypeInitializer.GenericMapping = ObpDirectoryMapping;
456 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(DIRECTORY_OBJECT);
457 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObDirectoryType);
458
459 /* Create security descriptor */
460 RtlCreateSecurityDescriptor(&SecurityDescriptor,
461 SECURITY_DESCRIPTOR_REVISION1);
462 RtlSetOwnerSecurityDescriptor(&SecurityDescriptor,
463 SeAliasAdminsSid,
464 FALSE);
465 RtlSetGroupSecurityDescriptor(&SecurityDescriptor,
466 SeLocalSystemSid,
467 FALSE);
468 RtlSetDaclSecurityDescriptor(&SecurityDescriptor,
469 TRUE,
470 SePublicDefaultDacl,
471 FALSE);
472
473 /* Create root directory */
474 DPRINT("Creating Root Directory\n");
475 InitializeObjectAttributes(&ObjectAttributes,
476 NULL,
477 OBJ_PERMANENT,
478 NULL,
479 &SecurityDescriptor);
480 ObCreateObject(KernelMode,
481 ObDirectoryType,
482 &ObjectAttributes,
483 KernelMode,
484 NULL,
485 sizeof(DIRECTORY_OBJECT),
486 0,
487 0,
488 (PVOID*)&NameSpaceRoot);
489 ObInsertObject((PVOID)NameSpaceRoot,
490 NULL,
491 DIRECTORY_ALL_ACCESS,
492 0,
493 NULL,
494 NULL);
495
496 /* Create '\ObjectTypes' directory */
497 RtlInitUnicodeString(&Name, L"\\ObjectTypes");
498 InitializeObjectAttributes(&ObjectAttributes,
499 &Name,
500 OBJ_PERMANENT,
501 NULL,
502 &SecurityDescriptor);
503 ObCreateObject(KernelMode,
504 ObDirectoryType,
505 &ObjectAttributes,
506 KernelMode,
507 NULL,
508 sizeof(DIRECTORY_OBJECT),
509 0,
510 0,
511 (PVOID*)&ObpTypeDirectoryObject);
512 ObInsertObject((PVOID)ObpTypeDirectoryObject,
513 NULL,
514 DIRECTORY_ALL_ACCESS,
515 0,
516 NULL,
517 NULL);
518
519 /* Insert the two objects we already created but couldn't add */
520 /* NOTE: Uses TypeList & Creator Info in OB 2.0 */
521 ObpAddEntryDirectory(ObpTypeDirectoryObject, BODY_TO_HEADER(ObTypeObjectType), NULL);
522 ObpAddEntryDirectory(ObpTypeDirectoryObject, BODY_TO_HEADER(ObDirectoryType), NULL);
523
524 /* Create 'symbolic link' object type */
525 ObInitSymbolicLinkImplementation();
526
527 /* FIXME: Hack Hack! */
528 ObSystemDeviceMap = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ObSystemDeviceMap), TAG('O', 'b', 'D', 'm'));
529 RtlZeroMemory(ObSystemDeviceMap, sizeof(*ObSystemDeviceMap));
530 }
531
532 NTSTATUS
533 STDCALL
534 ObpCreateTypeObject(POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
535 PUNICODE_STRING TypeName,
536 POBJECT_TYPE *ObjectType)
537 {
538 POBJECT_HEADER Header;
539 POBJECT_TYPE LocalObjectType;
540 NTSTATUS Status;
541
542 DPRINT("ObpCreateTypeObject(ObjectType: %wZ)\n", TypeName);
543
544 /* Allocate the Object */
545 Status = ObpAllocateObject(NULL,
546 TypeName,
547 ObTypeObjectType,
548 OBJECT_ALLOC_SIZE(sizeof(OBJECT_TYPE)),
549 &Header);
550 if (!NT_SUCCESS(Status))
551 {
552 DPRINT1("ObpAllocateObject failed!\n");
553 return Status;
554 }
555
556 LocalObjectType = HEADER_TO_BODY(Header);
557
558 /* Check if this is the first Object Type */
559 if (!ObTypeObjectType)
560 {
561 ObTypeObjectType = LocalObjectType;
562 Header->ObjectType = ObTypeObjectType;
563 }
564
565 /* FIXME: Generate Tag */
566
567 /* Set it up */
568 LocalObjectType->TypeInfo = *ObjectTypeInitializer;
569 LocalObjectType->Name = *TypeName;
570
571 /* Insert it into the Object Directory */
572 if (ObpTypeDirectoryObject)
573 {
574 ObpAddEntryDirectory(ObpTypeDirectoryObject, Header, TypeName->Buffer);
575 ObReferenceObject(ObpTypeDirectoryObject);
576 }
577
578 *ObjectType = LocalObjectType;
579 return Status;
580 }
581
582 /* EOF */