fixed registry querying code in Ki386SetProcessorFeatures
[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 UserMode);
320 CurrentObject = NameSpaceRoot;
321 }
322 else
323 {
324 Status = ObReferenceObjectByHandle(ObjectCreateInfo->RootDirectory,
325 0,
326 NULL,
327 UserMode,
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 UserMode);
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(PsGetCurrentProcess(),
930 Object,
931 DesiredAccess,
932 (BOOLEAN)(HandleAttributes & OBJ_INHERIT),
933 Handle);
934
935 ObDereferenceObject(Object);
936
937 return STATUS_SUCCESS;
938 }
939
940
941 static NTSTATUS
942 ObpDeleteObject(POBJECT_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 POBJECT_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 POBJECT_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 POBJECT_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 POBJECT_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 POBJECT_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 */