- KdDebuggerNotPresent should be FALSE by default.
[reactos.git] / reactos / ntoskrnl / ob / oblife.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/create.c
5 * PURPOSE: Manages the lifetime of an Object, including its creation,
6 * and deletion, as well as setting or querying any of its
7 * information while it is active. Since Object Types are also
8 * Objects, those are also managed here.
9 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
10 * Eric Kohl
11 * Thomas Weidenmueller (w3seek@reactos.org)
12 */
13
14 /* INCLUDES ******************************************************************/
15
16 #include <ntoskrnl.h>
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 extern ULONG NtGlobalFlag;
21
22 POBJECT_TYPE ObTypeObjectType = NULL;
23 KEVENT ObpDefaultObject;
24
25 NPAGED_LOOKASIDE_LIST ObpNmLookasideList, ObpCiLookasideList;
26
27 WORK_QUEUE_ITEM ObpReaperWorkItem;
28 volatile PVOID ObpReaperList;
29
30 ULONG ObpObjectsCreated, ObpObjectsWithName, ObpObjectsWithPoolQuota;
31 ULONG ObpObjectsWithHandleDB, ObpObjectsWithCreatorInfo;
32 POBJECT_TYPE ObpObjectTypes[32];
33
34 /* PRIVATE FUNCTIONS *********************************************************/
35
36 VOID
37 FASTCALL
38 ObpDeallocateObject(IN PVOID Object)
39 {
40 PVOID HeaderLocation;
41 POBJECT_HEADER Header;
42 POBJECT_TYPE ObjectType;
43 POBJECT_HEADER_HANDLE_INFO HandleInfo;
44 POBJECT_HEADER_NAME_INFO NameInfo;
45 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
46 POBJECT_HEADER_QUOTA_INFO QuotaInfo;
47 ULONG PagedPoolCharge, NonPagedPoolCharge;
48 PAGED_CODE();
49
50 /* Get the header and assume this is what we'll free */
51 Header = OBJECT_TO_OBJECT_HEADER(Object);
52 ObjectType = Header->Type;
53 HeaderLocation = Header;
54
55 /* To find the header, walk backwards from how we allocated */
56 if ((CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header)))
57 {
58 HeaderLocation = CreatorInfo;
59 }
60 if ((NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header)))
61 {
62 HeaderLocation = NameInfo;
63 }
64 if ((HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(Header)))
65 {
66 HeaderLocation = HandleInfo;
67 }
68 if ((QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO(Header)))
69 {
70 HeaderLocation = QuotaInfo;
71 }
72
73 /* Decrease the total */
74 InterlockedDecrement((PLONG)&ObjectType->TotalNumberOfObjects);
75
76 /* Check if we have create info */
77 if (Header->Flags & OB_FLAG_CREATE_INFO)
78 {
79 /* Double-check that it exists */
80 if (Header->ObjectCreateInfo)
81 {
82 /* Free it */
83 ObpFreeAndReleaseCapturedAttributes(Header->ObjectCreateInfo);
84 Header->ObjectCreateInfo = NULL;
85 }
86 }
87 else
88 {
89 /* Check if it has a quota block */
90 if (Header->QuotaBlockCharged)
91 {
92 /* Check if we have quota information */
93 if (QuotaInfo)
94 {
95 /* Get charges from quota information */
96 PagedPoolCharge = QuotaInfo->PagedPoolCharge +
97 QuotaInfo->SecurityDescriptorCharge;
98 NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge;
99 }
100 else
101 {
102 /* Get charges from object type */
103 PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
104 NonPagedPoolCharge = ObjectType->
105 TypeInfo.DefaultNonPagedPoolCharge;
106
107 /* Add the SD charge too */
108 if (Header->Flags & OB_FLAG_SECURITY) PagedPoolCharge += 2048;
109 }
110 }
111 }
112
113 /* Check if a handle database was active */
114 if ((HandleInfo) && !(Header->Flags & OB_FLAG_SINGLE_PROCESS))
115 {
116 /* Free it */
117 ExFreePool(HandleInfo->HandleCountDatabase);
118 HandleInfo->HandleCountDatabase = NULL;
119 }
120
121 /* Check if we have a name */
122 if ((NameInfo) && (NameInfo->Name.Buffer))
123 {
124 /* Free it */
125 ExFreePool(NameInfo->Name.Buffer);
126 NameInfo->Name.Buffer = NULL;
127 }
128
129 /* Catch invalid access */
130 Header->Type = (POBJECT_TYPE)0xBAADB0B0;
131
132 /* Free the object using the same allocation tag */
133 ExFreePoolWithTag(HeaderLocation, ObjectType->Key);
134 }
135
136 VOID
137 NTAPI
138 ObpDeleteObject(IN PVOID Object,
139 IN BOOLEAN CalledFromWorkerThread)
140 {
141 POBJECT_HEADER Header;
142 POBJECT_TYPE ObjectType;
143 POBJECT_HEADER_NAME_INFO NameInfo;
144 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
145 KIRQL CalloutIrql;
146 PAGED_CODE();
147
148 /* Get the header and type */
149 Header = OBJECT_TO_OBJECT_HEADER(Object);
150 ObjectType = Header->Type;
151
152 /* Get creator and name information */
153 NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header);
154 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
155
156 /* Check if the object is on a type list */
157 if ((CreatorInfo) && !(IsListEmpty(&CreatorInfo->TypeList)))
158 {
159 /* Lock the object type */
160 ObpEnterObjectTypeMutex(ObjectType);
161
162 /* Remove the object from the type list */
163 RemoveEntryList(&CreatorInfo->TypeList);
164
165 /* Release the lock */
166 ObpLeaveObjectTypeMutex(ObjectType);
167 }
168
169 /* Check if we have a name */
170 if ((NameInfo) && (NameInfo->Name.Buffer))
171 {
172 /* Free it */
173 ExFreePool(NameInfo->Name.Buffer);
174 RtlInitEmptyUnicodeString(&NameInfo->Name, NULL, 0);
175 }
176
177 /* Check if we have a security descriptor */
178 if (Header->SecurityDescriptor)
179 {
180 /* Call the security procedure to delete it */
181 ObpCalloutStart(&CalloutIrql);
182 ObjectType->TypeInfo.SecurityProcedure(Object,
183 DeleteSecurityDescriptor,
184 0,
185 NULL,
186 NULL,
187 &Header->SecurityDescriptor,
188 0,
189 NULL);
190 ObpCalloutEnd(CalloutIrql, "Security", ObjectType, Object);
191 }
192
193 /* Check if we have a delete procedure */
194 if (ObjectType->TypeInfo.DeleteProcedure)
195 {
196 /* Save whether we were deleted from worker thread or not */
197 if (!CalledFromWorkerThread) Header->Flags |= OB_FLAG_DEFER_DELETE;
198
199 /* Call it */
200 ObpCalloutStart(&CalloutIrql);
201 ObjectType->TypeInfo.DeleteProcedure(Object);
202 ObpCalloutEnd(CalloutIrql, "Delete", ObjectType, Object);
203 }
204
205 /* Now de-allocate all object members */
206 ObpDeallocateObject(Object);
207 }
208
209 VOID
210 NTAPI
211 ObpReapObject(IN PVOID Parameter)
212 {
213 POBJECT_HEADER ReapObject, NextObject;
214
215 /* Start reaping */
216 do
217 {
218 /* Get the reap object */
219 ReapObject = InterlockedExchangePointer(&ObpReaperList, (PVOID)1);
220
221 /* Start deletion loop */
222 do
223 {
224 /* Get the next object */
225 NextObject = ReapObject->NextToFree;
226
227 /* Delete the object */
228 ObpDeleteObject(&ReapObject->Body, TRUE);
229
230 /* Move to the next one */
231 ReapObject = NextObject;
232 } while ((ReapObject) && (ReapObject != (PVOID)1));
233 } while ((ObpReaperList != (PVOID)1) ||
234 (InterlockedCompareExchange((PLONG)&ObpReaperList, 0, 1) != 1));
235 }
236
237 /*++
238 * @name ObpSetPermanentObject
239 *
240 * The ObpSetPermanentObject routine makes an sets or clears the permanent
241 * flag of an object, thus making it either permanent or temporary.
242 *
243 * @param ObjectBody
244 * Pointer to the object to make permanent or temporary.
245 *
246 * @param Permanent
247 * Flag specifying which operation to perform.
248 *
249 * @return None.
250 *
251 * @remarks If the object is being made temporary, then it will be checked
252 * as a candidate for immediate removal from the namespace.
253 *
254 *--*/
255 VOID
256 FASTCALL
257 ObpSetPermanentObject(IN PVOID ObjectBody,
258 IN BOOLEAN Permanent)
259 {
260 POBJECT_HEADER ObjectHeader;
261
262 /* Get the header */
263 ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
264
265 /* Acquire object type lock */
266 ObpEnterObjectTypeMutex(ObjectHeader->Type);
267
268 /* Check what we're doing to it */
269 if (Permanent)
270 {
271 /* Set it to permanent */
272 ObjectHeader->Flags |= OB_FLAG_PERMANENT;
273
274 /* Release the lock */
275 ObpLeaveObjectTypeMutex(ObjectHeader->Type);
276 }
277 else
278 {
279 /* Remove the flag */
280 ObjectHeader->Flags &= ~OB_FLAG_PERMANENT;
281
282 /* Release the lock */
283 ObpLeaveObjectTypeMutex(ObjectHeader->Type);
284
285 /* Check if we should delete the object now */
286 ObpDeleteNameCheck(ObjectBody);
287 }
288 }
289
290 PWCHAR
291 NTAPI
292 ObpAllocateObjectNameBuffer(IN ULONG Length,
293 IN BOOLEAN UseLookaside,
294 IN OUT PUNICODE_STRING ObjectName)
295 {
296 ULONG MaximumLength;
297 PVOID Buffer;
298
299 /* Set the maximum length to the length plus the terminator */
300 MaximumLength = Length + sizeof(UNICODE_NULL);
301
302 /* Check if we should use the lookaside buffer */
303 if (!(UseLookaside) || (MaximumLength > 248))
304 {
305 /* Nope, allocate directly from pool */
306 Buffer = ExAllocatePoolWithTag(PagedPool,
307 MaximumLength,
308 OB_NAME_TAG);
309 }
310 else
311 {
312 /* Allocate from the lookaside */
313 //MaximumLength = 248; <= hack, we should actually set this...!
314 Buffer = ObpAllocateCapturedAttributes(LookasideNameBufferList);
315 }
316
317 /* Setup the string */
318 ObjectName->Length = (USHORT)Length;
319 ObjectName->MaximumLength = (USHORT)MaximumLength;
320 ObjectName->Buffer = Buffer;
321 return Buffer;
322 }
323
324 VOID
325 NTAPI
326 ObpFreeObjectNameBuffer(IN PUNICODE_STRING Name)
327 {
328 PVOID Buffer = Name->Buffer;
329
330 /* We know this is a pool-allocation if the size doesn't match */
331 if (Name->MaximumLength != 248)
332 {
333 /* Free it from the pool */
334 ExFreePool(Buffer);
335 }
336 else
337 {
338 /* Otherwise, free from the lookaside */
339 ObpFreeCapturedAttributes(Buffer, LookasideNameBufferList);
340 }
341 }
342
343 NTSTATUS
344 NTAPI
345 ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,
346 IN PUNICODE_STRING ObjectName,
347 IN KPROCESSOR_MODE AccessMode,
348 IN BOOLEAN UseLookaside)
349 {
350 NTSTATUS Status = STATUS_SUCCESS;
351 ULONG StringLength;
352 PWCHAR StringBuffer = NULL;
353 UNICODE_STRING LocalName;
354 PAGED_CODE();
355
356 /* Initialize the Input String */
357 RtlInitEmptyUnicodeString(CapturedName, NULL, 0);
358
359 /* Protect everything */
360 _SEH_TRY
361 {
362 /* Check if we came from user mode */
363 if (AccessMode != KernelMode)
364 {
365 /* First Probe the String */
366 ProbeForReadUnicodeString(ObjectName);
367 LocalName = *ObjectName;
368 ProbeForRead(LocalName.Buffer, LocalName.Length, sizeof(WCHAR));
369 }
370 else
371 {
372 /* No probing needed */
373 LocalName = *ObjectName;
374 }
375
376 /* Make sure there really is a string */
377 if ((StringLength = LocalName.Length))
378 {
379 /* Check that the size is a valid WCHAR multiple */
380 if ((StringLength & (sizeof(WCHAR) - 1)) ||
381 /* Check that the NULL-termination below will work */
382 (StringLength == (MAXUSHORT - sizeof(UNICODE_NULL) + 1)))
383 {
384 /* PS: Please keep the checks above expanded for clarity */
385 Status = STATUS_OBJECT_NAME_INVALID;
386 }
387 else
388 {
389 /* Allocate the string buffer */
390 StringBuffer = ObpAllocateObjectNameBuffer(StringLength,
391 UseLookaside,
392 CapturedName);
393 if (!StringBuffer)
394 {
395 /* Set failure code */
396 Status = STATUS_INSUFFICIENT_RESOURCES;
397 }
398 else
399 {
400 /* Copy the name */
401 RtlCopyMemory(StringBuffer, LocalName.Buffer, StringLength);
402 StringBuffer[StringLength / sizeof(WCHAR)] = UNICODE_NULL;
403 }
404 }
405 }
406 }
407 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
408 {
409 /* Handle exception and free the string buffer */
410 Status = _SEH_GetExceptionCode();
411 if (StringBuffer) ExFreePool(StringBuffer);
412 }
413 _SEH_END;
414
415 /* Return */
416 return Status;
417 }
418
419 NTSTATUS
420 NTAPI
421 ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
422 IN KPROCESSOR_MODE AccessMode,
423 IN BOOLEAN AllocateFromLookaside,
424 IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
425 OUT PUNICODE_STRING ObjectName)
426 {
427 NTSTATUS Status = STATUS_SUCCESS;
428 PSECURITY_DESCRIPTOR SecurityDescriptor;
429 PSECURITY_QUALITY_OF_SERVICE SecurityQos;
430 PUNICODE_STRING LocalObjectName = NULL;
431 PAGED_CODE();
432
433 /* Zero out the Capture Data */
434 RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION));
435
436 /* SEH everything here for protection */
437 _SEH_TRY
438 {
439 /* Check if we got attributes */
440 if (ObjectAttributes)
441 {
442 /* Check if we're in user mode */
443 if (AccessMode != KernelMode)
444 {
445 /* Probe the attributes */
446 ProbeForRead(ObjectAttributes,
447 sizeof(OBJECT_ATTRIBUTES),
448 sizeof(ULONG));
449 }
450
451 /* Validate the Size and Attributes */
452 if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) ||
453 (ObjectAttributes->Attributes & ~OBJ_VALID_ATTRIBUTES))
454 {
455 /* Invalid combination, fail */
456 Status = STATUS_INVALID_PARAMETER;
457 _SEH_LEAVE;
458 }
459
460 /* Set some Create Info */
461 ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory;
462 ObjectCreateInfo->Attributes = ObjectAttributes->Attributes;
463 LocalObjectName = ObjectAttributes->ObjectName;
464 SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
465 SecurityQos = ObjectAttributes->SecurityQualityOfService;
466
467 /* Check if we have a security descriptor */
468 if (SecurityDescriptor)
469 {
470 /* Capture it */
471 Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
472 AccessMode,
473 NonPagedPool,
474 TRUE,
475 &ObjectCreateInfo->
476 SecurityDescriptor);
477 if(!NT_SUCCESS(Status))
478 {
479 /* Capture failed, quit */
480 ObjectCreateInfo->SecurityDescriptor = NULL;
481 _SEH_LEAVE;
482 }
483
484 /* Save the probe mode and security descriptor size */
485 ObjectCreateInfo->SecurityDescriptorCharge = 2048; /* FIXME */
486 ObjectCreateInfo->ProbeMode = AccessMode;
487 }
488
489 /* Check if we have QoS */
490 if (SecurityQos)
491 {
492 /* Check if we came from user mode */
493 if (AccessMode != KernelMode)
494 {
495 /* Validate the QoS */
496 ProbeForRead(SecurityQos,
497 sizeof(SECURITY_QUALITY_OF_SERVICE),
498 sizeof(ULONG));
499 }
500
501 /* Save Info */
502 ObjectCreateInfo->SecurityQualityOfService = *SecurityQos;
503 ObjectCreateInfo->SecurityQos =
504 &ObjectCreateInfo->SecurityQualityOfService;
505 }
506 }
507 else
508 {
509 /* We don't have a name */
510 LocalObjectName = NULL;
511 }
512 }
513 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
514 {
515 /* Get the exception */
516 Status = _SEH_GetExceptionCode();
517 }
518 _SEH_END;
519
520 if (NT_SUCCESS(Status))
521 {
522 /* Now check if the Object Attributes had an Object Name */
523 if (LocalObjectName)
524 {
525 Status = ObpCaptureObjectName(ObjectName,
526 LocalObjectName,
527 AccessMode,
528 AllocateFromLookaside);
529 }
530 else
531 {
532 /* Clear the string */
533 RtlInitEmptyUnicodeString(ObjectName, NULL, 0);
534
535 /* He can't have specified a Root Directory */
536 if (ObjectCreateInfo->RootDirectory)
537 {
538 Status = STATUS_OBJECT_NAME_INVALID;
539 }
540 }
541 }
542
543 /* Cleanup if we failed */
544 if (!NT_SUCCESS(Status)) ObpReleaseCapturedAttributes(ObjectCreateInfo);
545
546 /* Return status to caller */
547 return Status;
548 }
549
550 VOID
551 NTAPI
552 ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
553 {
554 /* Call the macro. We use this function to isolate Ob internals from Io */
555 ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
556 }
557
558 NTSTATUS
559 NTAPI
560 ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
561 IN PUNICODE_STRING ObjectName,
562 IN POBJECT_TYPE ObjectType,
563 IN ULONG ObjectSize,
564 IN KPROCESSOR_MODE PreviousMode,
565 IN POBJECT_HEADER *ObjectHeader)
566 {
567 POBJECT_HEADER Header;
568 ULONG QuotaSize, HandleSize, NameSize, CreatorSize;
569 POBJECT_HEADER_HANDLE_INFO HandleInfo;
570 POBJECT_HEADER_NAME_INFO NameInfo;
571 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
572 POBJECT_HEADER_QUOTA_INFO QuotaInfo;
573 POOL_TYPE PoolType;
574 ULONG FinalSize;
575 ULONG Tag;
576 PAGED_CODE();
577
578 /* Accounting */
579 ObpObjectsCreated++;
580
581 /* Check if we don't have an Object Type yet */
582 if (!ObjectType)
583 {
584 /* Use default tag and non-paged pool */
585 PoolType = NonPagedPool;
586 Tag = TAG('O', 'b', 'j', 'T');
587 }
588 else
589 {
590 /* Use the pool and tag given */
591 PoolType = ObjectType->TypeInfo.PoolType;
592 Tag = ObjectType->Key;
593 }
594
595 /* Check if we have no create information (ie: we're an object type) */
596 if (!ObjectCreateInfo)
597 {
598 /* Use defaults */
599 QuotaSize = HandleSize = 0;
600 NameSize = sizeof(OBJECT_HEADER_NAME_INFO);
601 CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
602 }
603 else
604 {
605 /* Check if we have quota */
606 if ((((ObjectCreateInfo->PagedPoolCharge !=
607 ObjectType->TypeInfo.DefaultPagedPoolCharge) ||
608 (ObjectCreateInfo->NonPagedPoolCharge !=
609 ObjectType->TypeInfo.DefaultNonPagedPoolCharge) ||
610 (ObjectCreateInfo->SecurityDescriptorCharge > 2048)) &&
611 (PsGetCurrentProcess() != PsInitialSystemProcess)) ||
612 (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
613 {
614 /* Set quota size */
615 QuotaSize = sizeof(OBJECT_HEADER_QUOTA_INFO);
616 ObpObjectsWithPoolQuota++;
617 }
618 else
619 {
620 /* No Quota */
621 QuotaSize = 0;
622 }
623
624 /* Check if we have a handle database */
625 if (ObjectType->TypeInfo.MaintainHandleCount)
626 {
627 /* Set handle database size */
628 HandleSize = sizeof(OBJECT_HEADER_HANDLE_INFO);
629 ObpObjectsWithHandleDB++;
630 }
631 else
632 {
633 /* None */
634 HandleSize = 0;
635 }
636
637 /* Check if the Object has a name */
638 if (ObjectName->Buffer)
639 {
640 /* Set name size */
641 NameSize = sizeof(OBJECT_HEADER_NAME_INFO);
642 ObpObjectsWithName++;
643 }
644 else
645 {
646 /* No name */
647 NameSize = 0;
648 }
649
650 /* Check if the Object maintains type lists */
651 if (ObjectType->TypeInfo.MaintainTypeList)
652 {
653 /* Set owner/creator size */
654 CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
655 ObpObjectsWithCreatorInfo++;
656 }
657 else
658 {
659 /* No info */
660 CreatorSize = 0;
661 }
662 }
663
664 /* Set final header size */
665 FinalSize = QuotaSize +
666 HandleSize +
667 NameSize +
668 CreatorSize +
669 FIELD_OFFSET(OBJECT_HEADER, Body);
670
671 /* Allocate memory for the Object and Header */
672 Header = ExAllocatePoolWithTag(PoolType, FinalSize + ObjectSize, Tag);
673 if (!Header) return STATUS_INSUFFICIENT_RESOURCES;
674
675 /* Check if we have a quota header */
676 if (QuotaSize)
677 {
678 /* Initialize quota info */
679 QuotaInfo = (POBJECT_HEADER_QUOTA_INFO)Header;
680 QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge;
681 QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge;
682 QuotaInfo->SecurityDescriptorCharge = ObjectCreateInfo->SecurityDescriptorCharge;
683 QuotaInfo->ExclusiveProcess = NULL;
684 Header = (POBJECT_HEADER)(QuotaInfo + 1);
685 }
686
687 /* Check if we have a handle database header */
688 if (HandleSize)
689 {
690 /* Initialize Handle Info */
691 HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header;
692 HandleInfo->SingleEntry.HandleCount = 0;
693 Header = (POBJECT_HEADER)(HandleInfo + 1);
694 }
695
696 /* Check if we have a name header */
697 if (NameSize)
698 {
699 /* Initialize the Object Name Info */
700 NameInfo = (POBJECT_HEADER_NAME_INFO)Header;
701 NameInfo->Name = *ObjectName;
702 NameInfo->Directory = NULL;
703 NameInfo->QueryReferences = 1;
704
705 /* Check if this is a call with the special protection flag */
706 if ((PreviousMode == KernelMode) &&
707 (ObjectCreateInfo) &&
708 (ObjectCreateInfo->Attributes & 0x10000))
709 {
710 /* Set flag which will make the object protected from user-mode */
711 NameInfo->QueryReferences |= 0x40000000;
712 }
713
714 /* Set the header pointer */
715 Header = (POBJECT_HEADER)(NameInfo + 1);
716 }
717
718 /* Check if we have a creator header */
719 if (CreatorSize)
720 {
721 /* Initialize Creator Info */
722 CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header;
723 CreatorInfo->CreatorBackTraceIndex = 0;
724 CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId();
725 InitializeListHead(&CreatorInfo->TypeList);
726 Header = (POBJECT_HEADER)(CreatorInfo + 1);
727 }
728
729 /* Check for quota information */
730 if (QuotaSize)
731 {
732 /* Set the offset */
733 Header->QuotaInfoOffset = (UCHAR)(QuotaSize +
734 HandleSize +
735 NameSize +
736 CreatorSize);
737 }
738 else
739 {
740 /* No offset */
741 Header->QuotaInfoOffset = 0;
742 }
743
744 /* Check for handle information */
745 if (HandleSize)
746 {
747 /* Set the offset */
748 Header->HandleInfoOffset = (UCHAR)(HandleSize +
749 NameSize +
750 CreatorSize);
751 }
752 else
753 {
754 /* No offset */
755 Header->HandleInfoOffset = 0;
756 }
757
758 /* Check for name information */
759 if (NameSize)
760 {
761 /* Set the offset */
762 Header->NameInfoOffset = (UCHAR)(NameSize + CreatorSize);
763 }
764 else
765 {
766 /* No Name */
767 Header->NameInfoOffset = 0;
768 }
769
770 /* Set the new object flag */
771 Header->Flags = OB_FLAG_CREATE_INFO;
772
773 /* Remember if we have creator info */
774 if (CreatorSize) Header->Flags |= OB_FLAG_CREATOR_INFO;
775
776 /* Remember if we have handle info */
777 if (HandleSize) Header->Flags |= OB_FLAG_SINGLE_PROCESS;
778
779 /* Initialize the object header */
780 Header->PointerCount = 1;
781 Header->HandleCount = 0;
782 Header->Type = ObjectType;
783 Header->ObjectCreateInfo = ObjectCreateInfo;
784 Header->SecurityDescriptor = NULL;
785
786 /* Check if this is a permanent object */
787 if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_PERMANENT))
788 {
789 /* Set the needed flag so we can check */
790 Header->Flags |= OB_FLAG_PERMANENT;
791 }
792
793 /* Check if this is an exclusive object */
794 if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
795 {
796 /* Set the needed flag so we can check */
797 Header->Flags |= OB_FLAG_EXCLUSIVE;
798 }
799
800 /* Set kernel-mode flag */
801 if (PreviousMode == KernelMode) Header->Flags |= OB_FLAG_KERNEL_MODE;
802
803 /* Check if we have a type */
804 if (ObjectType)
805 {
806 /* Increase the number of objects of this type */
807 InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfObjects);
808
809 /* Update the high water */
810 ObjectType->HighWaterNumberOfObjects = max(ObjectType->
811 TotalNumberOfObjects,
812 ObjectType->
813 HighWaterNumberOfObjects);
814 }
815
816 /* OMG-Hack-Of-Doom */
817 RtlZeroMemory(&Header->Body, ObjectSize);
818
819 /* Return Header */
820 *ObjectHeader = Header;
821 return STATUS_SUCCESS;
822 }
823
824 NTSTATUS
825 NTAPI
826 ObQueryTypeInfo(IN POBJECT_TYPE ObjectType,
827 OUT POBJECT_TYPE_INFORMATION ObjectTypeInfo,
828 IN ULONG Length,
829 OUT PULONG ReturnLength)
830 {
831 NTSTATUS Status = STATUS_SUCCESS;
832 PWSTR InfoBuffer;
833
834 /* Enter SEH */
835 _SEH_TRY
836 {
837 /* Set return length aligned to 4-byte boundary */
838 *ReturnLength += sizeof(*ObjectTypeInfo) +
839 ALIGN_UP(ObjectType->Name.MaximumLength, ULONG);
840
841 /* Check if thats too much though. */
842 if (Length < *ReturnLength) return STATUS_INFO_LENGTH_MISMATCH;
843
844 /* Build the data */
845 ObjectTypeInfo->TotalNumberOfHandles =
846 ObjectType->TotalNumberOfHandles;
847 ObjectTypeInfo->TotalNumberOfObjects =
848 ObjectType->TotalNumberOfObjects;
849 ObjectTypeInfo->HighWaterNumberOfHandles =
850 ObjectType->HighWaterNumberOfHandles;
851 ObjectTypeInfo->HighWaterNumberOfObjects =
852 ObjectType->HighWaterNumberOfObjects;
853 ObjectTypeInfo->PoolType =
854 ObjectType->TypeInfo.PoolType;
855 ObjectTypeInfo->DefaultNonPagedPoolCharge =
856 ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
857 ObjectTypeInfo->DefaultPagedPoolCharge =
858 ObjectType->TypeInfo.DefaultPagedPoolCharge;
859 ObjectTypeInfo->ValidAccessMask =
860 ObjectType->TypeInfo.ValidAccessMask;
861 ObjectTypeInfo->SecurityRequired =
862 ObjectType->TypeInfo.SecurityRequired;
863 ObjectTypeInfo->InvalidAttributes =
864 ObjectType->TypeInfo.InvalidAttributes;
865 ObjectTypeInfo->GenericMapping =
866 ObjectType->TypeInfo.GenericMapping;
867 ObjectTypeInfo->MaintainHandleCount =
868 ObjectType->TypeInfo.MaintainHandleCount;
869
870 /* Setup the name buffer */
871 InfoBuffer = (PWSTR)(ObjectTypeInfo + 1);
872 ObjectTypeInfo->TypeName.Buffer = InfoBuffer;
873 ObjectTypeInfo->TypeName.MaximumLength = ObjectType->Name.MaximumLength;
874 ObjectTypeInfo->TypeName.Length = ObjectType->Name.Length;
875
876 /* Copy it */
877 RtlCopyMemory(InfoBuffer,
878 ObjectType->Name.Buffer,
879 ObjectType->Name.Length);
880
881 /* Null-terminate it */
882 (InfoBuffer)[ObjectType->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
883 }
884 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
885 {
886 /* Otherwise, get the exception code */
887 Status = _SEH_GetExceptionCode();
888 }
889 _SEH_END;
890
891 /* Return status to caller */
892 return Status;
893 }
894
895
896 /* PUBLIC FUNCTIONS **********************************************************/
897
898 NTSTATUS
899 NTAPI
900 ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL,
901 IN POBJECT_TYPE Type,
902 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
903 IN KPROCESSOR_MODE AccessMode,
904 IN OUT PVOID ParseContext OPTIONAL,
905 IN ULONG ObjectSize,
906 IN ULONG PagedPoolCharge OPTIONAL,
907 IN ULONG NonPagedPoolCharge OPTIONAL,
908 OUT PVOID *Object)
909 {
910 NTSTATUS Status;
911 POBJECT_CREATE_INFORMATION ObjectCreateInfo;
912 UNICODE_STRING ObjectName;
913 POBJECT_HEADER Header;
914
915 /* Allocate a capture buffer */
916 ObjectCreateInfo = ObpAllocateCapturedAttributes(LookasideCreateInfoList);
917 if (!ObjectCreateInfo) return STATUS_INSUFFICIENT_RESOURCES;
918
919 /* Capture all the info */
920 Status = ObpCaptureObjectAttributes(ObjectAttributes,
921 ProbeMode,
922 FALSE,
923 ObjectCreateInfo,
924 &ObjectName);
925 if (NT_SUCCESS(Status))
926 {
927 /* Validate attributes */
928 if (Type->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes)
929 {
930 /* Fail */
931 Status = STATUS_INVALID_PARAMETER;
932 }
933 else
934 {
935 /* Check if we have a paged charge */
936 if (!PagedPoolCharge)
937 {
938 /* Save it */
939 PagedPoolCharge = Type->TypeInfo.DefaultPagedPoolCharge;
940 }
941
942 /* Check for nonpaged charge */
943 if (!NonPagedPoolCharge)
944 {
945 /* Save it */
946 NonPagedPoolCharge = Type->TypeInfo.DefaultNonPagedPoolCharge;
947 }
948
949 /* Write the pool charges */
950 ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge;
951 ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge;
952
953 /* Allocate the Object */
954 Status = ObpAllocateObject(ObjectCreateInfo,
955 &ObjectName,
956 Type,
957 ObjectSize,
958 AccessMode,
959 &Header);
960 if (NT_SUCCESS(Status))
961 {
962 /* Return the Object */
963 *Object = &Header->Body;
964
965 /* Check if this is a permanent object */
966 if (Header->Flags & OB_FLAG_PERMANENT)
967 {
968 /* Do the privilege check */
969 if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
970 ProbeMode))
971 {
972 /* Fail */
973 ObpDeallocateObject(*Object);
974 Status = STATUS_PRIVILEGE_NOT_HELD;
975 }
976 }
977
978 /* Return status */
979 return Status;
980 }
981 }
982
983 /* Release the Capture Info, we don't need it */
984 ObpReleaseCapturedAttributes(ObjectCreateInfo);
985 if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
986 }
987
988 /* We failed, so release the Buffer */
989 ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
990 return Status;
991 }
992
993 NTSTATUS
994 NTAPI
995 ObCreateObjectType(IN PUNICODE_STRING TypeName,
996 IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
997 IN PVOID Reserved,
998 OUT POBJECT_TYPE *ObjectType)
999 {
1000 POBJECT_HEADER Header;
1001 POBJECT_TYPE LocalObjectType;
1002 ULONG HeaderSize;
1003 NTSTATUS Status;
1004 CHAR Tag[4];
1005 OBP_LOOKUP_CONTEXT Context;
1006 PWCHAR p;
1007 ULONG i;
1008 UNICODE_STRING ObjectName;
1009 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
1010
1011 /* Verify parameters */
1012 if (!(TypeName) ||
1013 !(TypeName->Length) ||
1014 (TypeName->Length % sizeof(WCHAR)) ||
1015 !(ObjectTypeInitializer) ||
1016 (ObjectTypeInitializer->Length != sizeof(*ObjectTypeInitializer)) ||
1017 (ObjectTypeInitializer->InvalidAttributes & ~OBJ_VALID_ATTRIBUTES) ||
1018 (ObjectTypeInitializer->MaintainHandleCount &&
1019 (!(ObjectTypeInitializer->OpenProcedure) &&
1020 !ObjectTypeInitializer->CloseProcedure)) ||
1021 ((!ObjectTypeInitializer->UseDefaultObject) &&
1022 (ObjectTypeInitializer->PoolType != NonPagedPool)))
1023 {
1024 /* Fail */
1025 return STATUS_INVALID_PARAMETER;
1026 }
1027
1028 /* Make sure the name doesn't have a separator */
1029 p = TypeName->Buffer;
1030 i = TypeName->Length / sizeof(WCHAR);
1031 while (i--)
1032 {
1033 /* Check for one and fail */
1034 if (*p++ == OBJ_NAME_PATH_SEPARATOR) return STATUS_OBJECT_NAME_INVALID;
1035 }
1036
1037 /* Setup a lookup context */
1038 ObpInitializeDirectoryLookup(&Context);
1039
1040 /* Check if we've already created the directory of types */
1041 if (ObpTypeDirectoryObject)
1042 {
1043 /* Acquire the directory lock */
1044 ObpAcquireDirectoryLockExclusive(ObpTypeDirectoryObject, &Context);
1045
1046 /* Do the lookup */
1047 if (ObpLookupEntryDirectory(ObpTypeDirectoryObject,
1048 TypeName,
1049 OBJ_CASE_INSENSITIVE,
1050 FALSE,
1051 &Context))
1052 {
1053 /* We have already created it, so fail */
1054 ObpCleanupDirectoryLookup(&Context);
1055 return STATUS_OBJECT_NAME_COLLISION;
1056 }
1057 }
1058
1059 /* Now make a copy of the object name */
1060 ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool,
1061 TypeName->MaximumLength,
1062 OB_NAME_TAG);
1063 if (!ObjectName.Buffer)
1064 {
1065 /* Out of memory, fail */
1066 ObpCleanupDirectoryLookup(&Context);
1067 return STATUS_INSUFFICIENT_RESOURCES;
1068 }
1069
1070 /* Set the length and copy the name */
1071 ObjectName.MaximumLength = TypeName->MaximumLength;
1072 RtlCopyUnicodeString(&ObjectName, TypeName);
1073
1074 /* Allocate the Object */
1075 Status = ObpAllocateObject(NULL,
1076 &ObjectName,
1077 ObTypeObjectType,
1078 sizeof(OBJECT_TYPE),
1079 KernelMode,
1080 (POBJECT_HEADER*)&Header);
1081 if (!NT_SUCCESS(Status))
1082 {
1083 /* Free the name and fail */
1084 ObpCleanupDirectoryLookup(&Context);
1085 ExFreePool(ObjectName.Buffer);
1086 return Status;
1087 }
1088
1089 /* Setup the flags and name */
1090 LocalObjectType = (POBJECT_TYPE)&Header->Body;
1091 LocalObjectType->Name = ObjectName;
1092 Header->Flags |= OB_FLAG_KERNEL_MODE | OB_FLAG_PERMANENT;
1093
1094 /* Clear accounting data */
1095 LocalObjectType->TotalNumberOfObjects =
1096 LocalObjectType->TotalNumberOfHandles =
1097 LocalObjectType->HighWaterNumberOfObjects =
1098 LocalObjectType->HighWaterNumberOfHandles = 0;
1099
1100 /* Check if this is the first Object Type */
1101 if (!ObTypeObjectType)
1102 {
1103 /* It is, so set this as the type object */
1104 ObTypeObjectType = LocalObjectType;
1105 Header->Type = ObTypeObjectType;
1106
1107 /* Set the hard-coded key and object count */
1108 LocalObjectType->TotalNumberOfObjects = 1;
1109 LocalObjectType->Key = TAG('O', 'b', 'j', 'T');
1110 }
1111 else
1112 {
1113 /* Set Tag */
1114 Tag[0] = (CHAR)TypeName->Buffer[0];
1115 Tag[1] = (CHAR)TypeName->Buffer[1];
1116 Tag[2] = (CHAR)TypeName->Buffer[2];
1117 Tag[3] = (CHAR)TypeName->Buffer[3];
1118 LocalObjectType->Key = *(PULONG)Tag;
1119 }
1120
1121 /* Set up the type information */
1122 LocalObjectType->TypeInfo = *ObjectTypeInitializer;
1123 LocalObjectType->TypeInfo.PoolType = ObjectTypeInitializer->PoolType;
1124
1125 /* Check if we have to maintain a type list */
1126 if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST)
1127 {
1128 /* Enable support */
1129 LocalObjectType->TypeInfo.MaintainTypeList = TRUE;
1130 }
1131
1132 /* Calculate how much space our header'll take up */
1133 HeaderSize = sizeof(OBJECT_HEADER) +
1134 sizeof(OBJECT_HEADER_NAME_INFO) +
1135 (ObjectTypeInitializer->MaintainHandleCount ?
1136 sizeof(OBJECT_HEADER_HANDLE_INFO) : 0);
1137
1138 /* Check the pool type */
1139 if (ObjectTypeInitializer->PoolType == NonPagedPool)
1140 {
1141 /* Update the NonPaged Pool charge */
1142 LocalObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderSize;
1143 }
1144 else
1145 {
1146 /* Update the Paged Pool charge */
1147 LocalObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderSize;
1148 }
1149
1150 /* All objects types need a security procedure */
1151 if (!ObjectTypeInitializer->SecurityProcedure)
1152 {
1153 LocalObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod;
1154 }
1155
1156 /* Select the Wait Object */
1157 if (LocalObjectType->TypeInfo.UseDefaultObject)
1158 {
1159 /* Add the SYNCHRONIZE access mask since it's waitable */
1160 LocalObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE;
1161
1162 /* Use the "Default Object", a simple event */
1163 LocalObjectType->DefaultObject = &ObpDefaultObject;
1164 }
1165 /* The File Object gets an optimized hack so it can be waited on */
1166 else if ((TypeName->Length == 8) && !(wcscmp(TypeName->Buffer, L"File")))
1167 {
1168 /* Wait on the File Object's event directly */
1169 LocalObjectType->DefaultObject = (PVOID)FIELD_OFFSET(FILE_OBJECT,
1170 Event);
1171 }
1172 else if ((TypeName->Length == 24) && !(wcscmp(TypeName->Buffer, L"WaitablePort")))
1173 {
1174 /* Wait on the LPC Port's object directly */
1175 LocalObjectType->DefaultObject = (PVOID)FIELD_OFFSET(LPCP_PORT_OBJECT,
1176 WaitEvent);
1177 }
1178 else
1179 {
1180 /* No default Object */
1181 LocalObjectType->DefaultObject = NULL;
1182 }
1183
1184 /* Initialize Object Type components */
1185 ExInitializeResourceLite(&LocalObjectType->Mutex);
1186 for (i = 0; i < 4; i++)
1187 {
1188 /* Initialize the object locks */
1189 ExInitializeResourceLite(&LocalObjectType->ObjectLocks[i]);
1190 }
1191 InitializeListHead(&LocalObjectType->TypeList);
1192
1193 /* Lock the object type */
1194 ObpEnterObjectTypeMutex(LocalObjectType);
1195
1196 /* Get creator info and insert it into the type list */
1197 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
1198 if (CreatorInfo) InsertTailList(&ObTypeObjectType->TypeList,
1199 &CreatorInfo->TypeList);
1200
1201 /* Set the index and the entry into the object type array */
1202 LocalObjectType->Index = ObTypeObjectType->TotalNumberOfObjects;
1203 if (LocalObjectType->Index < 32)
1204 {
1205 /* It fits, insert it */
1206 ObpObjectTypes[LocalObjectType->Index - 1] = LocalObjectType;
1207 }
1208
1209 /* Release the object type */
1210 ObpLeaveObjectTypeMutex(LocalObjectType);
1211
1212 /* Check if we're actually creating the directory object itself */
1213 if (!(ObpTypeDirectoryObject) ||
1214 (ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header)))
1215 {
1216 /* Check if the type directory exists */
1217 if (ObpTypeDirectoryObject)
1218 {
1219 /* Reference it */
1220 ObReferenceObject(ObpTypeDirectoryObject);
1221 }
1222
1223 /* Cleanup the lookup context */
1224 ObpCleanupDirectoryLookup(&Context);
1225
1226 /* Return the object type and success */
1227 *ObjectType = LocalObjectType;
1228 return STATUS_SUCCESS;
1229 }
1230
1231 /* If we got here, then we failed */
1232 ObpCleanupDirectoryLookup(&Context);
1233 return STATUS_INSUFFICIENT_RESOURCES;
1234 }
1235
1236 /*++
1237 * @name ObMakeTemporaryObject
1238 * @implemented NT4
1239 *
1240 * The ObMakeTemporaryObject routine <FILLMEIN>
1241 *
1242 * @param ObjectBody
1243 * <FILLMEIN>
1244 *
1245 * @return None.
1246 *
1247 * @remarks None.
1248 *
1249 *--*/
1250 VOID
1251 NTAPI
1252 ObMakeTemporaryObject(IN PVOID ObjectBody)
1253 {
1254 PAGED_CODE();
1255
1256 /* Call the internal API */
1257 ObpSetPermanentObject(ObjectBody, FALSE);
1258 }
1259
1260 /*++
1261 * @name NtMakeTemporaryObject
1262 * @implemented NT4
1263 *
1264 * The NtMakeTemporaryObject routine <FILLMEIN>
1265 *
1266 * @param ObjectHandle
1267 * <FILLMEIN>
1268 *
1269 * @return STATUS_SUCCESS or appropriate error value.
1270 *
1271 * @remarks None.
1272 *
1273 *--*/
1274 NTSTATUS
1275 NTAPI
1276 NtMakeTemporaryObject(IN HANDLE ObjectHandle)
1277 {
1278 PVOID ObjectBody;
1279 NTSTATUS Status;
1280 PAGED_CODE();
1281
1282 /* Reference the object for DELETE access */
1283 Status = ObReferenceObjectByHandle(ObjectHandle,
1284 DELETE,
1285 NULL,
1286 KeGetPreviousMode(),
1287 &ObjectBody,
1288 NULL);
1289 if (Status != STATUS_SUCCESS) return Status;
1290
1291 /* Set it as temporary and dereference it */
1292 ObpSetPermanentObject(ObjectBody, FALSE);
1293 ObDereferenceObject(ObjectBody);
1294 return STATUS_SUCCESS;
1295 }
1296
1297 /*++
1298 * @name NtMakePermanentObject
1299 * @implemented NT4
1300 *
1301 * The NtMakePermanentObject routine <FILLMEIN>
1302 *
1303 * @param ObjectHandle
1304 * <FILLMEIN>
1305 *
1306 * @return STATUS_SUCCESS or appropriate error value.
1307 *
1308 * @remarks None.
1309 *
1310 *--*/
1311 NTSTATUS
1312 NTAPI
1313 NtMakePermanentObject(IN HANDLE ObjectHandle)
1314 {
1315 PVOID ObjectBody;
1316 NTSTATUS Status;
1317 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1318 PAGED_CODE();
1319
1320 /* Make sure that the caller has SeCreatePermanentPrivilege */
1321 Status = SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
1322 PreviousMode);
1323 if (!NT_SUCCESS(Status)) return STATUS_PRIVILEGE_NOT_HELD;
1324
1325 /* Reference the object */
1326 Status = ObReferenceObjectByHandle(ObjectHandle,
1327 0,
1328 NULL,
1329 PreviousMode,
1330 &ObjectBody,
1331 NULL);
1332 if (Status != STATUS_SUCCESS) return Status;
1333
1334 /* Set it as permanent and dereference it */
1335 ObpSetPermanentObject(ObjectBody, TRUE);
1336 ObDereferenceObject(ObjectBody);
1337 return STATUS_SUCCESS;
1338 }
1339
1340 /*++
1341 * @name NtQueryObject
1342 * @implemented NT4
1343 *
1344 * The NtQueryObject routine <FILLMEIN>
1345 *
1346 * @param ObjectHandle
1347 * <FILLMEIN>
1348 *
1349 * @param ObjectInformationClass
1350 * <FILLMEIN>
1351 *
1352 * @param ObjectInformation
1353 * <FILLMEIN>
1354 *
1355 * @param Length
1356 * <FILLMEIN>
1357 *
1358 * @param ResultLength
1359 * <FILLMEIN>
1360 *
1361 * @return STATUS_SUCCESS or appropriate error value.
1362 *
1363 * @remarks None.
1364 *
1365 *--*/
1366 NTSTATUS
1367 NTAPI
1368 NtQueryObject(IN HANDLE ObjectHandle,
1369 IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1370 OUT PVOID ObjectInformation,
1371 IN ULONG Length,
1372 OUT PULONG ResultLength OPTIONAL)
1373 {
1374 OBJECT_HANDLE_INFORMATION HandleInfo;
1375 POBJECT_HEADER ObjectHeader = NULL;
1376 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
1377 POBJECT_BASIC_INFORMATION BasicInfo;
1378 ULONG InfoLength;
1379 PVOID Object = NULL;
1380 NTSTATUS Status = STATUS_SUCCESS;
1381 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1382 PAGED_CODE();
1383
1384 /* Check if the caller is from user mode */
1385 if (PreviousMode != KernelMode)
1386 {
1387 /* Protect validation with SEH */
1388 _SEH_TRY
1389 {
1390 /* Probe the input structure */
1391 ProbeForWrite(ObjectInformation, Length, sizeof(UCHAR));
1392
1393 /* If we have a result length, probe it too */
1394 if (ResultLength) ProbeForWriteUlong(ResultLength);
1395 }
1396 _SEH_HANDLE
1397 {
1398 /* Get the exception code */
1399 Status = _SEH_GetExceptionCode();
1400 }
1401 _SEH_END;
1402
1403 /* Fail if we raised an exception */
1404 if (!NT_SUCCESS(Status)) return Status;
1405 }
1406
1407 /*
1408 * Make sure this isn't a generic type query, since the caller doesn't
1409 * have to give a handle for it
1410 */
1411 if (ObjectInformationClass != ObjectAllTypesInformation)
1412 {
1413 /* Reference the object */
1414 Status = ObReferenceObjectByHandle(ObjectHandle,
1415 0,
1416 NULL,
1417 KeGetPreviousMode(),
1418 &Object,
1419 &HandleInfo);
1420 if (!NT_SUCCESS (Status)) return Status;
1421
1422 /* Get the object header */
1423 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1424 }
1425
1426 _SEH_TRY
1427 {
1428 /* Check the information class */
1429 switch (ObjectInformationClass)
1430 {
1431 /* Basic info */
1432 case ObjectBasicInformation:
1433
1434 /* Validate length */
1435 InfoLength = sizeof(OBJECT_BASIC_INFORMATION);
1436 if (Length != sizeof(OBJECT_BASIC_INFORMATION))
1437 {
1438 /* Fail */
1439 Status = STATUS_INFO_LENGTH_MISMATCH;
1440 break;
1441 }
1442
1443 /* Fill out the basic information */
1444 BasicInfo = (POBJECT_BASIC_INFORMATION)ObjectInformation;
1445 BasicInfo->Attributes = HandleInfo.HandleAttributes;
1446 BasicInfo->GrantedAccess = HandleInfo.GrantedAccess;
1447 BasicInfo->HandleCount = ObjectHeader->HandleCount;
1448 BasicInfo->PointerCount = ObjectHeader->PointerCount;
1449
1450 /* Permanent/Exclusive Flags are NOT in Handle attributes! */
1451 if (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE)
1452 {
1453 /* Set the flag */
1454 BasicInfo->Attributes |= OBJ_EXCLUSIVE;
1455 }
1456 if (ObjectHeader->Flags & OB_FLAG_PERMANENT)
1457 {
1458 /* Set the flag */
1459 BasicInfo->Attributes |= OBJ_PERMANENT;
1460 }
1461
1462 /* Copy quota information */
1463 BasicInfo->PagedPoolUsage = 0; /* FIXME*/
1464 BasicInfo->NonPagedPoolUsage = 0; /* FIXME*/
1465
1466 /* Copy name information */
1467 BasicInfo->NameInformationLength = 0; /* FIXME*/
1468 BasicInfo->TypeInformationLength = 0; /* FIXME*/
1469
1470 /* Copy security information */
1471 BasicInfo->SecurityDescriptorLength = 0; /* FIXME*/
1472
1473 /* Check if this is a symlink */
1474 if (ObjectHeader->Type == ObSymbolicLinkType)
1475 {
1476 /* Return the creation time */
1477 BasicInfo->CreateTime.QuadPart =
1478 ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart;
1479 }
1480 else
1481 {
1482 /* Otherwise return 0 */
1483 BasicInfo->CreateTime.QuadPart = (ULONGLONG)0;
1484 }
1485
1486 /* Break out with success */
1487 Status = STATUS_SUCCESS;
1488 break;
1489
1490 /* Name information */
1491 case ObjectNameInformation:
1492
1493 /* Call the helper and break out */
1494 Status = ObQueryNameString(Object,
1495 (POBJECT_NAME_INFORMATION)
1496 ObjectInformation,
1497 Length,
1498 &InfoLength);
1499 break;
1500
1501 /* Information about this type */
1502 case ObjectTypeInformation:
1503
1504 /* Call the helper and break out */
1505 Status = ObQueryTypeInfo(ObjectHeader->Type,
1506 (POBJECT_TYPE_INFORMATION)
1507 ObjectInformation,
1508 Length,
1509 &InfoLength);
1510 break;
1511
1512 /* Information about all types */
1513 case ObjectAllTypesInformation:
1514 DPRINT1("NOT IMPLEMENTED!\n");
1515 Status = STATUS_NOT_IMPLEMENTED;
1516 break;
1517
1518 /* Information about the handle flags */
1519 case ObjectHandleInformation:
1520
1521 /* Validate length */
1522 InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION);
1523 if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1524 {
1525 Status = STATUS_INFO_LENGTH_MISMATCH;
1526 break;
1527 }
1528
1529 /* Get the structure */
1530 HandleFlags = (POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1531 ObjectInformation;
1532
1533 /* Set the flags */
1534 HandleFlags->Inherit = HandleInfo.HandleAttributes & OBJ_INHERIT;
1535 HandleFlags->ProtectFromClose = (HandleInfo.HandleAttributes &
1536 OBJ_PROTECT_CLOSE) != 0;
1537
1538 /* Break out with success */
1539 Status = STATUS_SUCCESS;
1540 break;
1541
1542 /* Anything else */
1543 default:
1544
1545 /* Fail it */
1546 Status = STATUS_INVALID_INFO_CLASS;
1547 break;
1548 }
1549
1550 /* Check if the caller wanted the return length */
1551 if (ResultLength)
1552 {
1553 /* Write the length */
1554 *ResultLength = Length;
1555 }
1556 }
1557 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
1558 {
1559 /* Otherwise, get the exception code */
1560 Status = _SEH_GetExceptionCode();
1561 }
1562 _SEH_END;
1563
1564 /* Dereference the object if we had referenced it */
1565 if (Object) ObDereferenceObject (Object);
1566
1567 /* Return status */
1568 return Status;
1569 }
1570
1571 /*++
1572 * @name NtSetInformationObject
1573 * @implemented NT4
1574 *
1575 * The NtSetInformationObject routine <FILLMEIN>
1576 *
1577 * @param ObjectHandle
1578 * <FILLMEIN>
1579 *
1580 * @param ObjectInformationClass
1581 * <FILLMEIN>
1582 *
1583 * @param ObjectInformation
1584 * <FILLMEIN>
1585 *
1586 * @param Length
1587 * <FILLMEIN>
1588 *
1589 * @return STATUS_SUCCESS or appropriate error value.
1590 *
1591 * @remarks None.
1592 *
1593 *--*/
1594 NTSTATUS
1595 NTAPI
1596 NtSetInformationObject(IN HANDLE ObjectHandle,
1597 IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1598 IN PVOID ObjectInformation,
1599 IN ULONG Length)
1600 {
1601 NTSTATUS Status = STATUS_SUCCESS;
1602 OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context;
1603 PVOID ObjectTable;
1604 KAPC_STATE ApcState;
1605 BOOLEAN AttachedToProcess = FALSE;
1606 PAGED_CODE();
1607
1608 /* Validate the information class */
1609 if (ObjectInformationClass != ObjectHandleInformation)
1610 {
1611 /* Invalid class */
1612 return STATUS_INVALID_INFO_CLASS;
1613 }
1614
1615 /* Validate the length */
1616 if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1617 {
1618 /* Invalid length */
1619 return STATUS_INFO_LENGTH_MISMATCH;
1620 }
1621
1622 /* Save the previous mode and actual information */
1623 Context.PreviousMode = ExGetPreviousMode();
1624
1625 if (Context.PreviousMode != KernelMode)
1626 {
1627 _SEH_TRY
1628 {
1629 ProbeForRead(ObjectInformation,
1630 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION),
1631 sizeof(ULONG));
1632 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1633 ObjectInformation;
1634 }
1635 _SEH_HANDLE
1636 {
1637 Status = _SEH_GetExceptionCode();
1638 }
1639 _SEH_END;
1640
1641 if (!NT_SUCCESS(Status)) return Status;
1642 }
1643 else
1644 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1645 ObjectInformation;
1646
1647 /* Check if this is a kernel handle */
1648 if (ObIsKernelHandle(ObjectHandle, Context.PreviousMode))
1649 {
1650 /* Get the actual handle */
1651 ObjectHandle = ObKernelHandleToHandle(ObjectHandle);
1652 ObjectTable = ObpKernelHandleTable;
1653
1654 /* Check if we're not in the system process */
1655 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1656 {
1657 /* Attach to it */
1658 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1659 AttachedToProcess = TRUE;
1660 }
1661 }
1662 else
1663 {
1664 /* Use the current table */
1665 ObjectTable = PsGetCurrentProcess()->ObjectTable;
1666 }
1667
1668 /* Change the handle attributes */
1669 if (!ExChangeHandle(ObjectTable,
1670 ObjectHandle,
1671 ObpSetHandleAttributes,
1672 (ULONG_PTR)&Context))
1673 {
1674 /* Some failure */
1675 Status = STATUS_ACCESS_DENIED;
1676 }
1677
1678 /* De-attach if we were attached, and return status */
1679 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1680 return Status;
1681 }
1682
1683 /* EOF */