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