08c36ed50d6c75e4db2e9e429152410cd627bbe0
[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 {
717 ObDereferenceObject(Parent);
718 return STATUS_OBJECT_NAME_COLLISION;
719 }
720 *Object = Parent;
721 return STATUS_OBJECT_EXISTS;
722 }
723 }
724 else
725 {
726 RtlInitUnicodeString(&RemainingPath, NULL);
727 }
728
729 Header = (POBJECT_HEADER)ExAllocatePoolWithTag(NonPagedPool,
730 OBJECT_ALLOC_SIZE(ObjectSize),
731 Type->Tag);
732 if (Header == NULL) {
733 DPRINT1("Not enough memory!\n");
734 return STATUS_INSUFFICIENT_RESOURCES;
735 }
736
737 RtlZeroMemory(Header, OBJECT_ALLOC_SIZE(ObjectSize));
738
739 /* Initialize the object header */
740 DPRINT("Initalizing header 0x%x (%wZ)\n", Header, &Type->TypeName);
741 Header->HandleCount = 0;
742 Header->RefCount = 1;
743 Header->ObjectType = Type;
744 if (ObjectAttributes != NULL &&
745 ObjectAttributes->Attributes & OBJ_PERMANENT)
746 {
747 Header->Permanent = TRUE;
748 }
749 else
750 {
751 Header->Permanent = FALSE;
752 }
753
754 if (ObjectAttributes != NULL &&
755 ObjectAttributes->Attributes & OBJ_INHERIT)
756 {
757 Header->Inherit = TRUE;
758 }
759 else
760 {
761 Header->Inherit = FALSE;
762 }
763
764 RtlInitUnicodeString(&(Header->Name),NULL);
765
766 DPRINT("Getting Parent and adding entry\n");
767 if (ParentHeader != NULL &&
768 ParentHeader->ObjectType == ObDirectoryType &&
769 RemainingPath.Buffer != NULL)
770 {
771 NamePtr = RemainingPath.Buffer;
772 if (*NamePtr == L'\\')
773 NamePtr++;
774
775 ObpAddEntryDirectory(Parent,
776 Header,
777 NamePtr);
778
779 ObjectAttached = TRUE;
780 }
781
782 DPRINT("About to call Create Routine\n");
783 if (Header->ObjectType->Create != NULL)
784 {
785 DPRINT("Calling %x\n", Header->ObjectType->Create);
786 Status = Header->ObjectType->Create(HEADER_TO_BODY(Header),
787 Parent,
788 RemainingPath.Buffer,
789 ObjectAttributes);
790 if (!NT_SUCCESS(Status))
791 {
792 if (ObjectAttached == TRUE)
793 {
794 ObpRemoveEntryDirectory(Header);
795 }
796 if (Parent)
797 {
798 ObDereferenceObject(Parent);
799 }
800 RtlFreeUnicodeString(&Header->Name);
801 RtlFreeUnicodeString(&RemainingPath);
802 ExFreePool(Header);
803 DPRINT("Create Failed\n");
804 return Status;
805 }
806 }
807 RtlFreeUnicodeString(&RemainingPath);
808
809 SeCaptureSubjectContext(&SubjectContext);
810
811 DPRINT("Security Assignment in progress\n");
812 /* Build the new security descriptor */
813 Status = SeAssignSecurity((ParentHeader != NULL) ? ParentHeader->SecurityDescriptor : NULL,
814 (ObjectAttributes != NULL) ? ObjectAttributes->SecurityDescriptor : NULL,
815 &NewSecurityDescriptor,
816 (Header->ObjectType == ObDirectoryType),
817 &SubjectContext,
818 Header->ObjectType->Mapping,
819 PagedPool);
820 if (NT_SUCCESS(Status))
821 {
822 DPRINT("NewSecurityDescriptor %p\n", NewSecurityDescriptor);
823
824 if (Header->ObjectType->Security != NULL)
825 {
826 /* Call the security method */
827 Status = Header->ObjectType->Security(HEADER_TO_BODY(Header),
828 AssignSecurityDescriptor,
829 0,
830 NewSecurityDescriptor,
831 NULL);
832 }
833 else
834 {
835 /* Assign the security descriptor to the object header */
836 Status = ObpAddSecurityDescriptor(NewSecurityDescriptor,
837 &Header->SecurityDescriptor);
838 DPRINT("Object security descriptor %p\n", Header->SecurityDescriptor);
839 }
840
841 /* Release the new security descriptor */
842 SeDeassignSecurity(&NewSecurityDescriptor);
843 }
844
845 DPRINT("Security Complete\n");
846 SeReleaseSubjectContext(&SubjectContext);
847
848 if (Object != NULL)
849 {
850 *Object = HEADER_TO_BODY(Header);
851 }
852
853 DPRINT("Sucess!\n");
854 return STATUS_SUCCESS;
855 }
856
857
858 /*
859 * FUNCTION: Increments the pointer reference count for a given object
860 * ARGUMENTS:
861 * ObjectBody = Object's body
862 * DesiredAccess = Desired access to the object
863 * ObjectType = Points to the object type structure
864 * AccessMode = Type of access check to perform
865 * RETURNS: Status
866 *
867 * @implemented
868 */
869 NTSTATUS STDCALL
870 ObReferenceObjectByPointer(IN PVOID Object,
871 IN ACCESS_MASK DesiredAccess,
872 IN POBJECT_TYPE ObjectType,
873 IN KPROCESSOR_MODE AccessMode)
874 {
875 POBJECT_HEADER Header;
876
877 /* NOTE: should be possible to reference an object above APC_LEVEL! */
878
879 DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
880 Object,ObjectType);
881
882 Header = BODY_TO_HEADER(Object);
883
884 if (ObjectType != NULL && Header->ObjectType != ObjectType)
885 {
886 DPRINT("Failed %x (type was %x %S) should be %x %S\n",
887 Header,
888 Header->ObjectType,
889 Header->ObjectType->TypeName.Buffer,
890 ObjectType,
891 ObjectType->TypeName.Buffer);
892 return(STATUS_UNSUCCESSFUL);
893 }
894 if (Header->ObjectType == PsProcessType)
895 {
896 DPRINT("Ref p 0x%x refcount %d type %x ",
897 Object, Header->RefCount, PsProcessType);
898 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
899 }
900 if (Header->ObjectType == PsThreadType)
901 {
902 DPRINT("Deref t 0x%x with refcount %d type %x ",
903 Object, Header->RefCount, PsThreadType);
904 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
905 }
906
907 if (Header->RefCount == 0 && !Header->Permanent)
908 {
909 if (Header->ObjectType == PsProcessType)
910 {
911 return STATUS_PROCESS_IS_TERMINATING;
912 }
913 if (Header->ObjectType == PsThreadType)
914 {
915 return STATUS_THREAD_IS_TERMINATING;
916 }
917 return(STATUS_UNSUCCESSFUL);
918 }
919
920 if (1 == InterlockedIncrement(&Header->RefCount) && !Header->Permanent)
921 {
922 KEBUGCHECK(0);
923 }
924
925 return(STATUS_SUCCESS);
926 }
927
928
929 /*
930 * @implemented
931 */
932 NTSTATUS STDCALL
933 ObOpenObjectByPointer(IN POBJECT Object,
934 IN ULONG HandleAttributes,
935 IN PACCESS_STATE PassedAccessState,
936 IN ACCESS_MASK DesiredAccess,
937 IN POBJECT_TYPE ObjectType,
938 IN KPROCESSOR_MODE AccessMode,
939 OUT PHANDLE Handle)
940 {
941 NTSTATUS Status;
942
943 PAGED_CODE();
944
945 DPRINT("ObOpenObjectByPointer()\n");
946
947 Status = ObReferenceObjectByPointer(Object,
948 0,
949 ObjectType,
950 AccessMode);
951 if (!NT_SUCCESS(Status))
952 {
953 return Status;
954 }
955
956 Status = ObCreateHandle(PsGetCurrentProcess(),
957 Object,
958 DesiredAccess,
959 (BOOLEAN)(HandleAttributes & OBJ_INHERIT),
960 Handle);
961
962 ObDereferenceObject(Object);
963
964 return STATUS_SUCCESS;
965 }
966
967
968 static NTSTATUS
969 ObpDeleteObject(POBJECT_HEADER Header)
970 {
971 DPRINT("ObpDeleteObject(Header %p)\n", Header);
972 if (KeGetCurrentIrql() != PASSIVE_LEVEL)
973 {
974 DPRINT("ObpDeleteObject called at an unsupported IRQL. Use ObpDeleteObjectDpcLevel instead.\n");
975 KEBUGCHECK(0);
976 }
977
978 if (Header->SecurityDescriptor != NULL)
979 {
980 ObpRemoveSecurityDescriptor(Header->SecurityDescriptor);
981 }
982
983 if (Header->ObjectType != NULL &&
984 Header->ObjectType->Delete != NULL)
985 {
986 Header->ObjectType->Delete(HEADER_TO_BODY(Header));
987 }
988
989 if (Header->Name.Buffer != NULL)
990 {
991 ObpRemoveEntryDirectory(Header);
992 RtlFreeUnicodeString(&Header->Name);
993 }
994
995 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
996 ExFreePool(Header);
997
998 return(STATUS_SUCCESS);
999 }
1000
1001
1002 VOID STDCALL
1003 ObpDeleteObjectWorkRoutine (IN PVOID Parameter)
1004 {
1005 PRETENTION_CHECK_PARAMS Params = (PRETENTION_CHECK_PARAMS)Parameter;
1006 /* ULONG Tag; */ /* See below */
1007
1008 ASSERT(Params);
1009 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); /* We need PAGED_CODE somewhere... */
1010
1011 /* Turn this on when we have ExFreePoolWithTag
1012 Tag = Params->ObjectHeader->ObjectType->Tag; */
1013 ObpDeleteObject(Params->ObjectHeader);
1014 ExFreePool(Params);
1015 /* ExFreePoolWithTag(Params, Tag); */
1016 }
1017
1018
1019 STATIC NTSTATUS
1020 ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader,
1021 IN LONG OldRefCount)
1022 {
1023 if (ObjectHeader->RefCount < 0)
1024 {
1025 CPRINT("Object %p/%p has invalid reference count (%d)\n",
1026 ObjectHeader, HEADER_TO_BODY(ObjectHeader),
1027 ObjectHeader->RefCount);
1028 KEBUGCHECK(0);
1029 }
1030
1031 if (ObjectHeader->HandleCount < 0)
1032 {
1033 CPRINT("Object %p/%p has invalid handle count (%d)\n",
1034 ObjectHeader, HEADER_TO_BODY(ObjectHeader),
1035 ObjectHeader->HandleCount);
1036 KEBUGCHECK(0);
1037 }
1038
1039
1040 switch (KeGetCurrentIrql ())
1041 {
1042 case PASSIVE_LEVEL:
1043 return ObpDeleteObject (ObjectHeader);
1044
1045 case APC_LEVEL:
1046 case DISPATCH_LEVEL:
1047 {
1048 PRETENTION_CHECK_PARAMS Params;
1049
1050 /*
1051 We use must succeed pool here because if the allocation fails
1052 then we leak memory.
1053 */
1054 Params = (PRETENTION_CHECK_PARAMS)
1055 ExAllocatePoolWithTag(NonPagedPoolMustSucceed,
1056 sizeof(RETENTION_CHECK_PARAMS),
1057 ObjectHeader->ObjectType->Tag);
1058 Params->ObjectHeader = ObjectHeader;
1059 ExInitializeWorkItem(&Params->WorkItem,
1060 ObpDeleteObjectWorkRoutine,
1061 (PVOID)Params);
1062 ExQueueWorkItem(&Params->WorkItem,
1063 CriticalWorkQueue);
1064 }
1065 return STATUS_PENDING;
1066
1067 default:
1068 DPRINT("ObpDeleteObjectDpcLevel called at unsupported "
1069 "IRQL %u!\n", KeGetCurrentIrql());
1070 KEBUGCHECK(0);
1071 return STATUS_UNSUCCESSFUL;
1072 }
1073
1074 return STATUS_SUCCESS;
1075 }
1076
1077
1078 /**********************************************************************
1079 * NAME EXPORTED
1080 * ObfReferenceObject@4
1081 *
1082 * DESCRIPTION
1083 * Increments a given object's reference count and performs
1084 * retention checks.
1085 *
1086 * ARGUMENTS
1087 * ObjectBody = Body of the object.
1088 *
1089 * RETURN VALUE
1090 * None.
1091 *
1092 * @implemented
1093 */
1094 VOID FASTCALL
1095 ObfReferenceObject(IN PVOID Object)
1096 {
1097 POBJECT_HEADER Header;
1098
1099 ASSERT(Object);
1100
1101 Header = BODY_TO_HEADER(Object);
1102
1103 /* No one should be referencing an object once we are deleting it. */
1104 if (InterlockedIncrement(&Header->RefCount) == 1 && !Header->Permanent)
1105 {
1106 KEBUGCHECK(0);
1107 }
1108
1109 }
1110
1111
1112 /**********************************************************************
1113 * NAME EXPORTED
1114 * ObfDereferenceObject@4
1115 *
1116 * DESCRIPTION
1117 * Decrements a given object's reference count and performs
1118 * retention checks.
1119 *
1120 * ARGUMENTS
1121 * ObjectBody = Body of the object.
1122 *
1123 * RETURN VALUE
1124 * None.
1125 *
1126 * @implemented
1127 */
1128 VOID FASTCALL
1129 ObfDereferenceObject(IN PVOID Object)
1130 {
1131 POBJECT_HEADER Header;
1132 LONG NewRefCount;
1133 BOOL Permanent;
1134
1135 ASSERT(Object);
1136
1137 /* Extract the object header. */
1138 Header = BODY_TO_HEADER(Object);
1139 Permanent = Header->Permanent;
1140
1141 /*
1142 Drop our reference and get the new count so we can tell if this was the
1143 last reference.
1144 */
1145 NewRefCount = InterlockedDecrement(&Header->RefCount);
1146 DPRINT("ObfDereferenceObject(0x%x)==%d (%wZ)\n", Object, NewRefCount, &Header->ObjectType->TypeName);
1147 ASSERT(NewRefCount >= 0);
1148
1149 /* Check whether the object can now be deleted. */
1150 if (NewRefCount == 0 &&
1151 !Permanent)
1152 {
1153 ObpDeleteObjectDpcLevel(Header, NewRefCount);
1154 }
1155 }
1156
1157
1158 /**********************************************************************
1159 * NAME EXPORTED
1160 * ObGetObjectPointerCount@4
1161 *
1162 * DESCRIPTION
1163 * Retrieves the pointer(reference) count of the given object.
1164 *
1165 * ARGUMENTS
1166 * ObjectBody = Body of the object.
1167 *
1168 * RETURN VALUE
1169 * Reference count.
1170 *
1171 * @implemented
1172 */
1173 ULONG STDCALL
1174 ObGetObjectPointerCount(PVOID Object)
1175 {
1176 POBJECT_HEADER Header;
1177
1178 PAGED_CODE();
1179
1180 ASSERT(Object);
1181 Header = BODY_TO_HEADER(Object);
1182
1183 return Header->RefCount;
1184 }
1185
1186
1187 /**********************************************************************
1188 * NAME INTERNAL
1189 * ObGetObjectHandleCount@4
1190 *
1191 * DESCRIPTION
1192 * Retrieves the handle count of the given object.
1193 *
1194 * ARGUMENTS
1195 * ObjectBody = Body of the object.
1196 *
1197 * RETURN VALUE
1198 * Reference count.
1199 */
1200 ULONG
1201 ObGetObjectHandleCount(PVOID Object)
1202 {
1203 POBJECT_HEADER Header;
1204
1205 PAGED_CODE();
1206
1207 ASSERT(Object);
1208 Header = BODY_TO_HEADER(Object);
1209
1210 return Header->HandleCount;
1211 }
1212
1213
1214 /**********************************************************************
1215 * NAME EXPORTED
1216 * ObDereferenceObject@4
1217 *
1218 * DESCRIPTION
1219 * Decrements a given object's reference count and performs
1220 * retention checks.
1221 *
1222 * ARGUMENTS
1223 * ObjectBody = Body of the object.
1224 *
1225 * RETURN VALUE
1226 * None.
1227 *
1228 * @implemented
1229 */
1230
1231 #ifdef ObDereferenceObject
1232 #undef ObDereferenceObject
1233 #endif
1234
1235 VOID STDCALL
1236 ObDereferenceObject(IN PVOID Object)
1237 {
1238 ObfDereferenceObject(Object);
1239 }
1240
1241 /* EOF */