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