Sync with trunk (r48008)
[reactos.git] / ntoskrnl / ob / oblife.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/oblife.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 <debug.h>
19
20 extern ULONG NtGlobalFlag;
21
22 POBJECT_TYPE ObpTypeObjectType = NULL;
23 KEVENT ObpDefaultObject;
24
25 GENERAL_LOOKASIDE ObpNameBufferLookasideList, ObpCreateInfoLookasideList;
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 ObpFreeObjectCreateInformation(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 lock */
266 ObpAcquireObjectLock(ObjectHeader);
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 ObpReleaseObjectLock(ObjectHeader);
276 }
277 else
278 {
279 /* Remove the flag */
280 ObjectHeader->Flags &= ~OB_FLAG_PERMANENT;
281
282 /* Release the lock */
283 ObpReleaseObjectLock(ObjectHeader);
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 > OBP_NAME_LOOKASIDE_MAX_SIZE))
304 {
305 /* Nope, allocate directly from pool */
306 /* Since we later use MaximumLength to detect that we're not allocating
307 * from a list, we need at least MaximumLength + sizeof(UNICODE_NULL)
308 * here.
309 *
310 * People do call this with UseLookasideList FALSE so the distinction
311 * is critical.
312 */
313 if (MaximumLength <= OBP_NAME_LOOKASIDE_MAX_SIZE)
314 {
315 MaximumLength = OBP_NAME_LOOKASIDE_MAX_SIZE + sizeof(UNICODE_NULL);
316 }
317 Buffer = ExAllocatePoolWithTag(PagedPool,
318 MaximumLength,
319 OB_NAME_TAG);
320 }
321 else
322 {
323 /* Allocate from the lookaside */
324 MaximumLength = OBP_NAME_LOOKASIDE_MAX_SIZE;
325 Buffer = ObpAllocateObjectCreateInfoBuffer(LookasideNameBufferList);
326 }
327
328 /* Setup the string */
329 ObjectName->MaximumLength = (USHORT)MaximumLength;
330 ObjectName->Length = (USHORT)Length;
331 ObjectName->Buffer = Buffer;
332 return Buffer;
333 }
334
335 VOID
336 NTAPI
337 ObpFreeObjectNameBuffer(IN PUNICODE_STRING Name)
338 {
339 PVOID Buffer = Name->Buffer;
340
341 /* We know this is a pool-allocation if the size doesn't match */
342 if (Name->MaximumLength != OBP_NAME_LOOKASIDE_MAX_SIZE)
343 {
344 /* Free it from the pool */
345 ExFreePool(Buffer);
346 }
347 else
348 {
349 /* Otherwise, free from the lookaside */
350 ObpFreeCapturedAttributes(Buffer, LookasideNameBufferList);
351 }
352 }
353
354 NTSTATUS
355 NTAPI
356 ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,
357 IN PUNICODE_STRING ObjectName,
358 IN KPROCESSOR_MODE AccessMode,
359 IN BOOLEAN UseLookaside)
360 {
361 NTSTATUS Status = STATUS_SUCCESS;
362 ULONG StringLength;
363 PWCHAR StringBuffer = NULL;
364 UNICODE_STRING LocalName;
365 PAGED_CODE();
366
367 /* Initialize the Input String */
368 RtlInitEmptyUnicodeString(CapturedName, NULL, 0);
369
370 /* Protect everything */
371 _SEH2_TRY
372 {
373 /* Check if we came from user mode */
374 if (AccessMode != KernelMode)
375 {
376 /* First Probe the String */
377 LocalName = ProbeForReadUnicodeString(ObjectName);
378 ProbeForRead(LocalName.Buffer, LocalName.Length, sizeof(WCHAR));
379 }
380 else
381 {
382 /* No probing needed */
383 LocalName = *ObjectName;
384 }
385
386 /* Make sure there really is a string */
387 if ((StringLength = LocalName.Length))
388 {
389 /* Check that the size is a valid WCHAR multiple */
390 if ((StringLength & (sizeof(WCHAR) - 1)) ||
391 /* Check that the NULL-termination below will work */
392 (StringLength == (MAXUSHORT - sizeof(UNICODE_NULL) + 1)))
393 {
394 /* PS: Please keep the checks above expanded for clarity */
395 Status = STATUS_OBJECT_NAME_INVALID;
396 }
397 else
398 {
399 /* Allocate the string buffer */
400 StringBuffer = ObpAllocateObjectNameBuffer(StringLength,
401 UseLookaside,
402 CapturedName);
403 if (!StringBuffer)
404 {
405 /* Set failure code */
406 Status = STATUS_INSUFFICIENT_RESOURCES;
407 }
408 else
409 {
410 /* Copy the name */
411 RtlCopyMemory(StringBuffer, LocalName.Buffer, StringLength);
412 StringBuffer[StringLength / sizeof(WCHAR)] = UNICODE_NULL;
413 }
414 }
415 }
416 }
417 _SEH2_EXCEPT(ExSystemExceptionFilter())
418 {
419 /* Handle exception and free the string buffer */
420 Status = _SEH2_GetExceptionCode();
421 if (StringBuffer)
422 {
423 ObpFreeObjectNameBuffer(CapturedName);
424 }
425 }
426 _SEH2_END;
427
428 /* Return */
429 return Status;
430 }
431
432 NTSTATUS
433 NTAPI
434 ObpCaptureObjectCreateInformation(IN POBJECT_ATTRIBUTES ObjectAttributes,
435 IN KPROCESSOR_MODE AccessMode,
436 IN BOOLEAN AllocateFromLookaside,
437 IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
438 OUT PUNICODE_STRING ObjectName)
439 {
440 NTSTATUS Status = STATUS_SUCCESS;
441 PSECURITY_DESCRIPTOR SecurityDescriptor;
442 PSECURITY_QUALITY_OF_SERVICE SecurityQos;
443 PUNICODE_STRING LocalObjectName = NULL;
444 PAGED_CODE();
445
446 /* Zero out the Capture Data */
447 RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION));
448
449 /* SEH everything here for protection */
450 _SEH2_TRY
451 {
452 /* Check if we got attributes */
453 if (ObjectAttributes)
454 {
455 /* Check if we're in user mode */
456 if (AccessMode != KernelMode)
457 {
458 /* Probe the attributes */
459 ProbeForRead(ObjectAttributes,
460 sizeof(OBJECT_ATTRIBUTES),
461 sizeof(ULONG));
462 }
463
464 /* Validate the Size and Attributes */
465 if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) ||
466 (ObjectAttributes->Attributes & ~OBJ_VALID_ATTRIBUTES))
467 {
468 /* Invalid combination, fail */
469 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
470 }
471
472 /* Set some Create Info */
473 ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory;
474 ObjectCreateInfo->Attributes = ObjectAttributes->Attributes;
475 LocalObjectName = ObjectAttributes->ObjectName;
476 SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
477 SecurityQos = ObjectAttributes->SecurityQualityOfService;
478
479 /* Check if we have a security descriptor */
480 if (SecurityDescriptor)
481 {
482 /* Capture it */
483 Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
484 AccessMode,
485 NonPagedPool,
486 TRUE,
487 &ObjectCreateInfo->
488 SecurityDescriptor);
489 if (!NT_SUCCESS(Status))
490 {
491 /* Capture failed, quit */
492 ObjectCreateInfo->SecurityDescriptor = NULL;
493 _SEH2_YIELD(return Status);
494 }
495
496 /* Save the probe mode and security descriptor size */
497 ObjectCreateInfo->SecurityDescriptorCharge = 2048; /* FIXME */
498 ObjectCreateInfo->ProbeMode = AccessMode;
499 }
500
501 /* Check if we have QoS */
502 if (SecurityQos)
503 {
504 /* Check if we came from user mode */
505 if (AccessMode != KernelMode)
506 {
507 /* Validate the QoS */
508 ProbeForRead(SecurityQos,
509 sizeof(SECURITY_QUALITY_OF_SERVICE),
510 sizeof(ULONG));
511 }
512
513 /* Save Info */
514 ObjectCreateInfo->SecurityQualityOfService = *SecurityQos;
515 ObjectCreateInfo->SecurityQos =
516 &ObjectCreateInfo->SecurityQualityOfService;
517 }
518 }
519 else
520 {
521 /* We don't have a name */
522 LocalObjectName = NULL;
523 }
524 }
525 _SEH2_EXCEPT(ExSystemExceptionFilter())
526 {
527 /* Cleanup and return the exception code */
528 ObpReleaseObjectCreateInformation(ObjectCreateInfo);
529 _SEH2_YIELD(return _SEH2_GetExceptionCode());
530 }
531 _SEH2_END;
532
533 /* Now check if the Object Attributes had an Object Name */
534 if (LocalObjectName)
535 {
536 Status = ObpCaptureObjectName(ObjectName,
537 LocalObjectName,
538 AccessMode,
539 AllocateFromLookaside);
540 }
541 else
542 {
543 /* Clear the string */
544 RtlInitEmptyUnicodeString(ObjectName, NULL, 0);
545
546 /* He can't have specified a Root Directory */
547 if (ObjectCreateInfo->RootDirectory)
548 {
549 Status = STATUS_OBJECT_NAME_INVALID;
550 }
551 }
552
553 /* Cleanup if we failed */
554 if (!NT_SUCCESS(Status))
555 {
556 ObpReleaseObjectCreateInformation(ObjectCreateInfo);
557 }
558
559 /* Return status to caller */
560 return Status;
561 }
562
563 VOID
564 NTAPI
565 ObFreeObjectCreateInfoBuffer(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
566 {
567 /* Call the macro. We use this function to isolate Ob internals from Io */
568 ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
569 }
570
571 NTSTATUS
572 NTAPI
573 ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
574 IN PUNICODE_STRING ObjectName,
575 IN POBJECT_TYPE ObjectType,
576 IN ULONG ObjectSize,
577 IN KPROCESSOR_MODE PreviousMode,
578 IN POBJECT_HEADER *ObjectHeader)
579 {
580 POBJECT_HEADER Header;
581 ULONG QuotaSize, HandleSize, NameSize, CreatorSize;
582 POBJECT_HEADER_HANDLE_INFO HandleInfo;
583 POBJECT_HEADER_NAME_INFO NameInfo;
584 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
585 POBJECT_HEADER_QUOTA_INFO QuotaInfo;
586 POOL_TYPE PoolType;
587 ULONG FinalSize;
588 ULONG Tag;
589 PAGED_CODE();
590
591 /* Accounting */
592 ObpObjectsCreated++;
593
594 /* Check if we don't have an Object Type yet */
595 if (!ObjectType)
596 {
597 /* Use default tag and non-paged pool */
598 PoolType = NonPagedPool;
599 Tag = 'TjbO';
600 }
601 else
602 {
603 /* Use the pool and tag given */
604 PoolType = ObjectType->TypeInfo.PoolType;
605 Tag = ObjectType->Key;
606 }
607
608 /* Check if we have no create information (ie: we're an object type) */
609 if (!ObjectCreateInfo)
610 {
611 /* Use defaults */
612 QuotaSize = HandleSize = 0;
613 NameSize = sizeof(OBJECT_HEADER_NAME_INFO);
614 CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
615 }
616 else
617 {
618 /* Check if we have quota */
619 if ((((ObjectCreateInfo->PagedPoolCharge !=
620 ObjectType->TypeInfo.DefaultPagedPoolCharge) ||
621 (ObjectCreateInfo->NonPagedPoolCharge !=
622 ObjectType->TypeInfo.DefaultNonPagedPoolCharge) ||
623 (ObjectCreateInfo->SecurityDescriptorCharge > 2048)) &&
624 (PsGetCurrentProcess() != PsInitialSystemProcess)) ||
625 (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
626 {
627 /* Set quota size */
628 QuotaSize = sizeof(OBJECT_HEADER_QUOTA_INFO);
629 ObpObjectsWithPoolQuota++;
630 }
631 else
632 {
633 /* No Quota */
634 QuotaSize = 0;
635 }
636
637 /* Check if we have a handle database */
638 if (ObjectType->TypeInfo.MaintainHandleCount)
639 {
640 /* Set handle database size */
641 HandleSize = sizeof(OBJECT_HEADER_HANDLE_INFO);
642 ObpObjectsWithHandleDB++;
643 }
644 else
645 {
646 /* None */
647 HandleSize = 0;
648 }
649
650 /* Check if the Object has a name */
651 if (ObjectName->Buffer)
652 {
653 /* Set name size */
654 NameSize = sizeof(OBJECT_HEADER_NAME_INFO);
655 ObpObjectsWithName++;
656 }
657 else
658 {
659 /* No name */
660 NameSize = 0;
661 }
662
663 /* Check if the Object maintains type lists */
664 if (ObjectType->TypeInfo.MaintainTypeList)
665 {
666 /* Set owner/creator size */
667 CreatorSize = sizeof(OBJECT_HEADER_CREATOR_INFO);
668 ObpObjectsWithCreatorInfo++;
669 }
670 else
671 {
672 /* No info */
673 CreatorSize = 0;
674 }
675 }
676
677 /* Set final header size */
678 FinalSize = QuotaSize +
679 HandleSize +
680 NameSize +
681 CreatorSize +
682 FIELD_OFFSET(OBJECT_HEADER, Body);
683
684 /* Allocate memory for the Object and Header */
685 Header = ExAllocatePoolWithTag(PoolType, FinalSize + ObjectSize, Tag);
686 if (!Header) return STATUS_INSUFFICIENT_RESOURCES;
687
688 /* Check if we have a quota header */
689 if (QuotaSize)
690 {
691 /* Initialize quota info */
692 QuotaInfo = (POBJECT_HEADER_QUOTA_INFO)Header;
693 QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge;
694 QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge;
695 QuotaInfo->SecurityDescriptorCharge = ObjectCreateInfo->SecurityDescriptorCharge;
696 QuotaInfo->ExclusiveProcess = NULL;
697 Header = (POBJECT_HEADER)(QuotaInfo + 1);
698 }
699
700 /* Check if we have a handle database header */
701 if (HandleSize)
702 {
703 /* Initialize Handle Info */
704 HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header;
705 HandleInfo->SingleEntry.HandleCount = 0;
706 Header = (POBJECT_HEADER)(HandleInfo + 1);
707 }
708
709 /* Check if we have a name header */
710 if (NameSize)
711 {
712 /* Initialize the Object Name Info */
713 NameInfo = (POBJECT_HEADER_NAME_INFO)Header;
714 NameInfo->Name = *ObjectName;
715 NameInfo->Directory = NULL;
716 NameInfo->QueryReferences = 1;
717
718 /* Check if this is a call with the special protection flag */
719 if ((PreviousMode == KernelMode) &&
720 (ObjectCreateInfo) &&
721 (ObjectCreateInfo->Attributes & 0x10000))
722 {
723 /* Set flag which will make the object protected from user-mode */
724 NameInfo->QueryReferences |= 0x40000000;
725 }
726
727 /* Set the header pointer */
728 Header = (POBJECT_HEADER)(NameInfo + 1);
729 }
730
731 /* Check if we have a creator header */
732 if (CreatorSize)
733 {
734 /* Initialize Creator Info */
735 CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header;
736 CreatorInfo->CreatorBackTraceIndex = 0;
737 CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId();
738 InitializeListHead(&CreatorInfo->TypeList);
739 Header = (POBJECT_HEADER)(CreatorInfo + 1);
740 }
741
742 /* Check for quota information */
743 if (QuotaSize)
744 {
745 /* Set the offset */
746 Header->QuotaInfoOffset = (UCHAR)(QuotaSize +
747 HandleSize +
748 NameSize +
749 CreatorSize);
750 }
751 else
752 {
753 /* No offset */
754 Header->QuotaInfoOffset = 0;
755 }
756
757 /* Check for handle information */
758 if (HandleSize)
759 {
760 /* Set the offset */
761 Header->HandleInfoOffset = (UCHAR)(HandleSize +
762 NameSize +
763 CreatorSize);
764 }
765 else
766 {
767 /* No offset */
768 Header->HandleInfoOffset = 0;
769 }
770
771 /* Check for name information */
772 if (NameSize)
773 {
774 /* Set the offset */
775 Header->NameInfoOffset = (UCHAR)(NameSize + CreatorSize);
776 }
777 else
778 {
779 /* No Name */
780 Header->NameInfoOffset = 0;
781 }
782
783 /* Set the new object flag */
784 Header->Flags = OB_FLAG_CREATE_INFO;
785
786 /* Remember if we have creator info */
787 if (CreatorSize) Header->Flags |= OB_FLAG_CREATOR_INFO;
788
789 /* Remember if we have handle info */
790 if (HandleSize) Header->Flags |= OB_FLAG_SINGLE_PROCESS;
791
792 /* Initialize the object header */
793 Header->PointerCount = 1;
794 Header->HandleCount = 0;
795 Header->Type = ObjectType;
796 Header->ObjectCreateInfo = ObjectCreateInfo;
797 Header->SecurityDescriptor = NULL;
798
799 /* Check if this is a permanent object */
800 if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_PERMANENT))
801 {
802 /* Set the needed flag so we can check */
803 Header->Flags |= OB_FLAG_PERMANENT;
804 }
805
806 /* Check if this is an exclusive object */
807 if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
808 {
809 /* Set the needed flag so we can check */
810 Header->Flags |= OB_FLAG_EXCLUSIVE;
811 }
812
813 /* Set kernel-mode flag */
814 if (PreviousMode == KernelMode) Header->Flags |= OB_FLAG_KERNEL_MODE;
815
816 /* Check if we have a type */
817 if (ObjectType)
818 {
819 /* Increase the number of objects of this type */
820 InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfObjects);
821
822 /* Update the high water */
823 ObjectType->HighWaterNumberOfObjects = max(ObjectType->
824 TotalNumberOfObjects,
825 ObjectType->
826 HighWaterNumberOfObjects);
827 }
828
829 /* Return Header */
830 *ObjectHeader = Header;
831 return STATUS_SUCCESS;
832 }
833
834 NTSTATUS
835 NTAPI
836 ObQueryTypeInfo(IN POBJECT_TYPE ObjectType,
837 OUT POBJECT_TYPE_INFORMATION ObjectTypeInfo,
838 IN ULONG Length,
839 OUT PULONG ReturnLength)
840 {
841 NTSTATUS Status = STATUS_SUCCESS;
842 PWSTR InfoBuffer;
843
844 /* Enter SEH */
845 _SEH2_TRY
846 {
847 /* Set return length aligned to 4-byte boundary */
848 *ReturnLength += sizeof(*ObjectTypeInfo) +
849 ALIGN_UP(ObjectType->Name.MaximumLength, ULONG);
850
851 /* Check if thats too much though. */
852 if (Length < *ReturnLength)
853 {
854 _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH);
855 }
856
857 /* Build the data */
858 ObjectTypeInfo->TotalNumberOfHandles =
859 ObjectType->TotalNumberOfHandles;
860 ObjectTypeInfo->TotalNumberOfObjects =
861 ObjectType->TotalNumberOfObjects;
862 ObjectTypeInfo->HighWaterNumberOfHandles =
863 ObjectType->HighWaterNumberOfHandles;
864 ObjectTypeInfo->HighWaterNumberOfObjects =
865 ObjectType->HighWaterNumberOfObjects;
866 ObjectTypeInfo->PoolType =
867 ObjectType->TypeInfo.PoolType;
868 ObjectTypeInfo->DefaultNonPagedPoolCharge =
869 ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
870 ObjectTypeInfo->DefaultPagedPoolCharge =
871 ObjectType->TypeInfo.DefaultPagedPoolCharge;
872 ObjectTypeInfo->ValidAccessMask =
873 ObjectType->TypeInfo.ValidAccessMask;
874 ObjectTypeInfo->SecurityRequired =
875 ObjectType->TypeInfo.SecurityRequired;
876 ObjectTypeInfo->InvalidAttributes =
877 ObjectType->TypeInfo.InvalidAttributes;
878 ObjectTypeInfo->GenericMapping =
879 ObjectType->TypeInfo.GenericMapping;
880 ObjectTypeInfo->MaintainHandleCount =
881 ObjectType->TypeInfo.MaintainHandleCount;
882
883 /* Setup the name buffer */
884 InfoBuffer = (PWSTR)(ObjectTypeInfo + 1);
885 ObjectTypeInfo->TypeName.Buffer = InfoBuffer;
886 ObjectTypeInfo->TypeName.MaximumLength = ObjectType->Name.MaximumLength;
887 ObjectTypeInfo->TypeName.Length = ObjectType->Name.Length;
888
889 /* Copy it */
890 RtlCopyMemory(InfoBuffer,
891 ObjectType->Name.Buffer,
892 ObjectType->Name.Length);
893
894 /* Null-terminate it */
895 (InfoBuffer)[ObjectType->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
896 }
897 _SEH2_EXCEPT(ExSystemExceptionFilter())
898 {
899 /* Otherwise, get the exception code */
900 Status = _SEH2_GetExceptionCode();
901 }
902 _SEH2_END;
903
904 /* Return status to caller */
905 return Status;
906 }
907
908
909 /* PUBLIC FUNCTIONS **********************************************************/
910
911 NTSTATUS
912 NTAPI
913 ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL,
914 IN POBJECT_TYPE Type,
915 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
916 IN KPROCESSOR_MODE AccessMode,
917 IN OUT PVOID ParseContext OPTIONAL,
918 IN ULONG ObjectSize,
919 IN ULONG PagedPoolCharge OPTIONAL,
920 IN ULONG NonPagedPoolCharge OPTIONAL,
921 OUT PVOID *Object)
922 {
923 NTSTATUS Status;
924 POBJECT_CREATE_INFORMATION ObjectCreateInfo;
925 UNICODE_STRING ObjectName;
926 POBJECT_HEADER Header;
927
928 /* Allocate a capture buffer */
929 ObjectCreateInfo = ObpAllocateObjectCreateInfoBuffer(LookasideCreateInfoList);
930 if (!ObjectCreateInfo) return STATUS_INSUFFICIENT_RESOURCES;
931
932 /* Capture all the info */
933 Status = ObpCaptureObjectCreateInformation(ObjectAttributes,
934 ProbeMode,
935 FALSE,
936 ObjectCreateInfo,
937 &ObjectName);
938 if (NT_SUCCESS(Status))
939 {
940 /* Validate attributes */
941 if (Type->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes)
942 {
943 /* Fail */
944 Status = STATUS_INVALID_PARAMETER;
945 }
946 else
947 {
948 /* Check if we have a paged charge */
949 if (!PagedPoolCharge)
950 {
951 /* Save it */
952 PagedPoolCharge = Type->TypeInfo.DefaultPagedPoolCharge;
953 }
954
955 /* Check for nonpaged charge */
956 if (!NonPagedPoolCharge)
957 {
958 /* Save it */
959 NonPagedPoolCharge = Type->TypeInfo.DefaultNonPagedPoolCharge;
960 }
961
962 /* Write the pool charges */
963 ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge;
964 ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge;
965
966 /* Allocate the Object */
967 Status = ObpAllocateObject(ObjectCreateInfo,
968 &ObjectName,
969 Type,
970 ObjectSize,
971 AccessMode,
972 &Header);
973 if (NT_SUCCESS(Status))
974 {
975 /* Return the Object */
976 *Object = &Header->Body;
977
978 /* Check if this is a permanent object */
979 if (Header->Flags & OB_FLAG_PERMANENT)
980 {
981 /* Do the privilege check */
982 if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
983 ProbeMode))
984 {
985 /* Fail */
986 ObpDeallocateObject(*Object);
987 Status = STATUS_PRIVILEGE_NOT_HELD;
988 }
989 }
990
991 /* Return status */
992 return Status;
993 }
994 }
995
996 /* Release the Capture Info, we don't need it */
997 ObpFreeObjectCreateInformation(ObjectCreateInfo);
998 if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
999 }
1000
1001 /* We failed, so release the Buffer */
1002 ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
1003 return Status;
1004 }
1005
1006 NTSTATUS
1007 NTAPI
1008 ObCreateObjectType(IN PUNICODE_STRING TypeName,
1009 IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
1010 IN PVOID Reserved,
1011 OUT POBJECT_TYPE *ObjectType)
1012 {
1013 POBJECT_HEADER Header;
1014 POBJECT_TYPE LocalObjectType;
1015 ULONG HeaderSize;
1016 NTSTATUS Status;
1017 CHAR Tag[4];
1018 OBP_LOOKUP_CONTEXT Context;
1019 PWCHAR p;
1020 ULONG i;
1021 UNICODE_STRING ObjectName;
1022 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
1023
1024 /* Verify parameters */
1025 if (!(TypeName) ||
1026 !(TypeName->Length) ||
1027 (TypeName->Length % sizeof(WCHAR)) ||
1028 !(ObjectTypeInitializer) ||
1029 (ObjectTypeInitializer->Length != sizeof(*ObjectTypeInitializer)) ||
1030 (ObjectTypeInitializer->InvalidAttributes & ~OBJ_VALID_ATTRIBUTES) ||
1031 (ObjectTypeInitializer->MaintainHandleCount &&
1032 (!(ObjectTypeInitializer->OpenProcedure) &&
1033 !ObjectTypeInitializer->CloseProcedure)) ||
1034 ((!ObjectTypeInitializer->UseDefaultObject) &&
1035 (ObjectTypeInitializer->PoolType != NonPagedPool)))
1036 {
1037 /* Fail */
1038 return STATUS_INVALID_PARAMETER;
1039 }
1040
1041 /* Make sure the name doesn't have a separator */
1042 p = TypeName->Buffer;
1043 i = TypeName->Length / sizeof(WCHAR);
1044 while (i--)
1045 {
1046 /* Check for one and fail */
1047 if (*p++ == OBJ_NAME_PATH_SEPARATOR) return STATUS_OBJECT_NAME_INVALID;
1048 }
1049
1050 /* Setup a lookup context */
1051 ObpInitializeLookupContext(&Context);
1052
1053 /* Check if we've already created the directory of types */
1054 if (ObpTypeDirectoryObject)
1055 {
1056 /* Acquire the directory lock */
1057 ObpAcquireDirectoryLockExclusive(ObpTypeDirectoryObject, &Context);
1058
1059 /* Do the lookup */
1060 if (ObpLookupEntryDirectory(ObpTypeDirectoryObject,
1061 TypeName,
1062 OBJ_CASE_INSENSITIVE,
1063 FALSE,
1064 &Context))
1065 {
1066 /* We have already created it, so fail */
1067 ObpReleaseLookupContext(&Context);
1068 return STATUS_OBJECT_NAME_COLLISION;
1069 }
1070 }
1071
1072 /* Now make a copy of the object name */
1073 ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool,
1074 TypeName->MaximumLength,
1075 OB_NAME_TAG);
1076 if (!ObjectName.Buffer)
1077 {
1078 /* Out of memory, fail */
1079 ObpReleaseLookupContext(&Context);
1080 return STATUS_INSUFFICIENT_RESOURCES;
1081 }
1082
1083 /* Set the length and copy the name */
1084 ObjectName.MaximumLength = TypeName->MaximumLength;
1085 RtlCopyUnicodeString(&ObjectName, TypeName);
1086
1087 /* Allocate the Object */
1088 Status = ObpAllocateObject(NULL,
1089 &ObjectName,
1090 ObpTypeObjectType,
1091 sizeof(OBJECT_TYPE),
1092 KernelMode,
1093 (POBJECT_HEADER*)&Header);
1094 if (!NT_SUCCESS(Status))
1095 {
1096 /* Free the name and fail */
1097 ObpReleaseLookupContext(&Context);
1098 ExFreePool(ObjectName.Buffer);
1099 return Status;
1100 }
1101
1102 /* Setup the flags and name */
1103 LocalObjectType = (POBJECT_TYPE)&Header->Body;
1104 LocalObjectType->Name = ObjectName;
1105 Header->Flags |= OB_FLAG_KERNEL_MODE | OB_FLAG_PERMANENT;
1106
1107 /* Clear accounting data */
1108 LocalObjectType->TotalNumberOfObjects =
1109 LocalObjectType->TotalNumberOfHandles =
1110 LocalObjectType->HighWaterNumberOfObjects =
1111 LocalObjectType->HighWaterNumberOfHandles = 0;
1112
1113 /* Check if this is the first Object Type */
1114 if (!ObpTypeObjectType)
1115 {
1116 /* It is, so set this as the type object */
1117 ObpTypeObjectType = LocalObjectType;
1118 Header->Type = ObpTypeObjectType;
1119
1120 /* Set the hard-coded key and object count */
1121 LocalObjectType->TotalNumberOfObjects = 1;
1122 LocalObjectType->Key = 'TjbO';
1123 }
1124 else
1125 {
1126 /* Set Tag */
1127 Tag[0] = (CHAR)TypeName->Buffer[0];
1128 Tag[1] = (CHAR)TypeName->Buffer[1];
1129 Tag[2] = (CHAR)TypeName->Buffer[2];
1130 Tag[3] = (CHAR)TypeName->Buffer[3];
1131 LocalObjectType->Key = *(PULONG)Tag;
1132 }
1133
1134 /* Set up the type information */
1135 LocalObjectType->TypeInfo = *ObjectTypeInitializer;
1136 LocalObjectType->TypeInfo.PoolType = ObjectTypeInitializer->PoolType;
1137
1138 /* Check if we have to maintain a type list */
1139 if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST)
1140 {
1141 /* Enable support */
1142 LocalObjectType->TypeInfo.MaintainTypeList = TRUE;
1143 }
1144
1145 /* Calculate how much space our header'll take up */
1146 HeaderSize = sizeof(OBJECT_HEADER) +
1147 sizeof(OBJECT_HEADER_NAME_INFO) +
1148 (ObjectTypeInitializer->MaintainHandleCount ?
1149 sizeof(OBJECT_HEADER_HANDLE_INFO) : 0);
1150
1151 /* Check the pool type */
1152 if (ObjectTypeInitializer->PoolType == NonPagedPool)
1153 {
1154 /* Update the NonPaged Pool charge */
1155 LocalObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderSize;
1156 }
1157 else
1158 {
1159 /* Update the Paged Pool charge */
1160 LocalObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderSize;
1161 }
1162
1163 /* All objects types need a security procedure */
1164 if (!ObjectTypeInitializer->SecurityProcedure)
1165 {
1166 LocalObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod;
1167 }
1168
1169 /* Select the Wait Object */
1170 if (LocalObjectType->TypeInfo.UseDefaultObject)
1171 {
1172 /* Add the SYNCHRONIZE access mask since it's waitable */
1173 LocalObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE;
1174
1175 /* Use the "Default Object", a simple event */
1176 LocalObjectType->DefaultObject = &ObpDefaultObject;
1177 }
1178 /* The File Object gets an optimized hack so it can be waited on */
1179 else if ((TypeName->Length == 8) && !(wcscmp(TypeName->Buffer, L"File")))
1180 {
1181 /* Wait on the File Object's event directly */
1182 LocalObjectType->DefaultObject = (PVOID)FIELD_OFFSET(FILE_OBJECT,
1183 Event);
1184 }
1185 else if ((TypeName->Length == 24) && !(wcscmp(TypeName->Buffer, L"WaitablePort")))
1186 {
1187 /* Wait on the LPC Port's object directly */
1188 LocalObjectType->DefaultObject = (PVOID)FIELD_OFFSET(LPCP_PORT_OBJECT,
1189 WaitEvent);
1190 }
1191 else
1192 {
1193 /* No default Object */
1194 LocalObjectType->DefaultObject = NULL;
1195 }
1196
1197 /* Initialize Object Type components */
1198 ExInitializeResourceLite(&LocalObjectType->Mutex);
1199 for (i = 0; i < 4; i++)
1200 {
1201 /* Initialize the object locks */
1202 ExInitializeResourceLite(&LocalObjectType->ObjectLocks[i]);
1203 }
1204 InitializeListHead(&LocalObjectType->TypeList);
1205
1206 /* Lock the object type */
1207 ObpEnterObjectTypeMutex(LocalObjectType);
1208
1209 /* Get creator info and insert it into the type list */
1210 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
1211 if (CreatorInfo) InsertTailList(&ObpTypeObjectType->TypeList,
1212 &CreatorInfo->TypeList);
1213
1214 /* Set the index and the entry into the object type array */
1215 LocalObjectType->Index = ObpTypeObjectType->TotalNumberOfObjects;
1216 if (LocalObjectType->Index < 32)
1217 {
1218 /* It fits, insert it */
1219 ObpObjectTypes[LocalObjectType->Index - 1] = LocalObjectType;
1220 }
1221
1222 /* Release the object type */
1223 ObpLeaveObjectTypeMutex(LocalObjectType);
1224
1225 /* Check if we're actually creating the directory object itself */
1226 if (!(ObpTypeDirectoryObject) ||
1227 (ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header)))
1228 {
1229 /* Check if the type directory exists */
1230 if (ObpTypeDirectoryObject)
1231 {
1232 /* Reference it */
1233 ObReferenceObject(ObpTypeDirectoryObject);
1234 }
1235
1236 /* Cleanup the lookup context */
1237 ObpReleaseLookupContext(&Context);
1238
1239 /* Return the object type and success */
1240 *ObjectType = LocalObjectType;
1241 return STATUS_SUCCESS;
1242 }
1243
1244 /* If we got here, then we failed */
1245 ObpReleaseLookupContext(&Context);
1246 return STATUS_INSUFFICIENT_RESOURCES;
1247 }
1248
1249 VOID
1250 NTAPI
1251 ObpDeleteObjectType(IN PVOID Object)
1252 {
1253 ULONG i;
1254 POBJECT_TYPE ObjectType = (PVOID)Object;
1255
1256 /* Loop our locks */
1257 for (i = 0; i < 4; i++)
1258 {
1259 /* Delete each one */
1260 ExDeleteResourceLite(&ObjectType->ObjectLocks[i]);
1261 }
1262
1263 /* Delete our main mutex */
1264 ExDeleteResourceLite(&ObjectType->Mutex);
1265 }
1266
1267 /*++
1268 * @name ObMakeTemporaryObject
1269 * @implemented NT4
1270 *
1271 * The ObMakeTemporaryObject routine <FILLMEIN>
1272 *
1273 * @param ObjectBody
1274 * <FILLMEIN>
1275 *
1276 * @return None.
1277 *
1278 * @remarks None.
1279 *
1280 *--*/
1281 VOID
1282 NTAPI
1283 ObMakeTemporaryObject(IN PVOID ObjectBody)
1284 {
1285 PAGED_CODE();
1286
1287 /* Call the internal API */
1288 ObpSetPermanentObject(ObjectBody, FALSE);
1289 }
1290
1291 /*++
1292 * @name NtMakeTemporaryObject
1293 * @implemented NT4
1294 *
1295 * The NtMakeTemporaryObject routine <FILLMEIN>
1296 *
1297 * @param ObjectHandle
1298 * <FILLMEIN>
1299 *
1300 * @return STATUS_SUCCESS or appropriate error value.
1301 *
1302 * @remarks None.
1303 *
1304 *--*/
1305 NTSTATUS
1306 NTAPI
1307 NtMakeTemporaryObject(IN HANDLE ObjectHandle)
1308 {
1309 PVOID ObjectBody;
1310 NTSTATUS Status;
1311 PAGED_CODE();
1312
1313 /* Reference the object for DELETE access */
1314 Status = ObReferenceObjectByHandle(ObjectHandle,
1315 DELETE,
1316 NULL,
1317 KeGetPreviousMode(),
1318 &ObjectBody,
1319 NULL);
1320 if (Status != STATUS_SUCCESS) return Status;
1321
1322 /* Set it as temporary and dereference it */
1323 ObpSetPermanentObject(ObjectBody, FALSE);
1324 ObDereferenceObject(ObjectBody);
1325 return STATUS_SUCCESS;
1326 }
1327
1328 /*++
1329 * @name NtMakePermanentObject
1330 * @implemented NT4
1331 *
1332 * The NtMakePermanentObject routine <FILLMEIN>
1333 *
1334 * @param ObjectHandle
1335 * <FILLMEIN>
1336 *
1337 * @return STATUS_SUCCESS or appropriate error value.
1338 *
1339 * @remarks None.
1340 *
1341 *--*/
1342 NTSTATUS
1343 NTAPI
1344 NtMakePermanentObject(IN HANDLE ObjectHandle)
1345 {
1346 PVOID ObjectBody;
1347 NTSTATUS Status;
1348 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1349 PAGED_CODE();
1350
1351 /* Make sure that the caller has SeCreatePermanentPrivilege */
1352 Status = SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
1353 PreviousMode);
1354 if (!NT_SUCCESS(Status)) return STATUS_PRIVILEGE_NOT_HELD;
1355
1356 /* Reference the object */
1357 Status = ObReferenceObjectByHandle(ObjectHandle,
1358 0,
1359 NULL,
1360 PreviousMode,
1361 &ObjectBody,
1362 NULL);
1363 if (Status != STATUS_SUCCESS) return Status;
1364
1365 /* Set it as permanent and dereference it */
1366 ObpSetPermanentObject(ObjectBody, TRUE);
1367 ObDereferenceObject(ObjectBody);
1368 return STATUS_SUCCESS;
1369 }
1370
1371 /*++
1372 * @name NtQueryObject
1373 * @implemented NT4
1374 *
1375 * The NtQueryObject routine <FILLMEIN>
1376 *
1377 * @param ObjectHandle
1378 * <FILLMEIN>
1379 *
1380 * @param ObjectInformationClass
1381 * <FILLMEIN>
1382 *
1383 * @param ObjectInformation
1384 * <FILLMEIN>
1385 *
1386 * @param Length
1387 * <FILLMEIN>
1388 *
1389 * @param ResultLength
1390 * <FILLMEIN>
1391 *
1392 * @return STATUS_SUCCESS or appropriate error value.
1393 *
1394 * @remarks None.
1395 *
1396 *--*/
1397 NTSTATUS
1398 NTAPI
1399 NtQueryObject(IN HANDLE ObjectHandle,
1400 IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1401 OUT PVOID ObjectInformation,
1402 IN ULONG Length,
1403 OUT PULONG ResultLength OPTIONAL)
1404 {
1405 OBJECT_HANDLE_INFORMATION HandleInfo;
1406 POBJECT_HEADER ObjectHeader = NULL;
1407 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
1408 POBJECT_BASIC_INFORMATION BasicInfo;
1409 ULONG InfoLength;
1410 PVOID Object = NULL;
1411 NTSTATUS Status;
1412 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1413 PAGED_CODE();
1414
1415 /* Check if the caller is from user mode */
1416 if (PreviousMode != KernelMode)
1417 {
1418 /* Protect validation with SEH */
1419 _SEH2_TRY
1420 {
1421 /* Probe the input structure */
1422 ProbeForWrite(ObjectInformation, Length, sizeof(UCHAR));
1423
1424 /* If we have a result length, probe it too */
1425 if (ResultLength) ProbeForWriteUlong(ResultLength);
1426 }
1427 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1428 {
1429 /* Return the exception code */
1430 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1431 }
1432 _SEH2_END;
1433 }
1434
1435 /*
1436 * Make sure this isn't a generic type query, since the caller doesn't
1437 * have to give a handle for it
1438 */
1439 if (ObjectInformationClass != ObjectTypesInformation)
1440 {
1441 /* Reference the object */
1442 Status = ObReferenceObjectByHandle(ObjectHandle,
1443 0,
1444 NULL,
1445 KeGetPreviousMode(),
1446 &Object,
1447 &HandleInfo);
1448 if (!NT_SUCCESS (Status)) return Status;
1449
1450 /* Get the object header */
1451 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1452 }
1453
1454 _SEH2_TRY
1455 {
1456 /* Check the information class */
1457 switch (ObjectInformationClass)
1458 {
1459 /* Basic info */
1460 case ObjectBasicInformation:
1461
1462 /* Validate length */
1463 InfoLength = sizeof(OBJECT_BASIC_INFORMATION);
1464 if (Length != sizeof(OBJECT_BASIC_INFORMATION))
1465 {
1466 /* Fail */
1467 Status = STATUS_INFO_LENGTH_MISMATCH;
1468 break;
1469 }
1470
1471 /* Fill out the basic information */
1472 BasicInfo = (POBJECT_BASIC_INFORMATION)ObjectInformation;
1473 BasicInfo->Attributes = HandleInfo.HandleAttributes;
1474 BasicInfo->GrantedAccess = HandleInfo.GrantedAccess;
1475 BasicInfo->HandleCount = ObjectHeader->HandleCount;
1476 BasicInfo->PointerCount = ObjectHeader->PointerCount;
1477
1478 /* Permanent/Exclusive Flags are NOT in Handle attributes! */
1479 if (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE)
1480 {
1481 /* Set the flag */
1482 BasicInfo->Attributes |= OBJ_EXCLUSIVE;
1483 }
1484 if (ObjectHeader->Flags & OB_FLAG_PERMANENT)
1485 {
1486 /* Set the flag */
1487 BasicInfo->Attributes |= OBJ_PERMANENT;
1488 }
1489
1490 /* Copy quota information */
1491 BasicInfo->PagedPoolCharge = 0; /* FIXME*/
1492 BasicInfo->NonPagedPoolCharge = 0; /* FIXME*/
1493
1494 /* Copy name information */
1495 BasicInfo->NameInfoSize = 0; /* FIXME*/
1496 BasicInfo->TypeInfoSize = 0; /* FIXME*/
1497
1498 /* Copy security information */
1499 BasicInfo->SecurityDescriptorSize = 0; /* FIXME*/
1500
1501 /* Check if this is a symlink */
1502 if (ObjectHeader->Type == ObSymbolicLinkType)
1503 {
1504 /* Return the creation time */
1505 BasicInfo->CreationTime.QuadPart =
1506 ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart;
1507 }
1508 else
1509 {
1510 /* Otherwise return 0 */
1511 BasicInfo->CreationTime.QuadPart = (ULONGLONG)0;
1512 }
1513
1514 /* Break out with success */
1515 Status = STATUS_SUCCESS;
1516 break;
1517
1518 /* Name information */
1519 case ObjectNameInformation:
1520
1521 /* Call the helper and break out */
1522 Status = ObQueryNameString(Object,
1523 (POBJECT_NAME_INFORMATION)
1524 ObjectInformation,
1525 Length,
1526 &InfoLength);
1527 break;
1528
1529 /* Information about this type */
1530 case ObjectTypeInformation:
1531
1532 /* Call the helper and break out */
1533 Status = ObQueryTypeInfo(ObjectHeader->Type,
1534 (POBJECT_TYPE_INFORMATION)
1535 ObjectInformation,
1536 Length,
1537 &InfoLength);
1538 break;
1539
1540 /* Information about all types */
1541 case ObjectTypesInformation:
1542 DPRINT1("NOT IMPLEMENTED!\n");
1543 Status = STATUS_NOT_IMPLEMENTED;
1544 break;
1545
1546 /* Information about the handle flags */
1547 case ObjectHandleFlagInformation:
1548
1549 /* Validate length */
1550 InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION);
1551 if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1552 {
1553 Status = STATUS_INFO_LENGTH_MISMATCH;
1554 break;
1555 }
1556
1557 /* Get the structure */
1558 HandleFlags = (POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1559 ObjectInformation;
1560
1561 /* Set the flags */
1562 HandleFlags->Inherit = HandleInfo.HandleAttributes & OBJ_INHERIT;
1563 HandleFlags->ProtectFromClose = (HandleInfo.HandleAttributes &
1564 OBJ_PROTECT_CLOSE) != 0;
1565
1566 /* Break out with success */
1567 Status = STATUS_SUCCESS;
1568 break;
1569
1570 /* Anything else */
1571 default:
1572
1573 /* Fail it */
1574 Status = STATUS_INVALID_INFO_CLASS;
1575 break;
1576 }
1577
1578 /* Check if the caller wanted the return length */
1579 if (ResultLength)
1580 {
1581 /* Write the length */
1582 *ResultLength = Length;
1583 }
1584 }
1585 _SEH2_EXCEPT(ExSystemExceptionFilter())
1586 {
1587 /* Otherwise, get the exception code */
1588 Status = _SEH2_GetExceptionCode();
1589 }
1590 _SEH2_END;
1591
1592 /* Dereference the object if we had referenced it */
1593 if (Object) ObDereferenceObject (Object);
1594
1595 /* Return status */
1596 return Status;
1597 }
1598
1599 /*++
1600 * @name NtSetInformationObject
1601 * @implemented NT4
1602 *
1603 * The NtSetInformationObject routine <FILLMEIN>
1604 *
1605 * @param ObjectHandle
1606 * <FILLMEIN>
1607 *
1608 * @param ObjectInformationClass
1609 * <FILLMEIN>
1610 *
1611 * @param ObjectInformation
1612 * <FILLMEIN>
1613 *
1614 * @param Length
1615 * <FILLMEIN>
1616 *
1617 * @return STATUS_SUCCESS or appropriate error value.
1618 *
1619 * @remarks None.
1620 *
1621 *--*/
1622 NTSTATUS
1623 NTAPI
1624 NtSetInformationObject(IN HANDLE ObjectHandle,
1625 IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1626 IN PVOID ObjectInformation,
1627 IN ULONG Length)
1628 {
1629 NTSTATUS Status;
1630 OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context;
1631 PVOID ObjectTable;
1632 KAPC_STATE ApcState;
1633 BOOLEAN AttachedToProcess = FALSE;
1634 PAGED_CODE();
1635
1636 /* Validate the information class */
1637 if (ObjectInformationClass != ObjectHandleFlagInformation)
1638 {
1639 /* Invalid class */
1640 return STATUS_INVALID_INFO_CLASS;
1641 }
1642
1643 /* Validate the length */
1644 if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1645 {
1646 /* Invalid length */
1647 return STATUS_INFO_LENGTH_MISMATCH;
1648 }
1649
1650 /* Save the previous mode */
1651 Context.PreviousMode = ExGetPreviousMode();
1652
1653 /* Check if we were called from user mode */
1654 if (Context.PreviousMode != KernelMode)
1655 {
1656 /* Enter SEH */
1657 _SEH2_TRY
1658 {
1659 /* Probe and capture the attribute buffer */
1660 ProbeForRead(ObjectInformation,
1661 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION),
1662 sizeof(BOOLEAN));
1663 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1664 ObjectInformation;
1665 }
1666 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1667 {
1668 /* Return the exception code */
1669 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1670 }
1671 _SEH2_END;
1672 }
1673 else
1674 {
1675 /* Just copy the buffer directly */
1676 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1677 ObjectInformation;
1678 }
1679
1680 /* Check if this is a kernel handle */
1681 if (ObIsKernelHandle(ObjectHandle, Context.PreviousMode))
1682 {
1683 /* Get the actual handle */
1684 ObjectHandle = ObKernelHandleToHandle(ObjectHandle);
1685 ObjectTable = ObpKernelHandleTable;
1686
1687 /* Check if we're not in the system process */
1688 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1689 {
1690 /* Attach to it */
1691 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1692 AttachedToProcess = TRUE;
1693 }
1694 }
1695 else
1696 {
1697 /* Use the current table */
1698 ObjectTable = PsGetCurrentProcess()->ObjectTable;
1699 }
1700
1701 /* Change the handle attributes */
1702 if (!ExChangeHandle(ObjectTable,
1703 ObjectHandle,
1704 ObpSetHandleAttributes,
1705 (ULONG_PTR)&Context))
1706 {
1707 /* Some failure */
1708 Status = STATUS_ACCESS_DENIED;
1709 }
1710 else
1711 {
1712 /* We are done */
1713 Status = STATUS_SUCCESS;
1714 }
1715
1716 /* De-attach if we were attached, and return status */
1717 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1718 return Status;
1719 }
1720
1721 /* EOF */