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