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