- Delete named objects from the namespace when the last handle is closed, unless...
[reactos.git] / reactos / ntoskrnl / ob / object.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/object.c
6 * PURPOSE: Implements generic object managment functions
7 *
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 * Skywing (skywing@valhallalegends.com)
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18
19 typedef struct _RETENTION_CHECK_PARAMS
20 {
21 WORK_QUEUE_ITEM WorkItem;
22 POBJECT_HEADER ObjectHeader;
23 } RETENTION_CHECK_PARAMS, *PRETENTION_CHECK_PARAMS;
24
25
26 /* FUNCTIONS ************************************************************/
27
28 NTSTATUS
29 ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
30 IN KPROCESSOR_MODE AccessMode,
31 IN POOL_TYPE PoolType,
32 IN BOOLEAN CaptureIfKernel,
33 OUT PCAPTURED_OBJECT_ATTRIBUTES CapturedObjectAttributes OPTIONAL,
34 OUT PUNICODE_STRING ObjectName OPTIONAL)
35 {
36 OBJECT_ATTRIBUTES AttributesCopy;
37 NTSTATUS Status = STATUS_SUCCESS;
38
39 /* at least one output parameter must be != NULL! */
40 ASSERT(CapturedObjectAttributes != NULL || ObjectName != NULL);
41
42 if(ObjectAttributes == NULL)
43 {
44 /* we're going to return STATUS_SUCCESS! */
45 goto failbasiccleanup;
46 }
47
48 if(AccessMode != KernelMode)
49 {
50 _SEH_TRY
51 {
52 ProbeForRead(ObjectAttributes,
53 sizeof(ObjectAttributes),
54 sizeof(ULONG));
55 /* make a copy on the stack */
56 AttributesCopy = *ObjectAttributes;
57 }
58 _SEH_HANDLE
59 {
60 Status = _SEH_GetExceptionCode();
61 }
62 _SEH_END;
63
64 if(!NT_SUCCESS(Status))
65 {
66 DPRINT1("ObpCaptureObjectAttributes failed to probe object attributes\n");
67 goto failbasiccleanup;
68 }
69 }
70 else if(!CaptureIfKernel)
71 {
72 if(ObjectAttributes->Length == sizeof(OBJECT_ATTRIBUTES))
73 {
74 if(ObjectName != NULL)
75 {
76 /* we don't have to capture any memory, the caller considers the passed data
77 as valid */
78 if(ObjectAttributes->ObjectName != NULL)
79 {
80 *ObjectName = *ObjectAttributes->ObjectName;
81 }
82 else
83 {
84 ObjectName->Length = ObjectName->MaximumLength = 0;
85 ObjectName->Buffer = NULL;
86 }
87 }
88 if(CapturedObjectAttributes != NULL)
89 {
90 CapturedObjectAttributes->RootDirectory = ObjectAttributes->RootDirectory;
91 CapturedObjectAttributes->Attributes = ObjectAttributes->Attributes;
92 CapturedObjectAttributes->SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
93 CapturedObjectAttributes->SecurityQualityOfService = ObjectAttributes->SecurityQualityOfService;
94 }
95
96 return STATUS_SUCCESS;
97 }
98 else
99 {
100 Status = STATUS_INVALID_PARAMETER;
101 goto failbasiccleanup;
102 }
103 }
104 else
105 {
106 AttributesCopy = *ObjectAttributes;
107 }
108
109 /* if Length isn't as expected, bail with an invalid parameter status code so
110 the caller knows he passed garbage... */
111 if(AttributesCopy.Length != sizeof(OBJECT_ATTRIBUTES))
112 {
113 Status = STATUS_INVALID_PARAMETER;
114 goto failbasiccleanup;
115 }
116
117 if(CapturedObjectAttributes != NULL)
118 {
119 CapturedObjectAttributes->RootDirectory = AttributesCopy.RootDirectory;
120 CapturedObjectAttributes->Attributes = AttributesCopy.Attributes;
121
122 if(AttributesCopy.SecurityDescriptor != NULL)
123 {
124 Status = SeCaptureSecurityDescriptor(AttributesCopy.SecurityDescriptor,
125 AccessMode,
126 PoolType,
127 TRUE,
128 &CapturedObjectAttributes->SecurityDescriptor);
129 if(!NT_SUCCESS(Status))
130 {
131 DPRINT1("Unable to capture the security descriptor!!!\n");
132 goto failbasiccleanup;
133 }
134 }
135 else
136 {
137 CapturedObjectAttributes->SecurityDescriptor = NULL;
138 }
139
140 if(AttributesCopy.SecurityQualityOfService != NULL)
141 {
142 SECURITY_QUALITY_OF_SERVICE SafeQoS;
143
144 _SEH_TRY
145 {
146 ProbeForRead(AttributesCopy.SecurityQualityOfService,
147 sizeof(SECURITY_QUALITY_OF_SERVICE),
148 sizeof(ULONG));
149 SafeQoS = *(PSECURITY_QUALITY_OF_SERVICE)AttributesCopy.SecurityQualityOfService;
150 }
151 _SEH_HANDLE
152 {
153 Status = _SEH_GetExceptionCode();
154 }
155 _SEH_END;
156
157 if(!NT_SUCCESS(Status))
158 {
159 DPRINT1("Unable to capture QoS!!!\n");
160 goto failcleanupsdescriptor;
161 }
162
163 if(SafeQoS.Length != sizeof(SECURITY_QUALITY_OF_SERVICE))
164 {
165 DPRINT1("Unable to capture QoS, wrong size!!!\n");
166 Status = STATUS_INVALID_PARAMETER;
167 goto failcleanupsdescriptor;
168 }
169
170 CapturedObjectAttributes->SecurityQualityOfService = ExAllocatePool(PoolType,
171 sizeof(SECURITY_QUALITY_OF_SERVICE));
172 if(CapturedObjectAttributes->SecurityQualityOfService != NULL)
173 {
174 *CapturedObjectAttributes->SecurityQualityOfService = SafeQoS;
175 }
176 else
177 {
178 Status = STATUS_INSUFFICIENT_RESOURCES;
179 goto failcleanupsdescriptor;
180 }
181 }
182 else
183 {
184 CapturedObjectAttributes->SecurityQualityOfService = NULL;
185 }
186 }
187
188 if(ObjectName != NULL)
189 {
190 if(AttributesCopy.ObjectName != NULL)
191 {
192 UNICODE_STRING OriginalCopy;
193
194 if(AccessMode != KernelMode)
195 {
196 _SEH_TRY
197 {
198 /* probe the ObjectName structure and make a local stack copy of it */
199 ProbeForRead(AttributesCopy.ObjectName,
200 sizeof(UNICODE_STRING),
201 sizeof(ULONG));
202 OriginalCopy = *AttributesCopy.ObjectName;
203 if(OriginalCopy.Length > 0)
204 {
205 ProbeForRead(OriginalCopy.Buffer,
206 OriginalCopy.Length,
207 sizeof(WCHAR));
208 }
209 }
210 _SEH_HANDLE
211 {
212 Status = _SEH_GetExceptionCode();
213 }
214 _SEH_END;
215
216 if(NT_SUCCESS(Status))
217 {
218 if(OriginalCopy.Length > 0)
219 {
220 ObjectName->MaximumLength = OriginalCopy.Length + sizeof(WCHAR);
221 ObjectName->Buffer = ExAllocatePool(PoolType,
222 ObjectName->MaximumLength);
223 if(ObjectName->Buffer != NULL)
224 {
225 _SEH_TRY
226 {
227 /* no need to probe OriginalCopy.Buffer again, we already did that
228 when capturing the UNICODE_STRING structure itself */
229 RtlCopyMemory(ObjectName->Buffer, OriginalCopy.Buffer, OriginalCopy.Length);
230 ObjectName->Buffer[OriginalCopy.Length / sizeof(WCHAR)] = L'\0';
231 }
232 _SEH_HANDLE
233 {
234 Status = _SEH_GetExceptionCode();
235 }
236 _SEH_END;
237
238 if(!NT_SUCCESS(Status))
239 {
240 DPRINT1("ObpCaptureObjectAttributes failed to copy the unicode string!\n");
241 }
242 }
243 else
244 {
245 Status = STATUS_INSUFFICIENT_RESOURCES;
246 }
247 }
248 else if(AttributesCopy.RootDirectory != NULL /* && OriginalCopy.Length == 0 */)
249 {
250 /* if the caller specified a root directory, there must be an object name! */
251 Status = STATUS_OBJECT_NAME_INVALID;
252 }
253 }
254 else
255 {
256 DPRINT1("ObpCaptureObjectAttributes failed to probe the object name UNICODE_STRING structure!\n");
257 }
258 }
259 else /* AccessMode == KernelMode */
260 {
261 OriginalCopy = *AttributesCopy.ObjectName;
262
263 if(OriginalCopy.Length > 0)
264 {
265 ObjectName->MaximumLength = OriginalCopy.Length + sizeof(WCHAR);
266 ObjectName->Buffer = ExAllocatePool(PoolType,
267 ObjectName->MaximumLength);
268 if(ObjectName->Buffer != NULL)
269 {
270 RtlCopyMemory(ObjectName->Buffer, OriginalCopy.Buffer, OriginalCopy.Length);
271 ObjectName->Buffer[OriginalCopy.Length / sizeof(WCHAR)] = L'\0';
272 }
273 else
274 {
275 Status = STATUS_INSUFFICIENT_RESOURCES;
276 }
277 }
278 else if(AttributesCopy.RootDirectory != NULL /* && OriginalCopy.Length == 0 */)
279 {
280 /* if the caller specified a root directory, there must be an object name! */
281 Status = STATUS_OBJECT_NAME_INVALID;
282 }
283 }
284 }
285 else
286 {
287 ObjectName->Length = ObjectName->MaximumLength = 0;
288 ObjectName->Buffer = NULL;
289 }
290 }
291
292 if(!NT_SUCCESS(Status))
293 {
294 if(ObjectName->Buffer)
295 {
296 ExFreePool(ObjectName->Buffer);
297 }
298
299 failcleanupsdescriptor:
300 if(CapturedObjectAttributes != NULL)
301 {
302 /* cleanup allocated resources */
303 SeReleaseSecurityDescriptor(CapturedObjectAttributes->SecurityDescriptor,
304 AccessMode,
305 TRUE);
306 }
307
308 failbasiccleanup:
309 if(ObjectName != NULL)
310 {
311 ObjectName->Length = ObjectName->MaximumLength = 0;
312 ObjectName->Buffer = NULL;
313 }
314 if(CapturedObjectAttributes != NULL)
315 {
316 RtlZeroMemory(CapturedObjectAttributes, sizeof(CAPTURED_OBJECT_ATTRIBUTES));
317 }
318 }
319
320 return Status;
321 }
322
323
324 VOID
325 ObpReleaseObjectAttributes(IN PCAPTURED_OBJECT_ATTRIBUTES CapturedObjectAttributes OPTIONAL,
326 IN PUNICODE_STRING ObjectName OPTIONAL,
327 IN KPROCESSOR_MODE AccessMode,
328 IN BOOLEAN CaptureIfKernel)
329 {
330 /* WARNING - You need to pass the same parameters to this function as you passed
331 to ObpCaptureObjectAttributes() to avoid memory leaks */
332 if(AccessMode != KernelMode || CaptureIfKernel)
333 {
334 if(CapturedObjectAttributes != NULL)
335 {
336 if(CapturedObjectAttributes->SecurityDescriptor != NULL)
337 {
338 ExFreePool(CapturedObjectAttributes->SecurityDescriptor);
339 CapturedObjectAttributes->SecurityDescriptor = NULL;
340 }
341 if(CapturedObjectAttributes->SecurityQualityOfService != NULL)
342 {
343 ExFreePool(CapturedObjectAttributes->SecurityQualityOfService);
344 CapturedObjectAttributes->SecurityQualityOfService = NULL;
345 }
346 }
347 if(ObjectName != NULL &&
348 ObjectName->Length > 0)
349 {
350 ExFreePool(ObjectName->Buffer);
351 }
352 }
353 }
354
355
356 /**********************************************************************
357 * NAME PRIVATE
358 * ObFindObject@16
359 *
360 * DESCRIPTION
361 *
362 * ARGUMENTS
363 * ObjectAttributes
364 *
365 * ReturnedObject
366 *
367 * RemainigPath
368 * Pointer to a unicode string that will contain the
369 * remaining path if the function returns successfully.
370 * The caller must free the buffer after use by calling
371 * RtlFreeUnicodeString ().
372 *
373 * ObjectType
374 * Optional pointer to an object type. This is used to
375 * descide if a symbolic link object will be parsed or not.
376 *
377 * RETURN VALUE
378 */
379 NTSTATUS
380 ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes,
381 PVOID* ReturnedObject,
382 PUNICODE_STRING RemainingPath,
383 POBJECT_TYPE ObjectType)
384 {
385 PVOID NextObject;
386 PVOID CurrentObject;
387 PVOID RootObject;
388 POBJECT_HEADER CurrentHeader;
389 NTSTATUS Status;
390 PWSTR current;
391 UNICODE_STRING PathString;
392 ULONG Attributes;
393 PUNICODE_STRING ObjectName;
394
395 PAGED_CODE();
396
397 DPRINT("ObFindObject(ObjectAttributes %x, ReturnedObject %x, "
398 "RemainingPath %x)\n",ObjectAttributes,ReturnedObject,RemainingPath);
399 DPRINT("ObjectAttributes->ObjectName %wZ\n",
400 ObjectAttributes->ObjectName);
401
402 RtlInitUnicodeString (RemainingPath, NULL);
403
404 if (ObjectAttributes->RootDirectory == NULL)
405 {
406 ObReferenceObjectByPointer(NameSpaceRoot,
407 DIRECTORY_TRAVERSE,
408 NULL,
409 UserMode);
410 CurrentObject = NameSpaceRoot;
411 }
412 else
413 {
414 Status = ObReferenceObjectByHandle(ObjectAttributes->RootDirectory,
415 0,
416 NULL,
417 UserMode,
418 &CurrentObject,
419 NULL);
420 if (!NT_SUCCESS(Status))
421 {
422 return Status;
423 }
424 }
425
426 ObjectName = ObjectAttributes->ObjectName;
427 if (ObjectName->Length == 0 ||
428 ObjectName->Buffer[0] == UNICODE_NULL)
429 {
430 *ReturnedObject = CurrentObject;
431 return STATUS_SUCCESS;
432 }
433
434 if (ObjectAttributes->RootDirectory == NULL &&
435 ObjectName->Buffer[0] != L'\\')
436 {
437 ObDereferenceObject (CurrentObject);
438 return STATUS_UNSUCCESSFUL;
439 }
440
441 /* Create a zero-terminated copy of the object name */
442 PathString.Length = ObjectName->Length;
443 PathString.MaximumLength = ObjectName->Length + sizeof(WCHAR);
444 PathString.Buffer = ExAllocatePool (NonPagedPool,
445 PathString.MaximumLength);
446 if (PathString.Buffer == NULL)
447 {
448 ObDereferenceObject (CurrentObject);
449 return STATUS_INSUFFICIENT_RESOURCES;
450 }
451
452 RtlCopyMemory (PathString.Buffer,
453 ObjectName->Buffer,
454 ObjectName->Length);
455 PathString.Buffer[PathString.Length / sizeof(WCHAR)] = UNICODE_NULL;
456
457 current = PathString.Buffer;
458
459 RootObject = CurrentObject;
460 Attributes = ObjectAttributes->Attributes;
461 if (ObjectType == ObSymbolicLinkType)
462 Attributes |= OBJ_OPENLINK;
463
464 while (TRUE)
465 {
466 DPRINT("current %S\n",current);
467 CurrentHeader = BODY_TO_HEADER(CurrentObject);
468
469 DPRINT("Current ObjectType %wZ\n",
470 &CurrentHeader->ObjectType->TypeName);
471
472 if (CurrentHeader->ObjectType->Parse == NULL)
473 {
474 DPRINT("Current object can't parse\n");
475 break;
476 }
477 Status = CurrentHeader->ObjectType->Parse(CurrentObject,
478 &NextObject,
479 &PathString,
480 &current,
481 Attributes);
482 if (Status == STATUS_REPARSE)
483 {
484 /* reparse the object path */
485 NextObject = NameSpaceRoot;
486 current = PathString.Buffer;
487
488 ObReferenceObjectByPointer(NextObject,
489 DIRECTORY_TRAVERSE,
490 NULL,
491 UserMode);
492 }
493
494 if (NextObject == NULL)
495 {
496 break;
497 }
498 ObDereferenceObject(CurrentObject);
499 CurrentObject = NextObject;
500 }
501
502 if (current)
503 RtlpCreateUnicodeString (RemainingPath, current, NonPagedPool);
504 RtlFreeUnicodeString (&PathString);
505 *ReturnedObject = CurrentObject;
506
507 return STATUS_SUCCESS;
508 }
509
510
511 /**********************************************************************
512 * NAME EXPORTED
513 * ObQueryNameString@16
514 *
515 * DESCRIPTION
516 *
517 * ARGUMENTS
518 *
519 * RETURN VALUE
520 *
521 * @implemented
522 */
523 NTSTATUS STDCALL
524 ObQueryNameString (IN PVOID Object,
525 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
526 IN ULONG Length,
527 OUT PULONG ReturnLength)
528 {
529 POBJECT_NAME_INFORMATION LocalInfo;
530 POBJECT_HEADER ObjectHeader;
531 ULONG LocalReturnLength;
532 NTSTATUS Status;
533
534 PAGED_CODE();
535
536 *ReturnLength = 0;
537
538 if (Length < sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR))
539 return STATUS_INVALID_BUFFER_SIZE;
540
541 ObjectNameInfo->Name.MaximumLength = (USHORT)(Length - sizeof(OBJECT_NAME_INFORMATION));
542 ObjectNameInfo->Name.Length = 0;
543 ObjectNameInfo->Name.Buffer =
544 (PWCHAR)((ULONG_PTR)ObjectNameInfo + sizeof(OBJECT_NAME_INFORMATION));
545 ObjectNameInfo->Name.Buffer[0] = 0;
546
547 ObjectHeader = BODY_TO_HEADER(Object);
548
549 if (ObjectHeader->ObjectType != NULL &&
550 ObjectHeader->ObjectType->QueryName != NULL)
551 {
552 DPRINT ("Calling %x\n", ObjectHeader->ObjectType->QueryName);
553 Status = ObjectHeader->ObjectType->QueryName (Object,
554 ObjectNameInfo,
555 Length,
556 ReturnLength);
557 }
558 else if (ObjectHeader->Name.Length > 0 && ObjectHeader->Name.Buffer != NULL)
559 {
560 DPRINT ("Object does not have a 'QueryName' function\n");
561
562 if (ObjectHeader->Parent == NameSpaceRoot)
563 {
564 DPRINT ("Reached the root directory\n");
565 ObjectNameInfo->Name.Length = 0;
566 ObjectNameInfo->Name.Buffer[0] = 0;
567 Status = STATUS_SUCCESS;
568 }
569 else if (ObjectHeader->Parent != NULL)
570 {
571 LocalInfo = ExAllocatePool (NonPagedPool,
572 sizeof(OBJECT_NAME_INFORMATION) +
573 MAX_PATH * sizeof(WCHAR));
574 if (LocalInfo == NULL)
575 return STATUS_INSUFFICIENT_RESOURCES;
576
577 Status = ObQueryNameString (ObjectHeader->Parent,
578 LocalInfo,
579 MAX_PATH * sizeof(WCHAR),
580 &LocalReturnLength);
581 if (!NT_SUCCESS (Status))
582 {
583 ExFreePool (LocalInfo);
584 return Status;
585 }
586
587 Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
588 &LocalInfo->Name);
589
590 ExFreePool (LocalInfo);
591
592 if (!NT_SUCCESS (Status))
593 return Status;
594 }
595
596 DPRINT ("Object path %wZ\n", &ObjectHeader->Name);
597 Status = RtlAppendUnicodeToString (&ObjectNameInfo->Name,
598 L"\\");
599 if (!NT_SUCCESS (Status))
600 return Status;
601
602 Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
603 &ObjectHeader->Name);
604 }
605 else
606 {
607 DPRINT ("Object is unnamed\n");
608
609 ObjectNameInfo->Name.MaximumLength = 0;
610 ObjectNameInfo->Name.Length = 0;
611 ObjectNameInfo->Name.Buffer = NULL;
612
613 Status = STATUS_SUCCESS;
614 }
615
616 if (NT_SUCCESS (Status))
617 {
618 ObjectNameInfo->Name.MaximumLength =
619 (ObjectNameInfo->Name.Length) ? ObjectNameInfo->Name.Length + sizeof(WCHAR) : 0;
620 *ReturnLength =
621 sizeof(OBJECT_NAME_INFORMATION) + ObjectNameInfo->Name.MaximumLength;
622 DPRINT ("Returned object path: %wZ\n", &ObjectNameInfo->Name);
623 }
624
625 return Status;
626 }
627
628
629 /**********************************************************************
630 * NAME EXPORTED
631 * ObCreateObject@36
632 *
633 * DESCRIPTION
634 *
635 * ARGUMENTS
636 *
637 * RETURN VALUE
638 * Status
639 *
640 * @implemented
641 */
642 NTSTATUS STDCALL
643 ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
644 IN POBJECT_TYPE Type,
645 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
646 IN KPROCESSOR_MODE AccessMode,
647 IN OUT PVOID ParseContext OPTIONAL,
648 IN ULONG ObjectSize,
649 IN ULONG PagedPoolCharge OPTIONAL,
650 IN ULONG NonPagedPoolCharge OPTIONAL,
651 OUT PVOID *Object)
652 {
653 PVOID Parent = NULL;
654 UNICODE_STRING RemainingPath;
655 POBJECT_HEADER Header;
656 POBJECT_HEADER ParentHeader = NULL;
657 NTSTATUS Status;
658 BOOLEAN ObjectAttached = FALSE;
659 PWCHAR NamePtr;
660 PSECURITY_DESCRIPTOR NewSecurityDescriptor = NULL;
661 SECURITY_SUBJECT_CONTEXT SubjectContext;
662
663 PAGED_CODE();
664
665 if(ObjectAttributesAccessMode == UserMode && ObjectAttributes != NULL)
666 {
667 Status = STATUS_SUCCESS;
668 _SEH_TRY
669 {
670 ProbeForRead(ObjectAttributes,
671 sizeof(OBJECT_ATTRIBUTES),
672 sizeof(ULONG));
673 }
674 _SEH_HANDLE
675 {
676 Status = _SEH_GetExceptionCode();
677 }
678 _SEH_END;
679
680 if(!NT_SUCCESS(Status))
681 {
682 return Status;
683 }
684 }
685
686 DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n",
687 Type, ObjectAttributes, Object);
688
689 if (Type == NULL)
690 {
691 DPRINT1("Invalid object type!\n");
692 return STATUS_INVALID_PARAMETER;
693 }
694
695 if (ObjectAttributes != NULL &&
696 ObjectAttributes->ObjectName != NULL &&
697 ObjectAttributes->ObjectName->Buffer != NULL)
698 {
699 Status = ObFindObject(ObjectAttributes,
700 &Parent,
701 &RemainingPath,
702 NULL);
703 if (!NT_SUCCESS(Status))
704 {
705 DPRINT1("ObFindObject() failed! (Status 0x%x)\n", Status);
706 return Status;
707 }
708 if (Parent != NULL)
709 {
710 ParentHeader = BODY_TO_HEADER(Parent);
711 }
712 if (ParentHeader &&
713 RemainingPath.Buffer == NULL)
714 {
715 if (ParentHeader->ObjectType != Type
716 || !(ObjectAttributes->Attributes & OBJ_OPENIF))
717 {
718 ObDereferenceObject(Parent);
719 return STATUS_OBJECT_NAME_COLLISION;
720 }
721 *Object = Parent;
722 return STATUS_OBJECT_EXISTS;
723 }
724 }
725 else
726 {
727 RtlInitUnicodeString(&RemainingPath, NULL);
728 }
729
730 Header = (POBJECT_HEADER)ExAllocatePoolWithTag(NonPagedPool,
731 OBJECT_ALLOC_SIZE(ObjectSize),
732 Type->Tag);
733 if (Header == NULL) {
734 DPRINT1("Not enough memory!\n");
735 return STATUS_INSUFFICIENT_RESOURCES;
736 }
737
738 RtlZeroMemory(Header, OBJECT_ALLOC_SIZE(ObjectSize));
739
740 /* Initialize the object header */
741 DPRINT("Initalizing header 0x%x (%wZ)\n", Header, &Type->TypeName);
742 Header->HandleCount = 0;
743 Header->RefCount = 1;
744 Header->ObjectType = Type;
745 if (ObjectAttributes != NULL &&
746 ObjectAttributes->Attributes & OBJ_PERMANENT)
747 {
748 Header->Permanent = TRUE;
749 }
750 else
751 {
752 Header->Permanent = FALSE;
753 }
754
755 if (ObjectAttributes != NULL &&
756 ObjectAttributes->Attributes & OBJ_INHERIT)
757 {
758 Header->Inherit = TRUE;
759 }
760 else
761 {
762 Header->Inherit = FALSE;
763 }
764
765 RtlInitUnicodeString(&(Header->Name),NULL);
766
767 DPRINT("Getting Parent and adding entry\n");
768 if (ParentHeader != NULL &&
769 ParentHeader->ObjectType == ObDirectoryType &&
770 RemainingPath.Buffer != NULL)
771 {
772 NamePtr = RemainingPath.Buffer;
773 if (*NamePtr == L'\\')
774 NamePtr++;
775
776 ObpAddEntryDirectory(Parent,
777 Header,
778 NamePtr);
779
780 ObjectAttached = TRUE;
781 }
782
783 DPRINT("About to call Create Routine\n");
784 if (Header->ObjectType->Create != NULL)
785 {
786 DPRINT("Calling %x\n", Header->ObjectType->Create);
787 Status = Header->ObjectType->Create(HEADER_TO_BODY(Header),
788 Parent,
789 RemainingPath.Buffer,
790 ObjectAttributes);
791 if (!NT_SUCCESS(Status))
792 {
793 if (ObjectAttached == TRUE)
794 {
795 ObpRemoveEntryDirectory(Header);
796 }
797 if (Parent)
798 {
799 ObDereferenceObject(Parent);
800 }
801 RtlFreeUnicodeString(&Header->Name);
802 RtlFreeUnicodeString(&RemainingPath);
803 ExFreePool(Header);
804 DPRINT("Create Failed\n");
805 return Status;
806 }
807 }
808 RtlFreeUnicodeString(&RemainingPath);
809
810 SeCaptureSubjectContext(&SubjectContext);
811
812 DPRINT("Security Assignment in progress\n");
813 /* Build the new security descriptor */
814 Status = SeAssignSecurity((ParentHeader != NULL) ? ParentHeader->SecurityDescriptor : NULL,
815 (ObjectAttributes != NULL) ? ObjectAttributes->SecurityDescriptor : NULL,
816 &NewSecurityDescriptor,
817 (Header->ObjectType == ObDirectoryType),
818 &SubjectContext,
819 Header->ObjectType->Mapping,
820 PagedPool);
821 if (NT_SUCCESS(Status))
822 {
823 DPRINT("NewSecurityDescriptor %p\n", NewSecurityDescriptor);
824
825 if (Header->ObjectType->Security != NULL)
826 {
827 /* Call the security method */
828 Status = Header->ObjectType->Security(HEADER_TO_BODY(Header),
829 AssignSecurityDescriptor,
830 0,
831 NewSecurityDescriptor,
832 NULL);
833 }
834 else
835 {
836 /* Assign the security descriptor to the object header */
837 Status = ObpAddSecurityDescriptor(NewSecurityDescriptor,
838 &Header->SecurityDescriptor);
839 DPRINT("Object security descriptor %p\n", Header->SecurityDescriptor);
840 }
841
842 /* Release the new security descriptor */
843 SeDeassignSecurity(&NewSecurityDescriptor);
844 }
845
846 DPRINT("Security Complete\n");
847 SeReleaseSubjectContext(&SubjectContext);
848
849 if (Object != NULL)
850 {
851 *Object = HEADER_TO_BODY(Header);
852 }
853
854 DPRINT("Sucess!\n");
855 return STATUS_SUCCESS;
856 }
857
858
859 /*
860 * FUNCTION: Increments the pointer reference count for a given object
861 * ARGUMENTS:
862 * ObjectBody = Object's body
863 * DesiredAccess = Desired access to the object
864 * ObjectType = Points to the object type structure
865 * AccessMode = Type of access check to perform
866 * RETURNS: Status
867 *
868 * @implemented
869 */
870 NTSTATUS STDCALL
871 ObReferenceObjectByPointer(IN PVOID Object,
872 IN ACCESS_MASK DesiredAccess,
873 IN POBJECT_TYPE ObjectType,
874 IN KPROCESSOR_MODE AccessMode)
875 {
876 POBJECT_HEADER Header;
877
878 /* NOTE: should be possible to reference an object above APC_LEVEL! */
879
880 DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
881 Object,ObjectType);
882
883 Header = BODY_TO_HEADER(Object);
884
885 if (ObjectType != NULL && Header->ObjectType != ObjectType)
886 {
887 DPRINT("Failed %x (type was %x %S) should be %x %S\n",
888 Header,
889 Header->ObjectType,
890 Header->ObjectType->TypeName.Buffer,
891 ObjectType,
892 ObjectType->TypeName.Buffer);
893 return(STATUS_UNSUCCESSFUL);
894 }
895 if (Header->ObjectType == PsProcessType)
896 {
897 DPRINT("Ref p 0x%x refcount %d type %x ",
898 Object, Header->RefCount, PsProcessType);
899 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
900 }
901 if (Header->ObjectType == PsThreadType)
902 {
903 DPRINT("Deref t 0x%x with refcount %d type %x ",
904 Object, Header->RefCount, PsThreadType);
905 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
906 }
907
908 if (Header->RefCount == 0 && !Header->Permanent)
909 {
910 if (Header->ObjectType == PsProcessType)
911 {
912 return STATUS_PROCESS_IS_TERMINATING;
913 }
914 if (Header->ObjectType == PsThreadType)
915 {
916 return STATUS_THREAD_IS_TERMINATING;
917 }
918 return(STATUS_UNSUCCESSFUL);
919 }
920
921 if (1 == InterlockedIncrement(&Header->RefCount) && !Header->Permanent)
922 {
923 KEBUGCHECK(0);
924 }
925
926 return(STATUS_SUCCESS);
927 }
928
929
930 /*
931 * @implemented
932 */
933 NTSTATUS STDCALL
934 ObOpenObjectByPointer(IN POBJECT Object,
935 IN ULONG HandleAttributes,
936 IN PACCESS_STATE PassedAccessState,
937 IN ACCESS_MASK DesiredAccess,
938 IN POBJECT_TYPE ObjectType,
939 IN KPROCESSOR_MODE AccessMode,
940 OUT PHANDLE Handle)
941 {
942 NTSTATUS Status;
943
944 PAGED_CODE();
945
946 DPRINT("ObOpenObjectByPointer()\n");
947
948 Status = ObReferenceObjectByPointer(Object,
949 0,
950 ObjectType,
951 AccessMode);
952 if (!NT_SUCCESS(Status))
953 {
954 return Status;
955 }
956
957 Status = ObCreateHandle(PsGetCurrentProcess(),
958 Object,
959 DesiredAccess,
960 (BOOLEAN)(HandleAttributes & OBJ_INHERIT),
961 Handle);
962
963 ObDereferenceObject(Object);
964
965 return STATUS_SUCCESS;
966 }
967
968
969 static NTSTATUS
970 ObpDeleteObject(POBJECT_HEADER Header)
971 {
972 DPRINT("ObpDeleteObject(Header %p)\n", Header);
973 if (KeGetCurrentIrql() != PASSIVE_LEVEL)
974 {
975 DPRINT("ObpDeleteObject called at an unsupported IRQL. Use ObpDeleteObjectDpcLevel instead.\n");
976 KEBUGCHECK(0);
977 }
978
979 if (Header->SecurityDescriptor != NULL)
980 {
981 ObpRemoveSecurityDescriptor(Header->SecurityDescriptor);
982 }
983
984 if (Header->ObjectType != NULL &&
985 Header->ObjectType->Delete != NULL)
986 {
987 Header->ObjectType->Delete(HEADER_TO_BODY(Header));
988 }
989
990 if (Header->Name.Buffer != NULL)
991 {
992 ObpRemoveEntryDirectory(Header);
993 RtlFreeUnicodeString(&Header->Name);
994 }
995
996 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
997 ExFreePool(Header);
998
999 return(STATUS_SUCCESS);
1000 }
1001
1002
1003 VOID STDCALL
1004 ObpDeleteObjectWorkRoutine (IN PVOID Parameter)
1005 {
1006 PRETENTION_CHECK_PARAMS Params = (PRETENTION_CHECK_PARAMS)Parameter;
1007 /* ULONG Tag; */ /* See below */
1008
1009 ASSERT(Params);
1010 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); /* We need PAGED_CODE somewhere... */
1011
1012 /* Turn this on when we have ExFreePoolWithTag
1013 Tag = Params->ObjectHeader->ObjectType->Tag; */
1014 ObpDeleteObject(Params->ObjectHeader);
1015 ExFreePool(Params);
1016 /* ExFreePoolWithTag(Params, Tag); */
1017 }
1018
1019
1020 STATIC NTSTATUS
1021 ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader,
1022 IN LONG OldRefCount)
1023 {
1024 #if 0
1025 if (ObjectHeader->RefCount < 0)
1026 {
1027 CPRINT("Object %p/%p has invalid reference count (%d)\n",
1028 ObjectHeader, HEADER_TO_BODY(ObjectHeader),
1029 ObjectHeader->RefCount);
1030 KEBUGCHECK(0);
1031 }
1032
1033 if (ObjectHeader->HandleCount < 0)
1034 {
1035 CPRINT("Object %p/%p has invalid handle count (%d)\n",
1036 ObjectHeader, HEADER_TO_BODY(ObjectHeader),
1037 ObjectHeader->HandleCount);
1038 KEBUGCHECK(0);
1039 }
1040 #endif
1041
1042
1043 switch (KeGetCurrentIrql ())
1044 {
1045 case PASSIVE_LEVEL:
1046 return ObpDeleteObject (ObjectHeader);
1047
1048 case APC_LEVEL:
1049 case DISPATCH_LEVEL:
1050 {
1051 PRETENTION_CHECK_PARAMS Params;
1052
1053 /*
1054 We use must succeed pool here because if the allocation fails
1055 then we leak memory.
1056 */
1057 Params = (PRETENTION_CHECK_PARAMS)
1058 ExAllocatePoolWithTag(NonPagedPoolMustSucceed,
1059 sizeof(RETENTION_CHECK_PARAMS),
1060 ObjectHeader->ObjectType->Tag);
1061 Params->ObjectHeader = ObjectHeader;
1062 ExInitializeWorkItem(&Params->WorkItem,
1063 ObpDeleteObjectWorkRoutine,
1064 (PVOID)Params);
1065 ExQueueWorkItem(&Params->WorkItem,
1066 CriticalWorkQueue);
1067 }
1068 return STATUS_PENDING;
1069
1070 default:
1071 DPRINT("ObpDeleteObjectDpcLevel called at unsupported "
1072 "IRQL %u!\n", KeGetCurrentIrql());
1073 KEBUGCHECK(0);
1074 return STATUS_UNSUCCESSFUL;
1075 }
1076
1077 return STATUS_SUCCESS;
1078 }
1079
1080
1081 /**********************************************************************
1082 * NAME EXPORTED
1083 * ObfReferenceObject@4
1084 *
1085 * DESCRIPTION
1086 * Increments a given object's reference count and performs
1087 * retention checks.
1088 *
1089 * ARGUMENTS
1090 * ObjectBody = Body of the object.
1091 *
1092 * RETURN VALUE
1093 * None.
1094 *
1095 * @implemented
1096 */
1097 VOID FASTCALL
1098 ObfReferenceObject(IN PVOID Object)
1099 {
1100 POBJECT_HEADER Header;
1101
1102 ASSERT(Object);
1103
1104 Header = BODY_TO_HEADER(Object);
1105
1106 /* No one should be referencing an object once we are deleting it. */
1107 if (InterlockedIncrement(&Header->RefCount) == 1 && !Header->Permanent)
1108 {
1109 KEBUGCHECK(0);
1110 }
1111
1112 }
1113
1114
1115 /**********************************************************************
1116 * NAME EXPORTED
1117 * ObfDereferenceObject@4
1118 *
1119 * DESCRIPTION
1120 * Decrements a given object's reference count and performs
1121 * retention checks.
1122 *
1123 * ARGUMENTS
1124 * ObjectBody = Body of the object.
1125 *
1126 * RETURN VALUE
1127 * None.
1128 *
1129 * @implemented
1130 */
1131 VOID FASTCALL
1132 ObfDereferenceObject(IN PVOID Object)
1133 {
1134 POBJECT_HEADER Header;
1135 LONG NewRefCount;
1136 BOOL Permanent;
1137
1138 ASSERT(Object);
1139
1140 /* Extract the object header. */
1141 Header = BODY_TO_HEADER(Object);
1142 Permanent = Header->Permanent;
1143
1144 /*
1145 Drop our reference and get the new count so we can tell if this was the
1146 last reference.
1147 */
1148 NewRefCount = InterlockedDecrement(&Header->RefCount);
1149 DPRINT("ObfDereferenceObject(0x%x)==%d (%wZ)\n", Object, NewRefCount, &Header->ObjectType->TypeName);
1150 ASSERT(NewRefCount >= 0);
1151
1152 /* Check whether the object can now be deleted. */
1153 if (NewRefCount == 0 &&
1154 !Permanent)
1155 {
1156 ObpDeleteObjectDpcLevel(Header, NewRefCount);
1157 }
1158 }
1159
1160
1161 /**********************************************************************
1162 * NAME EXPORTED
1163 * ObGetObjectPointerCount@4
1164 *
1165 * DESCRIPTION
1166 * Retrieves the pointer(reference) count of the given object.
1167 *
1168 * ARGUMENTS
1169 * ObjectBody = Body of the object.
1170 *
1171 * RETURN VALUE
1172 * Reference count.
1173 *
1174 * @implemented
1175 */
1176 ULONG STDCALL
1177 ObGetObjectPointerCount(PVOID Object)
1178 {
1179 POBJECT_HEADER Header;
1180
1181 PAGED_CODE();
1182
1183 ASSERT(Object);
1184 Header = BODY_TO_HEADER(Object);
1185
1186 return Header->RefCount;
1187 }
1188
1189
1190 /**********************************************************************
1191 * NAME INTERNAL
1192 * ObGetObjectHandleCount@4
1193 *
1194 * DESCRIPTION
1195 * Retrieves the handle count of the given object.
1196 *
1197 * ARGUMENTS
1198 * ObjectBody = Body of the object.
1199 *
1200 * RETURN VALUE
1201 * Reference count.
1202 */
1203 ULONG
1204 ObGetObjectHandleCount(PVOID Object)
1205 {
1206 POBJECT_HEADER Header;
1207
1208 PAGED_CODE();
1209
1210 ASSERT(Object);
1211 Header = BODY_TO_HEADER(Object);
1212
1213 return Header->HandleCount;
1214 }
1215
1216
1217 /**********************************************************************
1218 * NAME EXPORTED
1219 * ObDereferenceObject@4
1220 *
1221 * DESCRIPTION
1222 * Decrements a given object's reference count and performs
1223 * retention checks.
1224 *
1225 * ARGUMENTS
1226 * ObjectBody = Body of the object.
1227 *
1228 * RETURN VALUE
1229 * None.
1230 *
1231 * @implemented
1232 */
1233
1234 #ifdef ObDereferenceObject
1235 #undef ObDereferenceObject
1236 #endif
1237
1238 VOID STDCALL
1239 ObDereferenceObject(IN PVOID Object)
1240 {
1241 ObfDereferenceObject(Object);
1242 }
1243
1244 /* EOF */