initialize StringBuffer to NULL, as some code paths lead to it being tested without...
[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 goto Quickie;
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 goto Quickie;
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 goto Quickie;
216 }
217 _SEH_END;
218
219 /* Now check if the Object Attributes had an Object Name */
220 if (LocalObjectName)
221 {
222 DPRINT("Name Buffer: %wZ\n", LocalObjectName);
223 Status = ObpCaptureObjectName(ObjectName,
224 LocalObjectName,
225 AccessMode);
226 }
227 else
228 {
229 /* Clear the string */
230 RtlInitUnicodeString(ObjectName, NULL);
231
232 /* He can't have specified a Root Directory */
233 if (ObjectCreateInfo->RootDirectory)
234 {
235 DPRINT1("Invalid name\n");
236 Status = STATUS_OBJECT_NAME_INVALID;
237 }
238 }
239
240 Quickie:
241 if (!NT_SUCCESS(Status))
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 ObFindObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo,
292 PUNICODE_STRING ObjectName,
293 PVOID* ReturnedObject,
294 PUNICODE_STRING RemainingPath,
295 POBJECT_TYPE ObjectType)
296 {
297 PVOID NextObject;
298 PVOID CurrentObject;
299 PVOID RootObject;
300 POBJECT_HEADER CurrentHeader;
301 NTSTATUS Status;
302 PWSTR current;
303 UNICODE_STRING PathString;
304 ULONG Attributes;
305
306 PAGED_CODE();
307
308 DPRINT("ObFindObject(ObjectCreateInfo %x, ReturnedObject %x, "
309 "RemainingPath %x)\n",ObjectCreateInfo,ReturnedObject,RemainingPath);
310
311 RtlInitUnicodeString (RemainingPath, NULL);
312
313 if (ObjectCreateInfo->RootDirectory == NULL)
314 {
315 ObReferenceObjectByPointer(NameSpaceRoot,
316 DIRECTORY_TRAVERSE,
317 NULL,
318 UserMode);
319 CurrentObject = NameSpaceRoot;
320 }
321 else
322 {
323 Status = ObReferenceObjectByHandle(ObjectCreateInfo->RootDirectory,
324 0,
325 NULL,
326 UserMode,
327 &CurrentObject,
328 NULL);
329 if (!NT_SUCCESS(Status))
330 {
331 return Status;
332 }
333 }
334
335 if (ObjectName->Length == 0 ||
336 ObjectName->Buffer[0] == UNICODE_NULL)
337 {
338 *ReturnedObject = CurrentObject;
339 return STATUS_SUCCESS;
340 }
341
342 if (ObjectCreateInfo->RootDirectory == NULL &&
343 ObjectName->Buffer[0] != L'\\')
344 {
345 ObDereferenceObject (CurrentObject);
346 DPRINT1("failed\n");
347 return STATUS_UNSUCCESSFUL;
348 }
349
350 /* Create a zero-terminated copy of the object name */
351 PathString.Length = ObjectName->Length;
352 PathString.MaximumLength = ObjectName->Length + sizeof(WCHAR);
353 PathString.Buffer = ExAllocatePool (NonPagedPool,
354 PathString.MaximumLength);
355 if (PathString.Buffer == NULL)
356 {
357 ObDereferenceObject (CurrentObject);
358 return STATUS_INSUFFICIENT_RESOURCES;
359 }
360
361 RtlCopyMemory (PathString.Buffer,
362 ObjectName->Buffer,
363 ObjectName->Length);
364 PathString.Buffer[PathString.Length / sizeof(WCHAR)] = UNICODE_NULL;
365
366 current = PathString.Buffer;
367
368 RootObject = CurrentObject;
369 Attributes = ObjectCreateInfo->Attributes;
370 if (ObjectType == ObSymbolicLinkType)
371 Attributes |= OBJ_OPENLINK;
372
373 while (TRUE)
374 {
375 DPRINT("current %S\n",current);
376 CurrentHeader = BODY_TO_HEADER(CurrentObject);
377
378 DPRINT("Current ObjectType %wZ\n",
379 &CurrentHeader->Type->Name);
380
381 if (CurrentHeader->Type->TypeInfo.ParseProcedure == NULL)
382 {
383 DPRINT("Current object can't parse\n");
384 break;
385 }
386 Status = CurrentHeader->Type->TypeInfo.ParseProcedure(CurrentObject,
387 &NextObject,
388 &PathString,
389 &current,
390 Attributes);
391 if (Status == STATUS_REPARSE)
392 {
393 /* reparse the object path */
394 NextObject = NameSpaceRoot;
395 current = PathString.Buffer;
396
397 ObReferenceObjectByPointer(NextObject,
398 DIRECTORY_TRAVERSE,
399 NULL,
400 UserMode);
401 }
402
403 if (NextObject == NULL)
404 {
405 break;
406 }
407 ObDereferenceObject(CurrentObject);
408 CurrentObject = NextObject;
409 }
410
411 if (current)
412 {
413 RtlpCreateUnicodeString (RemainingPath, current, NonPagedPool);
414 }
415
416 RtlFreeUnicodeString (&PathString);
417 *ReturnedObject = CurrentObject;
418
419 return STATUS_SUCCESS;
420 }
421
422
423 /**********************************************************************
424 * NAME EXPORTED
425 * ObQueryNameString@16
426 *
427 * DESCRIPTION
428 *
429 * ARGUMENTS
430 *
431 * RETURN VALUE
432 *
433 * @implemented
434 */
435 NTSTATUS
436 STDCALL
437 ObQueryNameString(IN PVOID Object,
438 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
439 IN ULONG Length,
440 OUT PULONG ReturnLength)
441 {
442 POBJECT_HEADER_NAME_INFO LocalInfo;
443 POBJECT_HEADER ObjectHeader;
444 PDIRECTORY_OBJECT ParentDirectory;
445 ULONG NameSize;
446 PWCH ObjectName;
447 NTSTATUS Status;
448
449 DPRINT("ObQueryNameString: %x, %x\n", Object, ObjectNameInfo);
450
451 /* Get the Kernel Meta-Structures */
452 ObjectHeader = BODY_TO_HEADER(Object);
453 LocalInfo = HEADER_TO_OBJECT_NAME(ObjectHeader);
454
455 /* Check if a Query Name Procedure is available */
456 if (ObjectHeader->Type->TypeInfo.QueryNameProcedure)
457 {
458 /* Call the procedure */
459 DPRINT("Calling Object's Procedure\n");
460 Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object,
461 ObjectNameInfo,
462 Length,
463 ReturnLength);
464
465 /* Return the status */
466 return Status;
467 }
468
469 /* Check if the object doesn't even have a name */
470 if (!LocalInfo || !LocalInfo->Name.Buffer)
471 {
472 /* We're returning the name structure */
473 DPRINT("Nameless Object\n");
474 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
475
476 /* Check if we were given enough space */
477 if (*ReturnLength > Length)
478 {
479 DPRINT1("Not enough buffer space\n");
480 return STATUS_INFO_LENGTH_MISMATCH;
481 }
482
483 /* Return an empty buffer */
484 ObjectNameInfo->Name.Length = 0;
485 ObjectNameInfo->Name.MaximumLength = 0;
486 ObjectNameInfo->Name.Buffer = NULL;
487
488 return STATUS_SUCCESS;
489 }
490
491 /*
492 * Find the size needed for the name. We won't do
493 * this during the Name Creation loop because we want
494 * to let the caller know that the buffer isn't big
495 * enough right at the beginning, not work our way through
496 * and find out at the end
497 */
498 if (Object == NameSpaceRoot)
499 {
500 /* Size of the '\' string */
501 DPRINT("Object is Root\n");
502 NameSize = sizeof(UNICODE_PATH_SEP);
503 }
504 else
505 {
506 /* Get the Object Directory and add name of Object */
507 ParentDirectory = LocalInfo->Directory;
508 NameSize = sizeof(UNICODE_PATH_SEP) + LocalInfo->Name.Length;
509
510 /* Loop inside the directory to get the top-most one (meaning root) */
511 while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
512 {
513 /* Get the Name Information */
514 LocalInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory));
515
516 /* Add the size of the Directory Name */
517 if (LocalInfo && LocalInfo->Directory)
518 {
519 /* Size of the '\' string + Directory Name */
520 NameSize += sizeof(UNICODE_PATH_SEP) + LocalInfo->Name.Length;
521
522 /* Move to next parent Directory */
523 ParentDirectory = LocalInfo->Directory;
524 }
525 else
526 {
527 /* Directory with no name. We append "...\" */
528 DPRINT("Nameless Directory\n");
529 NameSize += sizeof(UNICODE_NO_PATH) + sizeof(UNICODE_PATH_SEP);
530 break;
531 }
532 }
533 }
534
535 /* Finally, add the name of the structure and the null char */
536 *ReturnLength = NameSize + sizeof(OBJECT_NAME_INFORMATION) + sizeof(UNICODE_NULL);
537 DPRINT("Final Length: %x\n", *ReturnLength);
538
539 /* Check if we were given enough space */
540 if (*ReturnLength > Length)
541 {
542 DPRINT1("Not enough buffer space\n");
543 return STATUS_INFO_LENGTH_MISMATCH;
544 }
545
546 /*
547 * Now we will actually create the name. We work backwards because
548 * it's easier to start off from the Name we have and walk up the
549 * parent directories. We use the same logic as Name Length calculation.
550 */
551 LocalInfo = HEADER_TO_OBJECT_NAME(ObjectHeader);
552 ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength);
553 *--ObjectName = UNICODE_NULL;
554
555 if (Object == NameSpaceRoot)
556 {
557 /* This is already the Root Directory, return "\\" */
558 DPRINT("Returning Root Dir\n");
559 *--ObjectName = UNICODE_PATH_SEP;
560 ObjectNameInfo->Name.Length = (USHORT)NameSize;
561 ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL));
562 ObjectNameInfo->Name.Buffer = ObjectName;
563
564 return STATUS_SUCCESS;
565 }
566 else
567 {
568 /* Start by adding the Object's Name */
569 ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length);
570 RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length);
571
572 /* Now parse the Parent directories until we reach the top */
573 ParentDirectory = LocalInfo->Directory;
574 while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
575 {
576 /* Get the name information */
577 LocalInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory));
578
579 /* Add the "\" */
580 *(--ObjectName) = UNICODE_PATH_SEP;
581
582 /* Add the Parent Directory's Name */
583 if (LocalInfo && LocalInfo->Name.Buffer)
584 {
585 /* Add the name */
586 ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length);
587 RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length);
588
589 /* Move to next parent */
590 ParentDirectory = LocalInfo->Directory;
591 }
592 else
593 {
594 /* Directory without a name, we add "..." */
595 DPRINT("Nameless Directory\n");
596 ObjectName -= sizeof(UNICODE_NO_PATH);
597 ObjectName = UNICODE_NO_PATH;
598 break;
599 }
600 }
601
602 /* Add Root Directory Name */
603 *(--ObjectName) = UNICODE_PATH_SEP;
604 DPRINT("Current Buffer: %S\n", ObjectName);
605 ObjectNameInfo->Name.Length = (USHORT)NameSize;
606 ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL));
607 ObjectNameInfo->Name.Buffer = ObjectName;
608 DPRINT("Complete: %wZ\n", ObjectNameInfo);
609 }
610
611 return STATUS_SUCCESS;
612 }
613
614 NTSTATUS
615 STDCALL
616 ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo,
617 PUNICODE_STRING ObjectName,
618 POBJECT_TYPE ObjectType,
619 ULONG ObjectSize,
620 POBJECT_HEADER *ObjectHeader)
621 {
622 POBJECT_HEADER Header;
623 BOOLEAN HasHandleInfo = FALSE;
624 BOOLEAN HasNameInfo = FALSE;
625 BOOLEAN HasCreatorInfo = FALSE;
626 POBJECT_HEADER_HANDLE_INFO HandleInfo;
627 POBJECT_HEADER_NAME_INFO NameInfo;
628 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
629 POOL_TYPE PoolType;
630 ULONG FinalSize = ObjectSize;
631 ULONG Tag;
632
633 /* If we don't have an Object Type yet, force NonPaged */
634 DPRINT("ObpAllocateObject\n");
635 if (!ObjectType)
636 {
637 PoolType = NonPagedPool;
638 Tag = TAG('O', 'b', 'j', 'T');
639 }
640 else
641 {
642 PoolType = ObjectType->TypeInfo.PoolType;
643 Tag = ObjectType->Key;
644 }
645
646 DPRINT("Checking ObjectName: %x\n", ObjectName);
647 /* Check if the Object has a name */
648 if (ObjectName->Buffer)
649 {
650 FinalSize += sizeof(OBJECT_HEADER_NAME_INFO);
651 HasNameInfo = TRUE;
652 }
653
654 if (ObjectType)
655 {
656 /* Check if the Object maintains handle counts */
657 DPRINT("Checking ObjectType->TypeInfo: %x\n", &ObjectType->TypeInfo);
658 if (ObjectType->TypeInfo.MaintainHandleCount)
659 {
660 FinalSize += sizeof(OBJECT_HEADER_HANDLE_INFO);
661 HasHandleInfo = TRUE;
662 }
663
664 /* Check if the Object maintains type lists */
665 if (ObjectType->TypeInfo.MaintainTypeList)
666 {
667 FinalSize += sizeof(OBJECT_HEADER_CREATOR_INFO);
668 HasCreatorInfo = TRUE;
669 }
670 }
671
672 /* Allocate memory for the Object and Header */
673 DPRINT("Allocating: %x %x\n", FinalSize, Tag);
674 Header = ExAllocatePoolWithTag(PoolType, FinalSize, Tag);
675 if (!Header) {
676 DPRINT1("Not enough memory!\n");
677 return STATUS_INSUFFICIENT_RESOURCES;
678 }
679
680 /* Initialize Handle Info */
681 if (HasHandleInfo)
682 {
683 HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header;
684 DPRINT("Info: %x\n", HandleInfo);
685 HandleInfo->SingleEntry.HandleCount = 0;
686 Header = (POBJECT_HEADER)(HandleInfo + 1);
687 }
688
689 /* Initialize the Object Name Info */
690 if (HasNameInfo)
691 {
692 NameInfo = (POBJECT_HEADER_NAME_INFO)Header;
693 DPRINT("Info: %x %wZ\n", NameInfo, ObjectName);
694 NameInfo->Name = *ObjectName;
695 NameInfo->Directory = NULL;
696 Header = (POBJECT_HEADER)(NameInfo + 1);
697 }
698
699 /* Initialize Creator Info */
700 if (HasCreatorInfo)
701 {
702 CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header;
703 DPRINT("Info: %x\n", CreatorInfo);
704 /* FIXME: Needs Alex's Init patch
705 * CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId();
706 */
707 InitializeListHead(&CreatorInfo->TypeList);
708 Header = (POBJECT_HEADER)(CreatorInfo + 1);
709 }
710
711 /* Initialize the object header */
712 RtlZeroMemory(Header, ObjectSize);
713 DPRINT("Initalized header %p\n", Header);
714 Header->HandleCount = 0;
715 Header->PointerCount = 1;
716 Header->Type = ObjectType;
717 Header->Flags = OB_FLAG_CREATE_INFO;
718
719 /* Set the Offsets for the Info */
720 if (HasHandleInfo)
721 {
722 Header->HandleInfoOffset = HasNameInfo * sizeof(OBJECT_HEADER_NAME_INFO) +
723 sizeof(OBJECT_HEADER_HANDLE_INFO) +
724 HasCreatorInfo * sizeof(OBJECT_HEADER_CREATOR_INFO);
725 Header->Flags |= OB_FLAG_SINGLE_PROCESS;
726 }
727 if (HasNameInfo)
728 {
729 Header->NameInfoOffset = sizeof(OBJECT_HEADER_NAME_INFO) +
730 HasCreatorInfo * sizeof(OBJECT_HEADER_CREATOR_INFO);
731 }
732 if (HasCreatorInfo) Header->Flags |= OB_FLAG_CREATOR_INFO;
733
734 if (ObjectCreateInfo && ObjectCreateInfo->Attributes & OBJ_PERMANENT)
735 {
736 Header->Flags |= OB_FLAG_PERMANENT;
737 }
738 if (ObjectCreateInfo && ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)
739 {
740 Header->Flags |= OB_FLAG_EXCLUSIVE;
741 }
742
743 /* Link stuff to Object Header */
744 Header->ObjectCreateInfo = ObjectCreateInfo;
745
746 /* Return Header */
747 *ObjectHeader = Header;
748 return STATUS_SUCCESS;
749 }
750
751 /**********************************************************************
752 * NAME EXPORTED
753 * ObCreateObject@36
754 *
755 * DESCRIPTION
756 *
757 * ARGUMENTS
758 *
759 * RETURN VALUE
760 * Status
761 *
762 * @implemented
763 */
764 NTSTATUS
765 STDCALL
766 ObCreateObject(IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
767 IN POBJECT_TYPE Type,
768 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
769 IN KPROCESSOR_MODE AccessMode,
770 IN OUT PVOID ParseContext OPTIONAL,
771 IN ULONG ObjectSize,
772 IN ULONG PagedPoolCharge OPTIONAL,
773 IN ULONG NonPagedPoolCharge OPTIONAL,
774 OUT PVOID *Object)
775 {
776 NTSTATUS Status;
777 POBJECT_CREATE_INFORMATION ObjectCreateInfo;
778 UNICODE_STRING ObjectName;
779 POBJECT_HEADER Header;
780
781 DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n",
782 Type, ObjectAttributes, Object);
783
784 /* Allocate a Buffer for the Object Create Info */
785 DPRINT("Allocating Create Buffer\n");
786 ObjectCreateInfo = ExAllocatePoolWithTag(NonPagedPool,
787 sizeof(*ObjectCreateInfo),
788 TAG('O','b','C', 'I'));
789
790 /* Capture all the info */
791 DPRINT("Capturing Create Info\n");
792 Status = ObpCaptureObjectAttributes(ObjectAttributes,
793 ObjectAttributesAccessMode,
794 Type,
795 ObjectCreateInfo,
796 &ObjectName);
797
798 if (NT_SUCCESS(Status))
799 {
800 /* Allocate the Object */
801 DPRINT("Allocating: %wZ\n", &ObjectName);
802 Status = ObpAllocateObject(ObjectCreateInfo,
803 &ObjectName,
804 Type,
805 OBJECT_ALLOC_SIZE(ObjectSize),
806 &Header);
807
808 if (NT_SUCCESS(Status))
809 {
810 /* Return the Object */
811 DPRINT("Returning Object\n");
812 *Object = &Header->Body;
813
814 /* Return to caller, leave the Capture Info Alive for ObInsert */
815 return Status;
816 }
817
818 /* Release the Capture Info, we don't need it */
819 DPRINT1("Allocation failed\n");
820 ObpReleaseCapturedAttributes(ObjectCreateInfo);
821 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
822 }
823
824 /* We failed, so release the Buffer */
825 DPRINT1("Capture failed\n");
826 ExFreePool(ObjectCreateInfo);
827 return Status;
828 }
829
830 /*
831 * FUNCTION: Increments the pointer reference count for a given object
832 * ARGUMENTS:
833 * ObjectBody = Object's body
834 * DesiredAccess = Desired access to the object
835 * ObjectType = Points to the object type structure
836 * AccessMode = Type of access check to perform
837 * RETURNS: Status
838 *
839 * @implemented
840 */
841 NTSTATUS STDCALL
842 ObReferenceObjectByPointer(IN PVOID Object,
843 IN ACCESS_MASK DesiredAccess,
844 IN POBJECT_TYPE ObjectType,
845 IN KPROCESSOR_MODE AccessMode)
846 {
847 POBJECT_HEADER Header;
848
849 /* NOTE: should be possible to reference an object above APC_LEVEL! */
850
851 DPRINT("ObReferenceObjectByPointer(Object %x, ObjectType %x)\n",
852 Object,ObjectType);
853
854 Header = BODY_TO_HEADER(Object);
855
856 if (ObjectType != NULL && Header->Type != ObjectType)
857 {
858 DPRINT("Failed %p (type was %x %wZ) should be %x %wZ\n",
859 Header,
860 Header->Type,
861 &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Header->Type))->Name,
862 ObjectType,
863 &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ObjectType))->Name);
864 return(STATUS_UNSUCCESSFUL);
865 }
866 if (Header->Type == PsProcessType)
867 {
868 DPRINT("Ref p 0x%x PointerCount %d type %x ",
869 Object, Header->PointerCount, PsProcessType);
870 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
871 }
872 if (Header->Type == PsThreadType)
873 {
874 DPRINT("Deref t 0x%x with PointerCount %d type %x ",
875 Object, Header->PointerCount, PsThreadType);
876 DPRINT("eip %x\n", ((PULONG)&Object)[-1]);
877 }
878
879 if (Header->PointerCount == 0 && !(Header->Flags & OB_FLAG_PERMANENT))
880 {
881 if (Header->Type == PsProcessType)
882 {
883 return STATUS_PROCESS_IS_TERMINATING;
884 }
885 if (Header->Type == PsThreadType)
886 {
887 return STATUS_THREAD_IS_TERMINATING;
888 }
889 return(STATUS_UNSUCCESSFUL);
890 }
891
892 if (1 == InterlockedIncrement(&Header->PointerCount) && !(Header->Flags & OB_FLAG_PERMANENT))
893 {
894 KEBUGCHECK(0);
895 }
896
897 return(STATUS_SUCCESS);
898 }
899
900
901 /*
902 * @implemented
903 */
904 NTSTATUS STDCALL
905 ObOpenObjectByPointer(IN PVOID Object,
906 IN ULONG HandleAttributes,
907 IN PACCESS_STATE PassedAccessState,
908 IN ACCESS_MASK DesiredAccess,
909 IN POBJECT_TYPE ObjectType,
910 IN KPROCESSOR_MODE AccessMode,
911 OUT PHANDLE Handle)
912 {
913 NTSTATUS Status;
914
915 PAGED_CODE();
916
917 DPRINT("ObOpenObjectByPointer()\n");
918
919 Status = ObReferenceObjectByPointer(Object,
920 0,
921 ObjectType,
922 AccessMode);
923 if (!NT_SUCCESS(Status))
924 {
925 return Status;
926 }
927
928 Status = ObpCreateHandle(PsGetCurrentProcess(),
929 Object,
930 DesiredAccess,
931 (BOOLEAN)(HandleAttributes & OBJ_INHERIT),
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 ObGetObjectHandleCount(PVOID Object)
1251 {
1252 POBJECT_HEADER Header;
1253
1254 PAGED_CODE();
1255
1256 ASSERT(Object);
1257 Header = BODY_TO_HEADER(Object);
1258
1259 return Header->HandleCount;
1260 }
1261
1262
1263 /**********************************************************************
1264 * NAME EXPORTED
1265 * ObDereferenceObject@4
1266 *
1267 * DESCRIPTION
1268 * Decrements a given object's reference count and performs
1269 * retention checks.
1270 *
1271 * ARGUMENTS
1272 * ObjectBody = Body of the object.
1273 *
1274 * RETURN VALUE
1275 * None.
1276 *
1277 * @implemented
1278 */
1279
1280 #ifdef ObDereferenceObject
1281 #undef ObDereferenceObject
1282 #endif
1283
1284 VOID STDCALL
1285 ObDereferenceObject(IN PVOID Object)
1286 {
1287 ObfDereferenceObject(Object);
1288 }
1289
1290 /* EOF */