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