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