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