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