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