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