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