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