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