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