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