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