Fix merge r65567.
[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 RtlFreeAnsiString(&AnsiName);
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(ObpTypeObjectType);
1231
1232 /* Get creator info and insert it into the type list */
1233 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
1234 if (CreatorInfo)
1235 {
1236 InsertTailList(&ObpTypeObjectType->TypeList,
1237 &CreatorInfo->TypeList);
1238
1239 /* CORE-8423: Avoid inserting this a second time if someone creates a
1240 * handle to the object type (bug in Windows 2003) */
1241 Header->Flags &= ~OB_FLAG_CREATE_INFO;
1242 }
1243
1244 /* Set the index and the entry into the object type array */
1245 LocalObjectType->Index = ObpTypeObjectType->TotalNumberOfObjects;
1246
1247 NT_ASSERT(LocalObjectType->Index != 0);
1248
1249 if (LocalObjectType->Index < 32)
1250 {
1251 /* It fits, insert it */
1252 ObpObjectTypes[LocalObjectType->Index - 1] = LocalObjectType;
1253 }
1254
1255 /* Release the object type */
1256 ObpLeaveObjectTypeMutex(ObpTypeObjectType);
1257
1258 /* Check if we're actually creating the directory object itself */
1259 if (!(ObpTypeDirectoryObject) ||
1260 (ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header)))
1261 {
1262 /* Check if the type directory exists */
1263 if (ObpTypeDirectoryObject)
1264 {
1265 /* Reference it */
1266 ObReferenceObject(ObpTypeDirectoryObject);
1267 }
1268
1269 /* Cleanup the lookup context */
1270 ObpReleaseLookupContext(&Context);
1271
1272 /* Return the object type and success */
1273 *ObjectType = LocalObjectType;
1274 return STATUS_SUCCESS;
1275 }
1276
1277 /* If we got here, then we failed */
1278 ObpReleaseLookupContext(&Context);
1279 return STATUS_INSUFFICIENT_RESOURCES;
1280 }
1281
1282 VOID
1283 NTAPI
1284 ObDeleteCapturedInsertInfo(IN PVOID Object)
1285 {
1286 POBJECT_HEADER ObjectHeader;
1287 PAGED_CODE();
1288
1289 /* Check if there is anything to free */
1290 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1291 if ((ObjectHeader->Flags & OB_FLAG_CREATE_INFO) &&
1292 (ObjectHeader->ObjectCreateInfo != NULL))
1293 {
1294 /* Free the create info */
1295 ObpFreeObjectCreateInformation(ObjectHeader->ObjectCreateInfo);
1296 ObjectHeader->ObjectCreateInfo = NULL;
1297 }
1298 }
1299
1300 VOID
1301 NTAPI
1302 ObpDeleteObjectType(IN PVOID Object)
1303 {
1304 ULONG i;
1305 POBJECT_TYPE ObjectType = (PVOID)Object;
1306
1307 /* Loop our locks */
1308 for (i = 0; i < 4; i++)
1309 {
1310 /* Delete each one */
1311 ExDeleteResourceLite(&ObjectType->ObjectLocks[i]);
1312 }
1313
1314 /* Delete our main mutex */
1315 ExDeleteResourceLite(&ObjectType->Mutex);
1316 }
1317
1318 /*++
1319 * @name ObMakeTemporaryObject
1320 * @implemented NT4
1321 *
1322 * The ObMakeTemporaryObject routine <FILLMEIN>
1323 *
1324 * @param ObjectBody
1325 * <FILLMEIN>
1326 *
1327 * @return None.
1328 *
1329 * @remarks None.
1330 *
1331 *--*/
1332 VOID
1333 NTAPI
1334 ObMakeTemporaryObject(IN PVOID ObjectBody)
1335 {
1336 PAGED_CODE();
1337
1338 /* Call the internal API */
1339 ObpSetPermanentObject(ObjectBody, FALSE);
1340 }
1341
1342 /*++
1343 * @name NtMakeTemporaryObject
1344 * @implemented NT4
1345 *
1346 * The NtMakeTemporaryObject routine <FILLMEIN>
1347 *
1348 * @param ObjectHandle
1349 * <FILLMEIN>
1350 *
1351 * @return STATUS_SUCCESS or appropriate error value.
1352 *
1353 * @remarks None.
1354 *
1355 *--*/
1356 NTSTATUS
1357 NTAPI
1358 NtMakeTemporaryObject(IN HANDLE ObjectHandle)
1359 {
1360 PVOID ObjectBody;
1361 NTSTATUS Status;
1362 PAGED_CODE();
1363
1364 /* Reference the object for DELETE access */
1365 Status = ObReferenceObjectByHandle(ObjectHandle,
1366 DELETE,
1367 NULL,
1368 KeGetPreviousMode(),
1369 &ObjectBody,
1370 NULL);
1371 if (Status != STATUS_SUCCESS) return Status;
1372
1373 /* Set it as temporary and dereference it */
1374 ObpSetPermanentObject(ObjectBody, FALSE);
1375 ObDereferenceObject(ObjectBody);
1376 return STATUS_SUCCESS;
1377 }
1378
1379 /*++
1380 * @name NtMakePermanentObject
1381 * @implemented NT4
1382 *
1383 * The NtMakePermanentObject routine <FILLMEIN>
1384 *
1385 * @param ObjectHandle
1386 * <FILLMEIN>
1387 *
1388 * @return STATUS_SUCCESS or appropriate error value.
1389 *
1390 * @remarks None.
1391 *
1392 *--*/
1393 NTSTATUS
1394 NTAPI
1395 NtMakePermanentObject(IN HANDLE ObjectHandle)
1396 {
1397 PVOID ObjectBody;
1398 NTSTATUS Status;
1399 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1400 PAGED_CODE();
1401
1402 /* Make sure that the caller has SeCreatePermanentPrivilege */
1403 Status = SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
1404 PreviousMode);
1405 if (!NT_SUCCESS(Status)) return STATUS_PRIVILEGE_NOT_HELD;
1406
1407 /* Reference the object */
1408 Status = ObReferenceObjectByHandle(ObjectHandle,
1409 0,
1410 NULL,
1411 PreviousMode,
1412 &ObjectBody,
1413 NULL);
1414 if (Status != STATUS_SUCCESS) return Status;
1415
1416 /* Set it as permanent and dereference it */
1417 ObpSetPermanentObject(ObjectBody, TRUE);
1418 ObDereferenceObject(ObjectBody);
1419 return STATUS_SUCCESS;
1420 }
1421
1422 /*++
1423 * @name NtQueryObject
1424 * @implemented NT4
1425 *
1426 * The NtQueryObject routine <FILLMEIN>
1427 *
1428 * @param ObjectHandle
1429 * <FILLMEIN>
1430 *
1431 * @param ObjectInformationClass
1432 * <FILLMEIN>
1433 *
1434 * @param ObjectInformation
1435 * <FILLMEIN>
1436 *
1437 * @param Length
1438 * <FILLMEIN>
1439 *
1440 * @param ResultLength
1441 * <FILLMEIN>
1442 *
1443 * @return STATUS_SUCCESS or appropriate error value.
1444 *
1445 * @remarks None.
1446 *
1447 *--*/
1448 NTSTATUS
1449 NTAPI
1450 NtQueryObject(IN HANDLE ObjectHandle,
1451 IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1452 OUT PVOID ObjectInformation,
1453 IN ULONG Length,
1454 OUT PULONG ResultLength OPTIONAL)
1455 {
1456 OBJECT_HANDLE_INFORMATION HandleInfo;
1457 POBJECT_HEADER ObjectHeader = NULL;
1458 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
1459 POBJECT_BASIC_INFORMATION BasicInfo;
1460 ULONG InfoLength = 0;
1461 PVOID Object = NULL;
1462 NTSTATUS Status;
1463 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1464 PAGED_CODE();
1465
1466 /* Check if the caller is from user mode */
1467 if (PreviousMode != KernelMode)
1468 {
1469 /* Protect validation with SEH */
1470 _SEH2_TRY
1471 {
1472 /* Probe the input structure */
1473 ProbeForWrite(ObjectInformation, Length, sizeof(UCHAR));
1474
1475 /* If we have a result length, probe it too */
1476 if (ResultLength) ProbeForWriteUlong(ResultLength);
1477 }
1478 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1479 {
1480 /* Return the exception code */
1481 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1482 }
1483 _SEH2_END;
1484 }
1485
1486 /*
1487 * Make sure this isn't a generic type query, since the caller doesn't
1488 * have to give a handle for it
1489 */
1490 if (ObjectInformationClass != ObjectTypesInformation)
1491 {
1492 /* Reference the object */
1493 Status = ObReferenceObjectByHandle(ObjectHandle,
1494 0,
1495 NULL,
1496 KeGetPreviousMode(),
1497 &Object,
1498 &HandleInfo);
1499 if (!NT_SUCCESS (Status)) return Status;
1500
1501 /* Get the object header */
1502 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1503 }
1504
1505 _SEH2_TRY
1506 {
1507 /* Check the information class */
1508 switch (ObjectInformationClass)
1509 {
1510 /* Basic info */
1511 case ObjectBasicInformation:
1512
1513 /* Validate length */
1514 InfoLength = sizeof(OBJECT_BASIC_INFORMATION);
1515 if (Length != sizeof(OBJECT_BASIC_INFORMATION))
1516 {
1517 /* Fail */
1518 Status = STATUS_INFO_LENGTH_MISMATCH;
1519 break;
1520 }
1521
1522 /* Fill out the basic information */
1523 BasicInfo = (POBJECT_BASIC_INFORMATION)ObjectInformation;
1524 BasicInfo->Attributes = HandleInfo.HandleAttributes;
1525 BasicInfo->GrantedAccess = HandleInfo.GrantedAccess;
1526 BasicInfo->HandleCount = ObjectHeader->HandleCount;
1527 BasicInfo->PointerCount = ObjectHeader->PointerCount;
1528
1529 /* Permanent/Exclusive Flags are NOT in Handle attributes! */
1530 if (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE)
1531 {
1532 /* Set the flag */
1533 BasicInfo->Attributes |= OBJ_EXCLUSIVE;
1534 }
1535 if (ObjectHeader->Flags & OB_FLAG_PERMANENT)
1536 {
1537 /* Set the flag */
1538 BasicInfo->Attributes |= OBJ_PERMANENT;
1539 }
1540
1541 /* Copy quota information */
1542 BasicInfo->PagedPoolCharge = 0; /* FIXME*/
1543 BasicInfo->NonPagedPoolCharge = 0; /* FIXME*/
1544
1545 /* Copy name information */
1546 BasicInfo->NameInfoSize = 0; /* FIXME*/
1547 BasicInfo->TypeInfoSize = 0; /* FIXME*/
1548
1549 /* Copy security information */
1550 BasicInfo->SecurityDescriptorSize = 0; /* FIXME*/
1551
1552 /* Check if this is a symlink */
1553 if (ObjectHeader->Type == ObSymbolicLinkType)
1554 {
1555 /* Return the creation time */
1556 BasicInfo->CreationTime.QuadPart =
1557 ((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart;
1558 }
1559 else
1560 {
1561 /* Otherwise return 0 */
1562 BasicInfo->CreationTime.QuadPart = (ULONGLONG)0;
1563 }
1564
1565 /* Break out with success */
1566 Status = STATUS_SUCCESS;
1567 break;
1568
1569 /* Name information */
1570 case ObjectNameInformation:
1571
1572 /* Call the helper and break out */
1573 Status = ObQueryNameString(Object,
1574 (POBJECT_NAME_INFORMATION)
1575 ObjectInformation,
1576 Length,
1577 &InfoLength);
1578 break;
1579
1580 /* Information about this type */
1581 case ObjectTypeInformation:
1582
1583 /* Call the helper and break out */
1584 Status = ObQueryTypeInfo(ObjectHeader->Type,
1585 (POBJECT_TYPE_INFORMATION)
1586 ObjectInformation,
1587 Length,
1588 &InfoLength);
1589 break;
1590
1591 /* Information about all types */
1592 case ObjectTypesInformation:
1593 DPRINT1("NOT IMPLEMENTED!\n");
1594 InfoLength = Length;
1595 Status = STATUS_NOT_IMPLEMENTED;
1596 break;
1597
1598 /* Information about the handle flags */
1599 case ObjectHandleFlagInformation:
1600
1601 /* Validate length */
1602 InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION);
1603 if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1604 {
1605 Status = STATUS_INFO_LENGTH_MISMATCH;
1606 break;
1607 }
1608
1609 /* Get the structure */
1610 HandleFlags = (POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1611 ObjectInformation;
1612
1613 /* Set the flags */
1614 HandleFlags->Inherit = HandleInfo.HandleAttributes & OBJ_INHERIT;
1615 HandleFlags->ProtectFromClose = (HandleInfo.HandleAttributes &
1616 OBJ_PROTECT_CLOSE) != 0;
1617
1618 /* Break out with success */
1619 Status = STATUS_SUCCESS;
1620 break;
1621
1622 /* Anything else */
1623 default:
1624
1625 /* Fail it */
1626 InfoLength = Length;
1627 Status = STATUS_INVALID_INFO_CLASS;
1628 break;
1629 }
1630
1631 /* Check if the caller wanted the return length */
1632 if (ResultLength)
1633 {
1634 /* Write the length */
1635 *ResultLength = InfoLength;
1636 }
1637 }
1638 _SEH2_EXCEPT(ExSystemExceptionFilter())
1639 {
1640 /* Otherwise, get the exception code */
1641 Status = _SEH2_GetExceptionCode();
1642 }
1643 _SEH2_END;
1644
1645 /* Dereference the object if we had referenced it */
1646 if (Object) ObDereferenceObject(Object);
1647
1648 /* Return status */
1649 return Status;
1650 }
1651
1652 /*++
1653 * @name NtSetInformationObject
1654 * @implemented NT4
1655 *
1656 * The NtSetInformationObject routine <FILLMEIN>
1657 *
1658 * @param ObjectHandle
1659 * <FILLMEIN>
1660 *
1661 * @param ObjectInformationClass
1662 * <FILLMEIN>
1663 *
1664 * @param ObjectInformation
1665 * <FILLMEIN>
1666 *
1667 * @param Length
1668 * <FILLMEIN>
1669 *
1670 * @return STATUS_SUCCESS or appropriate error value.
1671 *
1672 * @remarks None.
1673 *
1674 *--*/
1675 NTSTATUS
1676 NTAPI
1677 NtSetInformationObject(IN HANDLE ObjectHandle,
1678 IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
1679 IN PVOID ObjectInformation,
1680 IN ULONG Length)
1681 {
1682 NTSTATUS Status;
1683 OBP_SET_HANDLE_ATTRIBUTES_CONTEXT Context;
1684 PVOID ObjectTable;
1685 KAPC_STATE ApcState;
1686 POBJECT_DIRECTORY Directory;
1687 KPROCESSOR_MODE PreviousMode;
1688 BOOLEAN AttachedToProcess = FALSE;
1689 PAGED_CODE();
1690
1691 /* Validate the information class */
1692 switch (ObjectInformationClass)
1693 {
1694 case ObjectHandleFlagInformation:
1695
1696 /* Validate the length */
1697 if (Length != sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
1698 {
1699 /* Invalid length */
1700 return STATUS_INFO_LENGTH_MISMATCH;
1701 }
1702
1703 /* Save the previous mode */
1704 Context.PreviousMode = ExGetPreviousMode();
1705
1706 /* Check if we were called from user mode */
1707 if (Context.PreviousMode != KernelMode)
1708 {
1709 /* Enter SEH */
1710 _SEH2_TRY
1711 {
1712 /* Probe and capture the attribute buffer */
1713 ProbeForRead(ObjectInformation,
1714 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION),
1715 sizeof(BOOLEAN));
1716 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1717 ObjectInformation;
1718 }
1719 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1720 {
1721 /* Return the exception code */
1722 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1723 }
1724 _SEH2_END;
1725 }
1726 else
1727 {
1728 /* Just copy the buffer directly */
1729 Context.Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
1730 ObjectInformation;
1731 }
1732
1733 /* Check if this is a kernel handle */
1734 if (ObpIsKernelHandle(ObjectHandle, Context.PreviousMode))
1735 {
1736 /* Get the actual handle */
1737 ObjectHandle = ObKernelHandleToHandle(ObjectHandle);
1738 ObjectTable = ObpKernelHandleTable;
1739
1740 /* Check if we're not in the system process */
1741 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1742 {
1743 /* Attach to it */
1744 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1745 AttachedToProcess = TRUE;
1746 }
1747 }
1748 else
1749 {
1750 /* Use the current table */
1751 ObjectTable = PsGetCurrentProcess()->ObjectTable;
1752 }
1753
1754 /* Change the handle attributes */
1755 if (!ExChangeHandle(ObjectTable,
1756 ObjectHandle,
1757 ObpSetHandleAttributes,
1758 (ULONG_PTR)&Context))
1759 {
1760 /* Some failure */
1761 Status = STATUS_ACCESS_DENIED;
1762 }
1763 else
1764 {
1765 /* We are done */
1766 Status = STATUS_SUCCESS;
1767 }
1768
1769 /* De-attach if we were attached, and return status */
1770 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1771 break;
1772
1773 case ObjectSessionInformation:
1774
1775 /* Only a system process can do this */
1776 PreviousMode = ExGetPreviousMode();
1777 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1778 {
1779 /* Fail */
1780 DPRINT1("Privilege not held\n");
1781 Status = STATUS_PRIVILEGE_NOT_HELD;
1782 }
1783 else
1784 {
1785 /* Get the object directory */
1786 Status = ObReferenceObjectByHandle(ObjectHandle,
1787 0,
1788 ObDirectoryType,
1789 PreviousMode,
1790 (PVOID*)&Directory,
1791 NULL);
1792 if (NT_SUCCESS(Status))
1793 {
1794 /* FIXME: Missng locks */
1795 /* Set its session ID */
1796 Directory->SessionId = PsGetCurrentProcessSessionId();
1797 ObDereferenceObject(Directory);
1798 }
1799 }
1800 break;
1801
1802 default:
1803 /* Unsupported class */
1804 Status = STATUS_INVALID_INFO_CLASS;
1805 break;
1806 }
1807
1808 return Status;
1809 }
1810
1811 /* EOF */