dfe1b772a97f35aec69f994175b46999a1844c75
[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 PROS_OBJECT_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 PROS_OBJECT_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 = ((OB_ROS_PARSE_METHOD)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 PROS_OBJECT_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 TRUE, //fixme
463 ObjectNameInfo,
464 Length,
465 ReturnLength);
466
467 /* Return the status */
468 return Status;
469 }
470
471 /* Check if the object doesn't even have a name */
472 if (!LocalInfo || !LocalInfo->Name.Buffer)
473 {
474 /* We're returning the name structure */
475 DPRINT("Nameless Object\n");
476 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
477
478 /* Check if we were given enough space */
479 if (*ReturnLength > Length)
480 {
481 DPRINT1("Not enough buffer space\n");
482 return STATUS_INFO_LENGTH_MISMATCH;
483 }
484
485 /* Return an empty buffer */
486 ObjectNameInfo->Name.Length = 0;
487 ObjectNameInfo->Name.MaximumLength = 0;
488 ObjectNameInfo->Name.Buffer = NULL;
489
490 return STATUS_SUCCESS;
491 }
492
493 /*
494 * Find the size needed for the name. We won't do
495 * this during the Name Creation loop because we want
496 * to let the caller know that the buffer isn't big
497 * enough right at the beginning, not work our way through
498 * and find out at the end
499 */
500 if (Object == NameSpaceRoot)
501 {
502 /* Size of the '\' string */
503 DPRINT("Object is Root\n");
504 NameSize = sizeof(UNICODE_PATH_SEP);
505 }
506 else
507 {
508 /* Get the Object Directory and add name of Object */
509 ParentDirectory = LocalInfo->Directory;
510 NameSize = sizeof(UNICODE_PATH_SEP) + LocalInfo->Name.Length;
511
512 /* Loop inside the directory to get the top-most one (meaning root) */
513 while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
514 {
515 /* Get the Name Information */
516 LocalInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory));
517
518 /* Add the size of the Directory Name */
519 if (LocalInfo && LocalInfo->Directory)
520 {
521 /* Size of the '\' string + Directory Name */
522 NameSize += sizeof(UNICODE_PATH_SEP) + LocalInfo->Name.Length;
523
524 /* Move to next parent Directory */
525 ParentDirectory = LocalInfo->Directory;
526 }
527 else
528 {
529 /* Directory with no name. We append "...\" */
530 DPRINT("Nameless Directory\n");
531 NameSize += sizeof(UNICODE_NO_PATH) + sizeof(UNICODE_PATH_SEP);
532 break;
533 }
534 }
535 }
536
537 /* Finally, add the name of the structure and the null char */
538 *ReturnLength = NameSize + sizeof(OBJECT_NAME_INFORMATION) + sizeof(UNICODE_NULL);
539 DPRINT("Final Length: %x\n", *ReturnLength);
540
541 /* Check if we were given enough space */
542 if (*ReturnLength > Length)
543 {
544 DPRINT1("Not enough buffer space\n");
545 return STATUS_INFO_LENGTH_MISMATCH;
546 }
547
548 /*
549 * Now we will actually create the name. We work backwards because
550 * it's easier to start off from the Name we have and walk up the
551 * parent directories. We use the same logic as Name Length calculation.
552 */
553 LocalInfo = HEADER_TO_OBJECT_NAME(ObjectHeader);
554 ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength);
555 *--ObjectName = UNICODE_NULL;
556
557 if (Object == NameSpaceRoot)
558 {
559 /* This is already the Root Directory, return "\\" */
560 DPRINT("Returning Root Dir\n");
561 *--ObjectName = UNICODE_PATH_SEP;
562 ObjectNameInfo->Name.Length = (USHORT)NameSize;
563 ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL));
564 ObjectNameInfo->Name.Buffer = ObjectName;
565
566 return STATUS_SUCCESS;
567 }
568 else
569 {
570 /* Start by adding the Object's Name */
571 ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length);
572 RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length);
573
574 /* Now parse the Parent directories until we reach the top */
575 ParentDirectory = LocalInfo->Directory;
576 while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
577 {
578 /* Get the name information */
579 LocalInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory));
580
581 /* Add the "\" */
582 *(--ObjectName) = UNICODE_PATH_SEP;
583
584 /* Add the Parent Directory's Name */
585 if (LocalInfo && LocalInfo->Name.Buffer)
586 {
587 /* Add the name */
588 ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length);
589 RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length);
590
591 /* Move to next parent */
592 ParentDirectory = LocalInfo->Directory;
593 }
594 else
595 {
596 /* Directory without a name, we add "..." */
597 DPRINT("Nameless Directory\n");
598 ObjectName -= sizeof(UNICODE_NO_PATH);
599 ObjectName = UNICODE_NO_PATH;
600 break;
601 }
602 }
603
604 /* Add Root Directory Name */
605 *(--ObjectName) = UNICODE_PATH_SEP;
606 DPRINT("Current Buffer: %S\n", ObjectName);
607 ObjectNameInfo->Name.Length = (USHORT)NameSize;
608 ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL));
609 ObjectNameInfo->Name.Buffer = ObjectName;
610 DPRINT("Complete: %wZ\n", ObjectNameInfo);
611 }
612
613 return STATUS_SUCCESS;
614 }
615
616 NTSTATUS
617 STDCALL
618 ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo,
619 PUNICODE_STRING ObjectName,
620 POBJECT_TYPE ObjectType,
621 ULONG ObjectSize,
622 PROS_OBJECT_HEADER *ObjectHeader)
623 {
624 PROS_OBJECT_HEADER Header;
625 BOOLEAN HasHandleInfo = FALSE;
626 BOOLEAN HasNameInfo = FALSE;
627 BOOLEAN HasCreatorInfo = FALSE;
628 POBJECT_HEADER_HANDLE_INFO HandleInfo;
629 POBJECT_HEADER_NAME_INFO NameInfo;
630 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
631 POOL_TYPE PoolType;
632 ULONG FinalSize = ObjectSize;
633 ULONG Tag;
634
635 /* If we don't have an Object Type yet, force NonPaged */
636 DPRINT("ObpAllocateObject\n");
637 if (!ObjectType)
638 {
639 PoolType = NonPagedPool;
640 Tag = TAG('O', 'b', 'j', 'T');
641 }
642 else
643 {
644 PoolType = ObjectType->TypeInfo.PoolType;
645 Tag = ObjectType->Key;
646 }
647
648 DPRINT("Checking ObjectName: %x\n", ObjectName);
649 /* Check if the Object has a name */
650 if (ObjectName->Buffer)
651 {
652 FinalSize += sizeof(OBJECT_HEADER_NAME_INFO);
653 HasNameInfo = TRUE;
654 }
655
656 if (ObjectType)
657 {
658 /* Check if the Object maintains handle counts */
659 DPRINT("Checking ObjectType->TypeInfo: %x\n", &ObjectType->TypeInfo);
660 if (ObjectType->TypeInfo.MaintainHandleCount)
661 {
662 FinalSize += sizeof(OBJECT_HEADER_HANDLE_INFO);
663 HasHandleInfo = TRUE;
664 }
665
666 /* Check if the Object maintains type lists */
667 if (ObjectType->TypeInfo.MaintainTypeList)
668 {
669 FinalSize += sizeof(OBJECT_HEADER_CREATOR_INFO);
670 HasCreatorInfo = TRUE;
671 }
672 }
673
674 /* Allocate memory for the Object and Header */
675 DPRINT("Allocating: %x %x\n", FinalSize, Tag);
676 Header = ExAllocatePoolWithTag(PoolType, FinalSize, Tag);
677 if (!Header) {
678 DPRINT1("Not enough memory!\n");
679 return STATUS_INSUFFICIENT_RESOURCES;
680 }
681
682 /* Initialize Handle Info */
683 if (HasHandleInfo)
684 {
685 HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header;
686 DPRINT("Info: %x\n", HandleInfo);
687 HandleInfo->SingleEntry.HandleCount = 0;
688 Header = (PROS_OBJECT_HEADER)(HandleInfo + 1);
689 }
690
691 /* Initialize the Object Name Info */
692 if (HasNameInfo)
693 {
694 NameInfo = (POBJECT_HEADER_NAME_INFO)Header;
695 DPRINT("Info: %x %wZ\n", NameInfo, ObjectName);
696 NameInfo->Name = *ObjectName;
697 NameInfo->Directory = NULL;
698 Header = (PROS_OBJECT_HEADER)(NameInfo + 1);
699 }
700
701 /* Initialize Creator Info */
702 if (HasCreatorInfo)
703 {
704 CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header;
705 DPRINT("Info: %x\n", CreatorInfo);
706 /* FIXME: Needs Alex's Init patch
707 * CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId();
708 */
709 InitializeListHead(&CreatorInfo->TypeList);
710 Header = (PROS_OBJECT_HEADER)(CreatorInfo + 1);
711 }
712
713 /* Initialize the object header */
714 RtlZeroMemory(Header, ObjectSize);
715 DPRINT("Initalized header %p\n", Header);
716 Header->HandleCount = 0;
717 Header->PointerCount = 1;
718 Header->Type = ObjectType;
719 Header->Flags = OB_FLAG_CREATE_INFO;
720
721 /* Set the Offsets for the Info */
722 if (HasHandleInfo)
723 {
724 Header->HandleInfoOffset = HasNameInfo * sizeof(OBJECT_HEADER_NAME_INFO) +
725 sizeof(OBJECT_HEADER_HANDLE_INFO) +
726 HasCreatorInfo * sizeof(OBJECT_HEADER_CREATOR_INFO);
727 Header->Flags |= OB_FLAG_SINGLE_PROCESS;
728 }
729 if (HasNameInfo)
730 {
731 Header->NameInfoOffset = sizeof(OBJECT_HEADER_NAME_INFO) +
732 HasCreatorInfo * sizeof(OBJECT_HEADER_CREATOR_INFO);
733 }
734 if (HasCreatorInfo) Header->Flags |= OB_FLAG_CREATOR_INFO;
735
736 if (ObjectCreateInfo && ObjectCreateInfo->Attributes & OBJ_PERMANENT)
737 {
738 Header->Flags |= OB_FLAG_PERMANENT;
739 }
740 if (ObjectCreateInfo && ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)
741 {
742 Header->Flags |= OB_FLAG_EXCLUSIVE;
743 }
744
745 /* Link stuff to Object Header */
746 Header->ObjectCreateInfo = ObjectCreateInfo;
747
748 /* Return Header */
749 *ObjectHeader = Header;
750 return STATUS_SUCCESS;
751 }
752
753 /**********************************************************************
754 * NAME EXPORTED
755 * ObCreateObject@36
756 *
757 * DESCRIPTION
758 *
759 * ARGUMENTS
760 *
761 * RETURN VALUE
762 * Status
763 *
764 * @implemented
765 */
766 NTSTATUS
767 STDCALL
768 ObCreateObject(IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
769 IN POBJECT_TYPE Type,
770 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
771 IN KPROCESSOR_MODE AccessMode,
772 IN OUT PVOID ParseContext OPTIONAL,
773 IN ULONG ObjectSize,
774 IN ULONG PagedPoolCharge OPTIONAL,
775 IN ULONG NonPagedPoolCharge OPTIONAL,
776 OUT PVOID *Object)
777 {
778 NTSTATUS Status;
779 POBJECT_CREATE_INFORMATION ObjectCreateInfo;
780 UNICODE_STRING ObjectName;
781 PROS_OBJECT_HEADER Header;
782
783 DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n",
784 Type, ObjectAttributes, Object);
785
786 /* Allocate a Buffer for the Object Create Info */
787 DPRINT("Allocating Create Buffer\n");
788 ObjectCreateInfo = ExAllocatePoolWithTag(NonPagedPool,
789 sizeof(*ObjectCreateInfo),
790 TAG('O','b','C', 'I'));
791
792 /* Capture all the info */
793 DPRINT("Capturing Create Info\n");
794 Status = ObpCaptureObjectAttributes(ObjectAttributes,
795 ObjectAttributesAccessMode,
796 Type,
797 ObjectCreateInfo,
798 &ObjectName);
799
800 if (NT_SUCCESS(Status))
801 {
802 /* Allocate the Object */
803 DPRINT("Allocating: %wZ\n", &ObjectName);
804 Status = ObpAllocateObject(ObjectCreateInfo,
805 &ObjectName,
806 Type,
807 OBJECT_ALLOC_SIZE(ObjectSize),
808 &Header);
809
810 if (NT_SUCCESS(Status))
811 {
812 /* Return the Object */
813 DPRINT("Returning Object\n");
814 *Object = &Header->Body;
815
816 /* Return to caller, leave the Capture Info Alive for ObInsert */
817 return Status;
818 }
819
820 /* Release the Capture Info, we don't need it */
821 DPRINT1("Allocation failed\n");
822 ObpReleaseCapturedAttributes(ObjectCreateInfo);
823 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
824 }
825
826 /* We failed, so release the Buffer */
827 DPRINT1("Capture failed\n");
828 ExFreePool(ObjectCreateInfo);
829 return Status;
830 }
831
832 /*
833 * FUNCTION: Increments the pointer reference count for a given object
834 * ARGUMENTS:
835 * ObjectBody = Object's body
836 * DesiredAccess = Desired access to the object
837 * ObjectType = Points to the object type structure
838 * AccessMode = Type of access check to perform
839 * RETURNS: Status
840 *
841 * @implemented
842 */
843 NTSTATUS STDCALL
844 ObReferenceObjectByPointer(IN PVOID Object,
845 IN ACCESS_MASK DesiredAccess,
846 IN POBJECT_TYPE ObjectType,
847 IN KPROCESSOR_MODE AccessMode)
848 {
849 PROS_OBJECT_HEADER Header;
850
851 /* NOTE: should be possible to reference an object above APC_LEVEL! */
852
853 DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
854 Object,ObjectType);
855
856 Header = BODY_TO_HEADER(Object);
857
858 if (ObjectType != NULL && Header->Type != ObjectType)
859 {
860 DPRINT("Failed %p (type was %x %wZ) should be %x %wZ\n",
861 Header,
862 Header->Type,
863 &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Header->Type))->Name,
864 ObjectType,
865 &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ObjectType))->Name);
866 return(STATUS_UNSUCCESSFUL);
867 }
868 if (Header->Type == PsProcessType)
869 {
870 DPRINT("Ref p 0x%x PointerCount %d type %x ",
871 Object, Header->PointerCount, PsProcessType);
872 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
873 }
874 if (Header->Type == PsThreadType)
875 {
876 DPRINT("Deref t 0x%x with PointerCount %d type %x ",
877 Object, Header->PointerCount, PsThreadType);
878 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
879 }
880
881 if (Header->PointerCount == 0 && !(Header->Flags & OB_FLAG_PERMANENT))
882 {
883 if (Header->Type == PsProcessType)
884 {
885 return STATUS_PROCESS_IS_TERMINATING;
886 }
887 if (Header->Type == PsThreadType)
888 {
889 return STATUS_THREAD_IS_TERMINATING;
890 }
891 return(STATUS_UNSUCCESSFUL);
892 }
893
894 if (1 == InterlockedIncrement(&Header->PointerCount) && !(Header->Flags & OB_FLAG_PERMANENT))
895 {
896 KEBUGCHECK(0);
897 }
898
899 return(STATUS_SUCCESS);
900 }
901
902
903 /*
904 * @implemented
905 */
906 NTSTATUS STDCALL
907 ObOpenObjectByPointer(IN PVOID Object,
908 IN ULONG HandleAttributes,
909 IN PACCESS_STATE PassedAccessState,
910 IN ACCESS_MASK DesiredAccess,
911 IN POBJECT_TYPE ObjectType,
912 IN KPROCESSOR_MODE AccessMode,
913 OUT PHANDLE Handle)
914 {
915 NTSTATUS Status;
916
917 PAGED_CODE();
918
919 DPRINT("ObOpenObjectByPointer()\n");
920
921 Status = ObReferenceObjectByPointer(Object,
922 0,
923 ObjectType,
924 AccessMode);
925 if (!NT_SUCCESS(Status))
926 {
927 return Status;
928 }
929
930 Status = ObpCreateHandle(Object,
931 DesiredAccess,
932 HandleAttributes,
933 Handle);
934
935 ObDereferenceObject(Object);
936
937 return STATUS_SUCCESS;
938 }
939
940
941 static NTSTATUS
942 ObpDeleteObject(PROS_OBJECT_HEADER Header)
943 {
944 PVOID HeaderLocation = Header;
945 POBJECT_HEADER_HANDLE_INFO HandleInfo;
946 POBJECT_HEADER_NAME_INFO NameInfo;
947 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
948
949 DPRINT("ObpDeleteObject(Header %p)\n", Header);
950 if (KeGetCurrentIrql() != PASSIVE_LEVEL)
951 {
952 DPRINT("ObpDeleteObject called at an unsupported IRQL. Use ObpDeleteObjectDpcLevel instead.\n");
953 KEBUGCHECK(0);
954 }
955
956 if (Header->Type != NULL &&
957 Header->Type->TypeInfo.DeleteProcedure != NULL)
958 {
959 Header->Type->TypeInfo.DeleteProcedure(&Header->Body);
960 }
961
962 if (Header->SecurityDescriptor != NULL)
963 {
964 ObpRemoveSecurityDescriptor(Header->SecurityDescriptor);
965 }
966
967 if (HEADER_TO_OBJECT_NAME(Header))
968 {
969 if(HEADER_TO_OBJECT_NAME(Header)->Name.Buffer)
970 {
971 ExFreePool(HEADER_TO_OBJECT_NAME(Header)->Name.Buffer);
972 }
973 }
974 if (Header->ObjectCreateInfo)
975 {
976 ObpReleaseCapturedAttributes(Header->ObjectCreateInfo);
977 ExFreePool(Header->ObjectCreateInfo);
978 }
979
980 /* To find the header, walk backwards from how we allocated */
981 if ((CreatorInfo = HEADER_TO_CREATOR_INFO(Header)))
982 {
983 HeaderLocation = CreatorInfo;
984 }
985 if ((NameInfo = HEADER_TO_OBJECT_NAME(Header)))
986 {
987 HeaderLocation = NameInfo;
988 }
989 if ((HandleInfo = HEADER_TO_HANDLE_INFO(Header)))
990 {
991 HeaderLocation = HandleInfo;
992 }
993
994 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
995 ExFreePool(HeaderLocation);
996
997 return(STATUS_SUCCESS);
998 }
999
1000
1001 VOID STDCALL
1002 ObpDeleteObjectWorkRoutine (IN PVOID Parameter)
1003 {
1004 PRETENTION_CHECK_PARAMS Params = (PRETENTION_CHECK_PARAMS)Parameter;
1005 /* ULONG Tag; */ /* See below */
1006
1007 ASSERT(Params);
1008 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); /* We need PAGED_CODE somewhere... */
1009
1010 /* Turn this on when we have ExFreePoolWithTag
1011 Tag = Params->ObjectHeader->Type->Tag; */
1012 ObpDeleteObject(Params->ObjectHeader);
1013 ExFreePool(Params);
1014 /* ExFreePoolWithTag(Params, Tag); */
1015 }
1016
1017
1018 STATIC NTSTATUS
1019 ObpDeleteObjectDpcLevel(IN PROS_OBJECT_HEADER ObjectHeader,
1020 IN LONG OldPointerCount)
1021 {
1022 #if 0
1023 if (ObjectHeader->PointerCount < 0)
1024 {
1025 CPRINT("Object %p/%p has invalid reference count (%d)\n",
1026 ObjectHeader, HEADER_TO_BODY(ObjectHeader),
1027 ObjectHeader->PointerCount);
1028 KEBUGCHECK(0);
1029 }
1030
1031 if (ObjectHeader->HandleCount < 0)
1032 {
1033 CPRINT("Object %p/%p has invalid handle count (%d)\n",
1034 ObjectHeader, HEADER_TO_BODY(ObjectHeader),
1035 ObjectHeader->HandleCount);
1036 KEBUGCHECK(0);
1037 }
1038 #endif
1039
1040
1041 switch (KeGetCurrentIrql ())
1042 {
1043 case PASSIVE_LEVEL:
1044 return ObpDeleteObject (ObjectHeader);
1045
1046 case APC_LEVEL:
1047 case DISPATCH_LEVEL:
1048 {
1049 PRETENTION_CHECK_PARAMS Params;
1050
1051 /*
1052 We use must succeed pool here because if the allocation fails
1053 then we leak memory.
1054 */
1055 Params = (PRETENTION_CHECK_PARAMS)
1056 ExAllocatePoolWithTag(NonPagedPoolMustSucceed,
1057 sizeof(RETENTION_CHECK_PARAMS),
1058 ObjectHeader->Type->Key);
1059 Params->ObjectHeader = ObjectHeader;
1060 ExInitializeWorkItem(&Params->WorkItem,
1061 ObpDeleteObjectWorkRoutine,
1062 (PVOID)Params);
1063 ExQueueWorkItem(&Params->WorkItem,
1064 CriticalWorkQueue);
1065 }
1066 return STATUS_PENDING;
1067
1068 default:
1069 DPRINT("ObpDeleteObjectDpcLevel called at unsupported "
1070 "IRQL %u!\n", KeGetCurrentIrql());
1071 KEBUGCHECK(0);
1072 return STATUS_UNSUCCESSFUL;
1073 }
1074
1075 return STATUS_SUCCESS;
1076 }
1077
1078
1079 /**********************************************************************
1080 * NAME EXPORTED
1081 * ObfReferenceObject@4
1082 *
1083 * DESCRIPTION
1084 * Increments a given object's reference count and performs
1085 * retention checks.
1086 *
1087 * ARGUMENTS
1088 * ObjectBody = Body of the object.
1089 *
1090 * RETURN VALUE
1091 * None.
1092 *
1093 * @implemented
1094 */
1095 VOID FASTCALL
1096 ObfReferenceObject(IN PVOID Object)
1097 {
1098 PROS_OBJECT_HEADER Header;
1099
1100 ASSERT(Object);
1101
1102 Header = BODY_TO_HEADER(Object);
1103
1104 /* No one should be referencing an object once we are deleting it. */
1105 if (InterlockedIncrement(&Header->PointerCount) == 1 && !(Header->Flags & OB_FLAG_PERMANENT))
1106 {
1107 KEBUGCHECK(0);
1108 }
1109
1110 }
1111
1112 /**********************************************************************
1113 * NAME EXPORTED
1114 * ObfDereferenceObject@4
1115 *
1116 * DESCRIPTION
1117 * Decrements a given object's reference count and performs
1118 * retention checks.
1119 *
1120 * ARGUMENTS
1121 * ObjectBody = Body of the object.
1122 *
1123 * RETURN VALUE
1124 * None.
1125 *
1126 * @implemented
1127 */
1128 VOID FASTCALL
1129 ObfDereferenceObject(IN PVOID Object)
1130 {
1131 PROS_OBJECT_HEADER Header;
1132 LONG NewPointerCount;
1133 BOOL Permanent;
1134
1135 ASSERT(Object);
1136
1137 /* Extract the object header. */
1138 Header = BODY_TO_HEADER(Object);
1139 Permanent = Header->Flags & OB_FLAG_PERMANENT;
1140
1141 /*
1142 Drop our reference and get the new count so we can tell if this was the
1143 last reference.
1144 */
1145 NewPointerCount = InterlockedDecrement(&Header->PointerCount);
1146 DPRINT("ObfDereferenceObject(0x%x)==%d\n", Object, NewPointerCount);
1147 ASSERT(NewPointerCount >= 0);
1148
1149 /* Check whether the object can now be deleted. */
1150 if (NewPointerCount == 0 &&
1151 !Permanent)
1152 {
1153 ObpDeleteObjectDpcLevel(Header, NewPointerCount);
1154 }
1155 }
1156
1157 VOID
1158 FASTCALL
1159 ObInitializeFastReference(IN PEX_FAST_REF FastRef,
1160 PVOID Object)
1161 {
1162 /* FIXME: Fast Referencing is Unimplemented */
1163 FastRef->Object = Object;
1164 }
1165
1166
1167 PVOID
1168 FASTCALL
1169 ObFastReferenceObject(IN PEX_FAST_REF FastRef)
1170 {
1171 /* FIXME: Fast Referencing is Unimplemented */
1172
1173 /* Do a normal Reference */
1174 ObReferenceObject(FastRef->Object);
1175
1176 /* Return the Object */
1177 return FastRef->Object;
1178 }
1179
1180 VOID
1181 FASTCALL
1182 ObFastDereferenceObject(IN PEX_FAST_REF FastRef,
1183 PVOID Object)
1184 {
1185 /* FIXME: Fast Referencing is Unimplemented */
1186
1187 /* Do a normal Dereference */
1188 ObDereferenceObject(FastRef->Object);
1189 }
1190
1191 PVOID
1192 FASTCALL
1193 ObFastReplaceObject(IN PEX_FAST_REF FastRef,
1194 PVOID Object)
1195 {
1196 PVOID OldObject = FastRef->Object;
1197
1198 /* FIXME: Fast Referencing is Unimplemented */
1199 FastRef->Object = Object;
1200
1201 /* Do a normal Dereference */
1202 ObDereferenceObject(OldObject);
1203
1204 /* Return old Object*/
1205 return OldObject;
1206 }
1207
1208 /**********************************************************************
1209 * NAME EXPORTED
1210 * ObGetObjectPointerCount@4
1211 *
1212 * DESCRIPTION
1213 * Retrieves the pointer(reference) count of the given object.
1214 *
1215 * ARGUMENTS
1216 * ObjectBody = Body of the object.
1217 *
1218 * RETURN VALUE
1219 * Reference count.
1220 *
1221 * @implemented
1222 */
1223 ULONG STDCALL
1224 ObGetObjectPointerCount(PVOID Object)
1225 {
1226 PROS_OBJECT_HEADER Header;
1227
1228 PAGED_CODE();
1229
1230 ASSERT(Object);
1231 Header = BODY_TO_HEADER(Object);
1232
1233 return Header->PointerCount;
1234 }
1235
1236
1237 /**********************************************************************
1238 * NAME INTERNAL
1239 * ObGetObjectHandleCount@4
1240 *
1241 * DESCRIPTION
1242 * Retrieves the handle count of the given object.
1243 *
1244 * ARGUMENTS
1245 * ObjectBody = Body of the object.
1246 *
1247 * RETURN VALUE
1248 * Reference count.
1249 */
1250 ULONG
1251 NTAPI
1252 ObGetObjectHandleCount(PVOID Object)
1253 {
1254 PROS_OBJECT_HEADER Header;
1255
1256 PAGED_CODE();
1257
1258 ASSERT(Object);
1259 Header = BODY_TO_HEADER(Object);
1260
1261 return Header->HandleCount;
1262 }
1263
1264
1265 /**********************************************************************
1266 * NAME EXPORTED
1267 * ObDereferenceObject@4
1268 *
1269 * DESCRIPTION
1270 * Decrements a given object's reference count and performs
1271 * retention checks.
1272 *
1273 * ARGUMENTS
1274 * ObjectBody = Body of the object.
1275 *
1276 * RETURN VALUE
1277 * None.
1278 *
1279 * @implemented
1280 */
1281
1282 #ifdef ObDereferenceObject
1283 #undef ObDereferenceObject
1284 #endif
1285
1286 VOID STDCALL
1287 ObDereferenceObject(IN PVOID Object)
1288 {
1289 ObfDereferenceObject(Object);
1290 }
1291
1292 /* EOF */