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