[NTOS:OB]
[reactos.git] / reactos / ntoskrnl / ob / obhandle.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/obhandle.c
5 * PURPOSE: Manages all functions related to the Object Manager handle
6 * implementation, including creating and destroying handles
7 * and/or handle tables, duplicating objects, and setting the
8 * permanent or temporary flags.
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 PHANDLE_TABLE ObpKernelHandleTable = NULL;
21 ULONG ObpAccessProtectCloseBit = MAXIMUM_ALLOWED;
22
23 #define TAG_OB_HANDLE 'dHbO'
24
25 /* PRIVATE FUNCTIONS *********************************************************/
26
27 PHANDLE_TABLE
28 NTAPI
29 ObReferenceProcessHandleTable(IN PEPROCESS Process)
30 {
31 PHANDLE_TABLE HandleTable = NULL;
32
33 /* Lock the process */
34 if (ExAcquireRundownProtection(&Process->RundownProtect))
35 {
36 /* Get the handle table */
37 HandleTable = Process->ObjectTable;
38 if (!HandleTable)
39 {
40 /* No table, release the lock */
41 ExReleaseRundownProtection(&Process->RundownProtect);
42 }
43 }
44
45 /* Return the handle table */
46 return HandleTable;
47 }
48
49 VOID
50 NTAPI
51 ObDereferenceProcessHandleTable(IN PEPROCESS Process)
52 {
53 /* Release the process lock */
54 ExReleaseRundownProtection(&Process->RundownProtect);
55 }
56
57 ULONG
58 NTAPI
59 ObGetProcessHandleCount(IN PEPROCESS Process)
60 {
61 ULONG HandleCount;
62 PHANDLE_TABLE HandleTable;
63
64 ASSERT(Process);
65
66 /* Ensure the handle table doesn't go away while we use it */
67 HandleTable = ObReferenceProcessHandleTable(Process);
68
69 if (HandleTable != NULL)
70 {
71 /* Count the number of handles the process has */
72 HandleCount = HandleTable->HandleCount;
73
74 /* Let the handle table go */
75 ObDereferenceProcessHandleTable(Process);
76 }
77 else
78 {
79 /* No handle table, no handles */
80 HandleCount = 0;
81 }
82
83 return HandleCount;
84 }
85
86 NTSTATUS
87 NTAPI
88 ObpReferenceProcessObjectByHandle(IN HANDLE Handle,
89 IN PEPROCESS Process,
90 IN PHANDLE_TABLE HandleTable,
91 IN KPROCESSOR_MODE AccessMode,
92 OUT PVOID *Object,
93 OUT POBJECT_HANDLE_INFORMATION HandleInformation,
94 OUT PACCESS_MASK AuditMask)
95 {
96 PHANDLE_TABLE_ENTRY HandleEntry;
97 POBJECT_HEADER ObjectHeader;
98 ACCESS_MASK GrantedAccess;
99 ULONG Attributes;
100 PETHREAD Thread = PsGetCurrentThread();
101 NTSTATUS Status;
102
103 /* Assume failure */
104 *Object = NULL;
105
106 /* Check if this is a special handle */
107 if (HandleToLong(Handle) < 0)
108 {
109 /* Check if the caller wants the current process */
110 if (Handle == NtCurrentProcess())
111 {
112 /* Return handle info */
113 HandleInformation->HandleAttributes = 0;
114 HandleInformation->GrantedAccess = Process->GrantedAccess;
115
116 /* No audit mask */
117 *AuditMask = 0;
118
119 /* Reference ourselves */
120 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Process);
121 InterlockedIncrement(&ObjectHeader->PointerCount);
122
123 /* Return the pointer */
124 *Object = Process;
125 ASSERT(*Object != NULL);
126 return STATUS_SUCCESS;
127 }
128
129 /* Check if the caller wants the current thread */
130 if (Handle == NtCurrentThread())
131 {
132 /* Return handle information */
133 HandleInformation->HandleAttributes = 0;
134 HandleInformation->GrantedAccess = Thread->GrantedAccess;
135
136 /* Reference ourselves */
137 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Thread);
138 InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
139
140 /* No audit mask */
141 *AuditMask = 0;
142
143 /* Return the pointer */
144 *Object = Thread;
145 ASSERT(*Object != NULL);
146 return STATUS_SUCCESS;
147 }
148
149 /* This is a kernel handle... do we have access? */
150 if (AccessMode == KernelMode)
151 {
152 /* Use the kernel handle table and get the actual handle value */
153 Handle = ObKernelHandleToHandle(Handle);
154 HandleTable = ObpKernelHandleTable;
155 }
156 else
157 {
158 /* This is an illegal attempt to access a kernel handle */
159 return STATUS_INVALID_HANDLE;
160 }
161 }
162
163 /* Enter a critical region while we touch the handle table */
164 ASSERT(HandleTable != NULL);
165 KeEnterCriticalRegion();
166
167 /* Get the handle entry */
168 HandleEntry = ExMapHandleToPointer(HandleTable, Handle);
169 if (HandleEntry)
170 {
171 /* Get the object header and validate the type*/
172 ObjectHeader = ObpGetHandleObject(HandleEntry);
173
174 /* Get the granted access and validate it */
175 GrantedAccess = HandleEntry->GrantedAccess;
176
177 /* Mask out the internal attributes */
178 Attributes = HandleEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
179
180 /* Fill out the information */
181 HandleInformation->HandleAttributes = Attributes;
182 HandleInformation->GrantedAccess = GrantedAccess;
183
184 /* No audit mask (FIXME!) */
185 *AuditMask = 0;
186
187 /* Return the pointer */
188 *Object = &ObjectHeader->Body;
189
190 /* Add a reference */
191 InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
192
193 /* Unlock the handle */
194 ExUnlockHandleTableEntry(HandleTable, HandleEntry);
195 KeLeaveCriticalRegion();
196
197 /* Return success */
198 ASSERT(*Object != NULL);
199 return STATUS_SUCCESS;
200 }
201 else
202 {
203 /* Invalid handle */
204 Status = STATUS_INVALID_HANDLE;
205 }
206
207 /* Return failure status */
208 KeLeaveCriticalRegion();
209 return Status;
210 }
211
212 BOOLEAN
213 NTAPI
214 ObpEnumFindHandleProcedure(IN PHANDLE_TABLE_ENTRY HandleEntry,
215 IN HANDLE Handle,
216 IN PVOID Context)
217 {
218 POBJECT_HEADER ObjectHeader;
219 ACCESS_MASK GrantedAccess;
220 ULONG HandleAttributes;
221 POBP_FIND_HANDLE_DATA FindData = Context;
222
223 /* Get the object header */
224 ObjectHeader = ObpGetHandleObject(HandleEntry);
225
226 /* Make sure it's valid and matching */
227 if ((FindData->ObjectHeader) && (FindData->ObjectHeader != ObjectHeader))
228 {
229 /* No match, fail */
230 return FALSE;
231 }
232
233 /* Now attempt to match the object type */
234 if ((FindData->ObjectType) && (FindData->ObjectType != ObjectHeader->Type))
235 {
236 /* No match, fail */
237 return FALSE;
238 }
239
240 /* Check if we have extra information */
241 if (FindData->HandleInformation)
242 {
243 /* Get the granted access and attributes */
244 GrantedAccess = HandleEntry->GrantedAccess;
245 HandleAttributes = HandleEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
246
247 /* Attempt to match them */
248 if ((FindData->HandleInformation->HandleAttributes != HandleAttributes) ||
249 (FindData->HandleInformation->GrantedAccess != GrantedAccess))
250 {
251 /* No match, fail */
252 return FALSE;
253 }
254 }
255
256 /* We have a match */
257 return TRUE;
258 }
259
260 POBJECT_HANDLE_COUNT_ENTRY
261 NTAPI
262 ObpInsertHandleCount(IN POBJECT_HEADER ObjectHeader)
263 {
264 POBJECT_HEADER_HANDLE_INFO HandleInfo;
265 POBJECT_HANDLE_COUNT_ENTRY FreeEntry;
266 POBJECT_HANDLE_COUNT_DATABASE HandleDatabase, OldHandleDatabase;
267 ULONG i;
268 ULONG Size, OldSize;
269 OBJECT_HANDLE_COUNT_DATABASE SingleDatabase;
270 PAGED_CODE();
271
272 /* Get the handle info */
273 HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
274 if (!HandleInfo) return NULL;
275
276 /* Check if we only have one entry */
277 if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
278 {
279 /* Fill out the single entry */
280 SingleDatabase.CountEntries = 1;
281 SingleDatabase.HandleCountEntries[0] = HandleInfo->SingleEntry;
282
283 /* Use this as the old size */
284 OldHandleDatabase = &SingleDatabase;
285 OldSize = sizeof(SingleDatabase);
286
287 /* Now we'll have two entries, and an entire DB */
288 i = 2;
289 Size = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
290 ((i - 1) * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
291 }
292 else
293 {
294 /* We already have a DB, get the information from it */
295 OldHandleDatabase = HandleInfo->HandleCountDatabase;
296 i = OldHandleDatabase->CountEntries;
297 OldSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
298 ((i - 1) * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
299
300 /* Add 4 more entries */
301 i += 4;
302 Size = OldSize + (4 * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
303 }
304
305 /* Allocate the DB */
306 HandleDatabase = ExAllocatePoolWithTag(PagedPool, Size, TAG_OB_HANDLE);
307 if (!HandleDatabase) return NULL;
308
309 /* Copy the old database */
310 RtlCopyMemory(HandleDatabase, OldHandleDatabase, OldSize);
311
312 /* Check if we he had a single entry before */
313 if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
314 {
315 /* Now we have more */
316 ObjectHeader->Flags &= ~OB_FLAG_SINGLE_PROCESS;
317 }
318 else
319 {
320 /* Otherwise we had a DB, free it */
321 ExFreePoolWithTag(OldHandleDatabase, TAG_OB_HANDLE);
322 }
323
324 /* Find the end of the copy and zero out the new data */
325 FreeEntry = (PVOID)((ULONG_PTR)HandleDatabase + OldSize);
326 RtlZeroMemory(FreeEntry, Size - OldSize);
327
328 /* Set the new information and return the free entry */
329 HandleDatabase->CountEntries = i;
330 HandleInfo->HandleCountDatabase = HandleDatabase;
331 return FreeEntry;
332 }
333
334 NTSTATUS
335 NTAPI
336 ObpIncrementHandleDataBase(IN POBJECT_HEADER ObjectHeader,
337 IN PEPROCESS Process,
338 IN OUT PULONG NewProcessHandleCount)
339 {
340 POBJECT_HEADER_HANDLE_INFO HandleInfo;
341 POBJECT_HANDLE_COUNT_ENTRY HandleEntry, FreeEntry = NULL;
342 POBJECT_HANDLE_COUNT_DATABASE HandleDatabase;
343 ULONG i;
344 PAGED_CODE();
345
346 /* Get the handle info and check if we only have one entry */
347 HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
348 if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
349 {
350 /* Check if the entry is free */
351 if (!HandleInfo->SingleEntry.HandleCount)
352 {
353 /* Add ours */
354 HandleInfo->SingleEntry.HandleCount = 1;
355 HandleInfo->SingleEntry.Process = Process;
356
357 /* Return success and 1 handle */
358 *NewProcessHandleCount = 1;
359 return STATUS_SUCCESS;
360 }
361 else if (HandleInfo->SingleEntry.Process == Process)
362 {
363 /* Busy entry, but same process */
364 *NewProcessHandleCount = ++HandleInfo->SingleEntry.HandleCount;
365 return STATUS_SUCCESS;
366 }
367 else
368 {
369 /* Insert a new entry */
370 FreeEntry = ObpInsertHandleCount(ObjectHeader);
371 if (!FreeEntry) return STATUS_INSUFFICIENT_RESOURCES;
372 ASSERT(!FreeEntry->Process);
373 ASSERT(!FreeEntry->HandleCount);
374
375 /* Fill it out */
376 FreeEntry->Process = Process;
377 FreeEntry->HandleCount = 1;
378
379 /* Return success and 1 handle */
380 *NewProcessHandleCount = 1;
381 return STATUS_SUCCESS;
382 }
383 }
384
385 /* We have a database instead */
386 HandleDatabase = HandleInfo->HandleCountDatabase;
387 if (HandleDatabase)
388 {
389 /* Get the entries and loop them */
390 i = HandleDatabase->CountEntries;
391 HandleEntry = &HandleDatabase->HandleCountEntries[0];
392 while (i)
393 {
394 /* Check if this is a match */
395 if (HandleEntry->Process == Process)
396 {
397 /* Found it, get the process handle count */
398 *NewProcessHandleCount = ++HandleEntry->HandleCount;
399 return STATUS_SUCCESS;
400 }
401 else if (!HandleEntry->HandleCount)
402 {
403 /* Found a free entry */
404 FreeEntry = HandleEntry;
405 }
406
407 /* Keep looping */
408 HandleEntry++;
409 i--;
410 }
411
412 /* Check if we couldn't find a free entry */
413 if (!FreeEntry)
414 {
415 /* Allocate one */
416 FreeEntry = ObpInsertHandleCount(ObjectHeader);
417 if (!FreeEntry) return STATUS_INSUFFICIENT_RESOURCES;
418 ASSERT(!FreeEntry->Process);
419 ASSERT(!FreeEntry->HandleCount);
420 }
421
422 /* Fill out the entry */
423 FreeEntry->Process = Process;
424 FreeEntry->HandleCount = 1;
425 *NewProcessHandleCount = 1;
426 }
427
428 /* Return success if we got here */
429 return STATUS_SUCCESS;
430 }
431
432 NTSTATUS
433 NTAPI
434 ObpChargeQuotaForObject(IN POBJECT_HEADER ObjectHeader,
435 IN POBJECT_TYPE ObjectType,
436 OUT PBOOLEAN NewObject)
437 {
438 POBJECT_HEADER_QUOTA_INFO ObjectQuota;
439 ULONG PagedPoolCharge, NonPagedPoolCharge;
440
441 /* Get quota information */
442 ObjectQuota = OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader);
443 *NewObject = FALSE;
444
445 /* Check if this is a new object */
446 if (ObjectHeader->Flags & OB_FLAG_CREATE_INFO)
447 {
448 /* Remove the flag */
449 ObjectHeader->Flags &= ~ OB_FLAG_CREATE_INFO;
450 if (ObjectQuota)
451 {
452 /* We have a quota, get the charges */
453 PagedPoolCharge = ObjectQuota->PagedPoolCharge;
454 NonPagedPoolCharge = ObjectQuota->NonPagedPoolCharge;
455 }
456 else
457 {
458 /* Get it from the object type */
459 PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
460 NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
461 }
462
463 /* Charge the quota */
464 ObjectHeader->QuotaBlockCharged = (PVOID)1;
465 DPRINT("FIXME: Should charge: %lx %lx\n", PagedPoolCharge, NonPagedPoolCharge);
466 #if 0
467 PsChargeSharedPoolQuota(PsGetCurrentProcess(),
468 PagedPoolCharge,
469 NonPagedPoolCharge);
470 #endif
471
472 /* Check if we don't have a quota block */
473 if (!ObjectHeader->QuotaBlockCharged) return STATUS_QUOTA_EXCEEDED;
474
475 /* Now set the flag */
476 *NewObject = TRUE;
477 }
478
479 /* Return success */
480 return STATUS_SUCCESS;
481 }
482
483 NTSTATUS
484 NTAPI
485 ObpValidateAccessMask(IN PACCESS_STATE AccessState)
486 {
487 /* TODO */
488 return STATUS_SUCCESS;
489 }
490
491 /*++
492 * @name ObpDecrementHandleCount
493 *
494 * The ObpDecrementHandleCount routine <FILLMEIN>
495 *
496 * @param ObjectBody
497 * <FILLMEIN>.
498 *
499 * @param Process
500 * <FILLMEIN>.
501 *
502 * @param GrantedAccess
503 * <FILLMEIN>.
504 *
505 * @return None.
506 *
507 * @remarks None.
508 *
509 *--*/
510 VOID
511 NTAPI
512 ObpDecrementHandleCount(IN PVOID ObjectBody,
513 IN PEPROCESS Process,
514 IN ACCESS_MASK GrantedAccess,
515 IN POBJECT_TYPE ObjectType)
516 {
517 POBJECT_HEADER ObjectHeader;
518 LONG SystemHandleCount, ProcessHandleCount;
519 LONG NewCount;
520 KIRQL CalloutIrql;
521 POBJECT_HEADER_HANDLE_INFO HandleInfo;
522 POBJECT_HANDLE_COUNT_ENTRY HandleEntry;
523 POBJECT_HANDLE_COUNT_DATABASE HandleDatabase;
524 ULONG i;
525 PAGED_CODE();
526
527 /* Get the object type and header */
528 ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
529 OBTRACE(OB_HANDLE_DEBUG,
530 "%s - Decrementing count for: %p. HC PC %lx %lx\n",
531 __FUNCTION__,
532 ObjectBody,
533 ObjectHeader->HandleCount,
534 ObjectHeader->PointerCount);
535
536 /* Lock the object */
537 ObpAcquireObjectLock(ObjectHeader);
538
539 /* Set default counts */
540 SystemHandleCount = ObjectHeader->HandleCount;
541 ProcessHandleCount = 0;
542
543 /* Decrement the handle count */
544 NewCount = InterlockedDecrement(&ObjectHeader->HandleCount);
545
546 /* Check if we're out of handles and this was an exclusive object */
547 if (!(NewCount) && (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
548 {
549 /* Clear the exclusive flag */
550 OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = NULL;
551 }
552
553 /* Is the object type keeping track of handles? */
554 if (ObjectType->TypeInfo.MaintainHandleCount)
555 {
556 /* Get handle information */
557 HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
558
559 /* Check if there's only a single entry */
560 if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
561 {
562 /* It should be us */
563 ASSERT(HandleInfo->SingleEntry.Process == Process);
564 ASSERT(HandleInfo->SingleEntry.HandleCount > 0);
565
566 /* Get the handle counts */
567 ProcessHandleCount = HandleInfo->SingleEntry.HandleCount--;
568 HandleEntry = &HandleInfo->SingleEntry;
569 }
570 else
571 {
572 /* Otherwise, get the database */
573 HandleDatabase = HandleInfo->HandleCountDatabase;
574 if (HandleDatabase)
575 {
576 /* Get the entries and loop them */
577 i = HandleDatabase->CountEntries;
578 HandleEntry = &HandleDatabase->HandleCountEntries[0];
579 while (i)
580 {
581 /* Check if this is a match */
582 if ((HandleEntry->HandleCount) &&
583 (HandleEntry->Process == Process))
584 {
585 /* Found it, get the process handle count */
586 ProcessHandleCount = HandleEntry->HandleCount--;
587 break;
588 }
589
590 /* Keep looping */
591 HandleEntry++;
592 i--;
593 }
594 }
595 else
596 {
597 /* No database, so no entry */
598 HandleEntry = NULL;
599 }
600 }
601
602 /* Check if this is the last handle */
603 if (ProcessHandleCount == 1)
604 {
605 /* Then clear the entry */
606 HandleEntry->Process = NULL;
607 HandleEntry->HandleCount = 0;
608 }
609 }
610
611 /* Release the lock */
612 ObpReleaseObjectLock(ObjectHeader);
613
614 /* Check if we have a close procedure */
615 if (ObjectType->TypeInfo.CloseProcedure)
616 {
617 /* Call it */
618 ObpCalloutStart(&CalloutIrql);
619 ObjectType->TypeInfo.CloseProcedure(Process,
620 ObjectBody,
621 GrantedAccess,
622 ProcessHandleCount,
623 SystemHandleCount);
624 ObpCalloutEnd(CalloutIrql, "Close", ObjectType, ObjectBody);
625 }
626
627 /* Check if we should delete the object */
628 ObpDeleteNameCheck(ObjectBody);
629
630 /* Decrease the total number of handles for this type */
631 InterlockedDecrement((PLONG)&ObjectType->TotalNumberOfHandles);
632 OBTRACE(OB_HANDLE_DEBUG,
633 "%s - Decremented count for: %p. HC PC %lx %lx\n",
634 __FUNCTION__,
635 ObjectBody,
636 ObjectHeader->HandleCount,
637 ObjectHeader->PointerCount);
638 }
639
640 /*++
641 * @name ObpCloseHandleTableEntry
642 *
643 * The ObpCloseHandleTableEntry routine <FILLMEIN>
644 *
645 * @param HandleTable
646 * <FILLMEIN>.
647 *
648 * @param HandleEntry
649 * <FILLMEIN>.
650 *
651 * @param Handle
652 * <FILLMEIN>.
653 *
654 * @param AccessMode
655 * <FILLMEIN>.
656 *
657 * @param IgnoreHandleProtection
658 * <FILLMEIN>.
659 *
660 * @return <FILLMEIN>.
661 *
662 * @remarks None.
663 *
664 *--*/
665 NTSTATUS
666 NTAPI
667 ObpCloseHandleTableEntry(IN PHANDLE_TABLE HandleTable,
668 IN PHANDLE_TABLE_ENTRY HandleEntry,
669 IN HANDLE Handle,
670 IN KPROCESSOR_MODE AccessMode,
671 IN BOOLEAN IgnoreHandleProtection)
672 {
673 PVOID Body;
674 POBJECT_TYPE ObjectType;
675 POBJECT_HEADER ObjectHeader;
676 ACCESS_MASK GrantedAccess;
677 KIRQL CalloutIrql;
678 PAGED_CODE();
679
680 /* Get the object data */
681 ObjectHeader = ObpGetHandleObject(HandleEntry);
682 ObjectType = ObjectHeader->Type;
683 Body = &ObjectHeader->Body;
684 GrantedAccess = HandleEntry->GrantedAccess;
685 OBTRACE(OB_HANDLE_DEBUG,
686 "%s - Closing handle: %p for %p. HC PC %lx %lx\n",
687 __FUNCTION__,
688 Handle,
689 Body,
690 ObjectHeader->HandleCount,
691 ObjectHeader->PointerCount);
692
693 /* Check if the object has an Okay To Close procedure */
694 if (ObjectType->TypeInfo.OkayToCloseProcedure)
695 {
696 /* Call it and check if it's not letting us close it */
697 ObpCalloutStart(&CalloutIrql);
698 if (!ObjectType->TypeInfo.OkayToCloseProcedure(PsGetCurrentProcess(),
699 Body,
700 Handle,
701 AccessMode))
702 {
703 /* Fail */
704 ObpCalloutEnd(CalloutIrql, "NtClose", ObjectType, Body);
705 ExUnlockHandleTableEntry(HandleTable, HandleEntry);
706 return STATUS_HANDLE_NOT_CLOSABLE;
707 }
708
709 /* Success, validate callout retrn */
710 ObpCalloutEnd(CalloutIrql, "NtClose", ObjectType, Body);
711 }
712
713 /* The callback allowed us to close it, but does the handle itself? */
714 if ((HandleEntry->ObAttributes & OBJ_PROTECT_CLOSE) &&
715 !(IgnoreHandleProtection))
716 {
717 /* It doesn't, are we from user mode? */
718 if (AccessMode != KernelMode)
719 {
720 /* We are! Unlock the entry */
721 ExUnlockHandleTableEntry(HandleTable, HandleEntry);
722
723 /* Make sure we have a debug port */
724 if (PsGetCurrentProcess()->DebugPort)
725 {
726 /* Raise an exception */
727 return KeRaiseUserException(STATUS_HANDLE_NOT_CLOSABLE);
728 }
729 else
730 {
731 /* Return the error instead */
732 return STATUS_HANDLE_NOT_CLOSABLE;
733 }
734 }
735 else
736 {
737 /* Otherwise, bugcheck the OS */
738 KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 0, 0, 0);
739 }
740 }
741
742 /* Destroy and unlock the handle entry */
743 ExDestroyHandle(HandleTable, Handle, HandleEntry);
744
745 /* Now decrement the handle count */
746 ObpDecrementHandleCount(Body,
747 PsGetCurrentProcess(),
748 GrantedAccess,
749 ObjectType);
750
751 /* Dereference the object as well */
752 ObDereferenceObject(Body);
753
754 /* Return to caller */
755 OBTRACE(OB_HANDLE_DEBUG,
756 "%s - Closed handle: %p for %p.\n",
757 __FUNCTION__,
758 Handle,
759 Body);
760 return STATUS_SUCCESS;
761 }
762
763 /*++
764 * @name ObpIncrementHandleCount
765 *
766 * The ObpIncrementHandleCount routine <FILLMEIN>
767 *
768 * @param Object
769 * <FILLMEIN>.
770 *
771 * @param AccessState
772 * <FILLMEIN>.
773 *
774 * @param AccessMode
775 * <FILLMEIN>.
776 *
777 * @param HandleAttributes
778 * <FILLMEIN>.
779 *
780 * @param Process
781 * <FILLMEIN>.
782 *
783 * @param OpenReason
784 * <FILLMEIN>.
785 *
786 * @return <FILLMEIN>.
787 *
788 * @remarks None.
789 *
790 *--*/
791 NTSTATUS
792 NTAPI
793 ObpIncrementHandleCount(IN PVOID Object,
794 IN PACCESS_STATE AccessState OPTIONAL,
795 IN KPROCESSOR_MODE AccessMode,
796 IN ULONG HandleAttributes,
797 IN PEPROCESS Process,
798 IN OB_OPEN_REASON OpenReason)
799 {
800 POBJECT_HEADER ObjectHeader;
801 POBJECT_TYPE ObjectType;
802 ULONG ProcessHandleCount;
803 NTSTATUS Status;
804 PEPROCESS ExclusiveProcess;
805 BOOLEAN Exclusive = FALSE, NewObject;
806 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
807 KIRQL CalloutIrql;
808 KPROCESSOR_MODE ProbeMode;
809 ULONG Total;
810 POBJECT_HEADER_NAME_INFO NameInfo;
811 PAGED_CODE();
812
813 /* Get the object header and type */
814 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
815 ObjectType = ObjectHeader->Type;
816 OBTRACE(OB_HANDLE_DEBUG,
817 "%s - Incrementing count for: %p. Reason: %lx. HC PC %lx %lx\n",
818 __FUNCTION__,
819 Object,
820 OpenReason,
821 ObjectHeader->HandleCount,
822 ObjectHeader->PointerCount);
823
824 /* Check if caller is forcing user mode */
825 if (HandleAttributes & OBJ_FORCE_ACCESS_CHECK)
826 {
827 /* Force it */
828 ProbeMode = UserMode;
829 }
830 else
831 {
832 /* Keep original setting */
833 ProbeMode = AccessMode;
834 }
835
836 /* Lock the object */
837 ObpAcquireObjectLock(ObjectHeader);
838
839 /* Charge quota and remove the creator info flag */
840 Status = ObpChargeQuotaForObject(ObjectHeader, ObjectType, &NewObject);
841 if (!NT_SUCCESS(Status)) return Status;
842
843 /* Check if the open is exclusive */
844 if (HandleAttributes & OBJ_EXCLUSIVE)
845 {
846 /* Check if the object allows this, or if the inherit flag was given */
847 if ((HandleAttributes & OBJ_INHERIT) ||
848 !(ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
849 {
850 /* Incorrect attempt */
851 Status = STATUS_INVALID_PARAMETER;
852 goto Quickie;
853 }
854
855 /* Check if we have access to it */
856 ExclusiveProcess = OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader);
857 if ((!(ExclusiveProcess) && (ObjectHeader->HandleCount)) ||
858 ((ExclusiveProcess) && (ExclusiveProcess != PsGetCurrentProcess())))
859 {
860 /* This isn't the right process */
861 Status = STATUS_ACCESS_DENIED;
862 goto Quickie;
863 }
864
865 /* Now you got exclusive access */
866 Exclusive = TRUE;
867 }
868 else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) &&
869 (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader)))
870 {
871 /* Caller didn't want exclusive access, but the object is exclusive */
872 Status = STATUS_ACCESS_DENIED;
873 goto Quickie;
874 }
875
876 /* Check for exclusive kernel object */
877 NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
878 if ((NameInfo) && (NameInfo->QueryReferences & OB_FLAG_KERNEL_EXCLUSIVE) &&
879 (ProbeMode != KernelMode))
880 {
881 /* Caller is not kernel, but the object is kernel exclusive */
882 Status = STATUS_ACCESS_DENIED;
883 goto Quickie;
884 }
885
886 /*
887 * Check if this is an object that went from 0 handles back to existence,
888 * but doesn't have an open procedure, only a close procedure. This means
889 * that it will never realize that the object is back alive, so we must
890 * fail the request.
891 */
892 if (!(ObjectHeader->HandleCount) &&
893 !(NewObject) &&
894 (ObjectType->TypeInfo.MaintainHandleCount) &&
895 !(ObjectType->TypeInfo.OpenProcedure) &&
896 (ObjectType->TypeInfo.CloseProcedure))
897 {
898 /* Fail */
899 Status = STATUS_UNSUCCESSFUL;
900 goto Quickie;
901 }
902
903 /* Check if we're opening an existing handle */
904 if ((OpenReason == ObOpenHandle) ||
905 ((OpenReason == ObDuplicateHandle) && (AccessState)))
906 {
907 /* Validate the caller's access to this object */
908 if (!ObCheckObjectAccess(Object,
909 AccessState,
910 TRUE,
911 ProbeMode,
912 &Status))
913 {
914 /* Access was denied, so fail */
915 goto Quickie;
916 }
917 }
918 else if (OpenReason == ObCreateHandle)
919 {
920 /* Convert MAXIMUM_ALLOWED to GENERIC_ALL */
921 if (AccessState->RemainingDesiredAccess & MAXIMUM_ALLOWED)
922 {
923 /* Mask out MAXIMUM_ALLOWED and stick GENERIC_ALL instead */
924 AccessState->RemainingDesiredAccess &= ~MAXIMUM_ALLOWED;
925 AccessState->RemainingDesiredAccess |= GENERIC_ALL;
926 }
927
928 /* Check if we have to map the GENERIC mask */
929 if (AccessState->RemainingDesiredAccess & GENERIC_ACCESS)
930 {
931 /* Map it to the correct access masks */
932 RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
933 &ObjectType->TypeInfo.GenericMapping);
934 }
935
936 /* Check if the caller is trying to access system security */
937 if (AccessState->RemainingDesiredAccess & ACCESS_SYSTEM_SECURITY)
938 {
939 /* FIXME: TODO */
940 DPRINT1("ACCESS_SYSTEM_SECURITY not validated!\n");
941 }
942 }
943
944 /* Check if this is an exclusive handle */
945 if (Exclusive)
946 {
947 /* Save the owner process */
948 OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
949 }
950
951 /* Increase the handle count */
952 InterlockedIncrement(&ObjectHeader->HandleCount);
953 ProcessHandleCount = 0;
954
955 /* Check if we have a handle database */
956 if (ObjectType->TypeInfo.MaintainHandleCount)
957 {
958 /* Increment the handle database */
959 Status = ObpIncrementHandleDataBase(ObjectHeader,
960 Process,
961 &ProcessHandleCount);
962 if (!NT_SUCCESS(Status))
963 {
964 /* FIXME: This should never happen for now */
965 DPRINT1("Unhandled case\n");
966 ASSERT(FALSE);
967 goto Quickie;
968 }
969 }
970
971 /* Release the lock */
972 ObpReleaseObjectLock(ObjectHeader);
973
974 /* Check if we have an open procedure */
975 Status = STATUS_SUCCESS;
976 if (ObjectType->TypeInfo.OpenProcedure)
977 {
978 /* Call it */
979 ObpCalloutStart(&CalloutIrql);
980 Status = ObjectType->TypeInfo.OpenProcedure(OpenReason,
981 Process,
982 Object,
983 AccessState ?
984 AccessState->
985 PreviouslyGrantedAccess :
986 0,
987 ProcessHandleCount);
988 ObpCalloutEnd(CalloutIrql, "Open", ObjectType, Object);
989
990 /* Check if the open procedure failed */
991 if (!NT_SUCCESS(Status))
992 {
993 /* FIXME: This should never happen for now */
994 DPRINT1("Unhandled case\n");
995 ASSERT(FALSE);
996 return Status;
997 }
998 }
999
1000 /* Check if this is a create operation */
1001 if (OpenReason == ObCreateHandle)
1002 {
1003 /* Check if we have creator info */
1004 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(ObjectHeader);
1005 if (CreatorInfo)
1006 {
1007 /* We do, acquire the lock */
1008 ObpEnterObjectTypeMutex(ObjectType);
1009
1010 /* Insert us on the list */
1011 InsertTailList(&ObjectType->TypeList, &CreatorInfo->TypeList);
1012
1013 /* Release the lock */
1014 ObpLeaveObjectTypeMutex(ObjectType);
1015 }
1016 }
1017
1018 /* Increase total number of handles */
1019 Total = InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfHandles);
1020 if (Total > ObjectType->HighWaterNumberOfHandles)
1021 {
1022 /* Fixup count */
1023 ObjectType->HighWaterNumberOfHandles = Total;
1024 }
1025
1026 /* Trace call and return */
1027 OBTRACE(OB_HANDLE_DEBUG,
1028 "%s - Incremented count for: %p. Reason: %lx HC PC %lx %lx\n",
1029 __FUNCTION__,
1030 Object,
1031 OpenReason,
1032 ObjectHeader->HandleCount,
1033 ObjectHeader->PointerCount);
1034 return Status;
1035
1036 Quickie:
1037 /* Release lock and return */
1038 ObpReleaseObjectLock(ObjectHeader);
1039 return Status;
1040 }
1041
1042 /*++
1043 * @name ObpIncrementUnnamedHandleCount
1044 *
1045 * The ObpIncrementUnnamedHandleCount routine <FILLMEIN>
1046 *
1047 * @param Object
1048 * <FILLMEIN>.
1049 *
1050 * @param AccessState
1051 * <FILLMEIN>.
1052 *
1053 * @param AccessMode
1054 * <FILLMEIN>.
1055 *
1056 * @param HandleAttributes
1057 * <FILLMEIN>.
1058 *
1059 * @param Process
1060 * <FILLMEIN>.
1061 *
1062 * @param OpenReason
1063 * <FILLMEIN>.
1064 *
1065 * @return <FILLMEIN>.
1066 *
1067 * @remarks None.
1068 *
1069 *--*/
1070 NTSTATUS
1071 NTAPI
1072 ObpIncrementUnnamedHandleCount(IN PVOID Object,
1073 IN PACCESS_MASK DesiredAccess,
1074 IN KPROCESSOR_MODE AccessMode,
1075 IN ULONG HandleAttributes,
1076 IN PEPROCESS Process)
1077 {
1078 POBJECT_HEADER ObjectHeader;
1079 POBJECT_TYPE ObjectType;
1080 ULONG ProcessHandleCount;
1081 NTSTATUS Status;
1082 PEPROCESS ExclusiveProcess;
1083 BOOLEAN Exclusive = FALSE, NewObject;
1084 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
1085 KIRQL CalloutIrql;
1086 ULONG Total;
1087
1088 /* Get the object header and type */
1089 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1090 ObjectType = ObjectHeader->Type;
1091 OBTRACE(OB_HANDLE_DEBUG,
1092 "%s - Incrementing count for: %p. UNNAMED. HC PC %lx %lx\n",
1093 __FUNCTION__,
1094 Object,
1095 ObjectHeader->HandleCount,
1096 ObjectHeader->PointerCount);
1097
1098 /* Lock the object */
1099 ObpAcquireObjectLock(ObjectHeader);
1100
1101 /* Charge quota and remove the creator info flag */
1102 Status = ObpChargeQuotaForObject(ObjectHeader, ObjectType, &NewObject);
1103 if (!NT_SUCCESS(Status)) return Status;
1104
1105 /* Check if the open is exclusive */
1106 if (HandleAttributes & OBJ_EXCLUSIVE)
1107 {
1108 /* Check if the object allows this, or if the inherit flag was given */
1109 if ((HandleAttributes & OBJ_INHERIT) ||
1110 !(ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
1111 {
1112 /* Incorrect attempt */
1113 Status = STATUS_INVALID_PARAMETER;
1114 goto Quickie;
1115 }
1116
1117 /* Check if we have access to it */
1118 ExclusiveProcess = OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader);
1119 if ((!(ExclusiveProcess) && (ObjectHeader->HandleCount)) ||
1120 ((ExclusiveProcess) && (ExclusiveProcess != PsGetCurrentProcess())))
1121 {
1122 /* This isn't the right process */
1123 Status = STATUS_ACCESS_DENIED;
1124 goto Quickie;
1125 }
1126
1127 /* Now you got exclusive access */
1128 Exclusive = TRUE;
1129 }
1130 else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) &&
1131 (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader)))
1132 {
1133 /* Caller didn't want exclusive access, but the object is exclusive */
1134 Status = STATUS_ACCESS_DENIED;
1135 goto Quickie;
1136 }
1137
1138 /*
1139 * Check if this is an object that went from 0 handles back to existence,
1140 * but doesn't have an open procedure, only a close procedure. This means
1141 * that it will never realize that the object is back alive, so we must
1142 * fail the request.
1143 */
1144 if (!(ObjectHeader->HandleCount) &&
1145 !(NewObject) &&
1146 (ObjectType->TypeInfo.MaintainHandleCount) &&
1147 !(ObjectType->TypeInfo.OpenProcedure) &&
1148 (ObjectType->TypeInfo.CloseProcedure))
1149 {
1150 /* Fail */
1151 Status = STATUS_UNSUCCESSFUL;
1152 goto Quickie;
1153 }
1154
1155 /* Convert MAXIMUM_ALLOWED to GENERIC_ALL */
1156 if (*DesiredAccess & MAXIMUM_ALLOWED)
1157 {
1158 /* Mask out MAXIMUM_ALLOWED and stick GENERIC_ALL instead */
1159 *DesiredAccess &= ~MAXIMUM_ALLOWED;
1160 *DesiredAccess |= GENERIC_ALL;
1161 }
1162
1163 /* Check if we have to map the GENERIC mask */
1164 if (*DesiredAccess & GENERIC_ACCESS)
1165 {
1166 /* Map it to the correct access masks */
1167 RtlMapGenericMask(DesiredAccess,
1168 &ObjectType->TypeInfo.GenericMapping);
1169 }
1170
1171 /* Check if this is an exclusive handle */
1172 if (Exclusive)
1173 {
1174 /* Save the owner process */
1175 OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
1176 }
1177
1178 /* Increase the handle count */
1179 InterlockedIncrement(&ObjectHeader->HandleCount);
1180 ProcessHandleCount = 0;
1181
1182 /* Check if we have a handle database */
1183 if (ObjectType->TypeInfo.MaintainHandleCount)
1184 {
1185 /* Increment the handle database */
1186 Status = ObpIncrementHandleDataBase(ObjectHeader,
1187 Process,
1188 &ProcessHandleCount);
1189 if (!NT_SUCCESS(Status))
1190 {
1191 /* FIXME: This should never happen for now */
1192 DPRINT1("Unhandled case\n");
1193 ASSERT(FALSE);
1194 goto Quickie;
1195 }
1196 }
1197
1198 /* Release the lock */
1199 ObpReleaseObjectLock(ObjectHeader);
1200
1201 /* Check if we have an open procedure */
1202 Status = STATUS_SUCCESS;
1203 if (ObjectType->TypeInfo.OpenProcedure)
1204 {
1205 /* Call it */
1206 ObpCalloutStart(&CalloutIrql);
1207 Status = ObjectType->TypeInfo.OpenProcedure(ObCreateHandle,
1208 Process,
1209 Object,
1210 *DesiredAccess,
1211 ProcessHandleCount);
1212 ObpCalloutEnd(CalloutIrql, "Open", ObjectType, Object);
1213
1214 /* Check if the open procedure failed */
1215 if (!NT_SUCCESS(Status))
1216 {
1217 /* FIXME: This should never happen for now */
1218 DPRINT1("Unhandled case\n");
1219 ASSERT(FALSE);
1220 return Status;
1221 }
1222 }
1223
1224 /* Check if we have creator info */
1225 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(ObjectHeader);
1226 if (CreatorInfo)
1227 {
1228 /* We do, acquire the lock */
1229 ObpEnterObjectTypeMutex(ObjectType);
1230
1231 /* Insert us on the list */
1232 InsertTailList(&ObjectType->TypeList, &CreatorInfo->TypeList);
1233
1234 /* Release the lock */
1235 ObpLeaveObjectTypeMutex(ObjectType);
1236 }
1237
1238 /* Increase total number of handles */
1239 Total = InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfHandles);
1240 if (Total > ObjectType->HighWaterNumberOfHandles)
1241 {
1242 /* Fixup count */
1243 ObjectType->HighWaterNumberOfHandles = Total;
1244 }
1245
1246 /* Trace call and return */
1247 OBTRACE(OB_HANDLE_DEBUG,
1248 "%s - Incremented count for: %p. UNNAMED HC PC %lx %lx\n",
1249 __FUNCTION__,
1250 Object,
1251 ObjectHeader->HandleCount,
1252 ObjectHeader->PointerCount);
1253 return Status;
1254
1255 Quickie:
1256 /* Release lock and return */
1257 ObpReleaseObjectLock(ObjectHeader);
1258 return Status;
1259 }
1260
1261 /*++
1262 * @name ObpCreateUnnamedHandle
1263 *
1264 * The ObpCreateUnnamedHandle routine <FILLMEIN>
1265 *
1266 * @param Object
1267 * <FILLMEIN>.
1268 *
1269 * @param DesiredAccess
1270 * <FILLMEIN>.
1271 *
1272 * @param AdditionalReferences
1273 * <FILLMEIN>.
1274 *
1275 * @param HandleAttributes
1276 * <FILLMEIN>.
1277 *
1278 * @param AccessMode
1279 * <FILLMEIN>.
1280 *
1281 * @param ReturnedObject
1282 * <FILLMEIN>.
1283 *
1284 * @param ReturnedHandle
1285 * <FILLMEIN>.
1286 *
1287 * @return <FILLMEIN>.
1288 *
1289 * @remarks None.
1290 *
1291 *--*/
1292 NTSTATUS
1293 NTAPI
1294 ObpCreateUnnamedHandle(IN PVOID Object,
1295 IN ACCESS_MASK DesiredAccess,
1296 IN ULONG AdditionalReferences,
1297 IN ULONG HandleAttributes,
1298 IN KPROCESSOR_MODE AccessMode,
1299 OUT PVOID *ReturnedObject,
1300 OUT PHANDLE ReturnedHandle)
1301 {
1302 HANDLE_TABLE_ENTRY NewEntry;
1303 POBJECT_HEADER ObjectHeader;
1304 HANDLE Handle;
1305 KAPC_STATE ApcState;
1306 BOOLEAN AttachedToProcess = FALSE, KernelHandle = FALSE;
1307 PVOID HandleTable;
1308 NTSTATUS Status;
1309 ACCESS_MASK GrantedAccess;
1310 POBJECT_TYPE ObjectType;
1311 PAGED_CODE();
1312
1313 /* Get the object header and type */
1314 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1315 ObjectType = ObjectHeader->Type;
1316 OBTRACE(OB_HANDLE_DEBUG,
1317 "%s - Creating handle for: %p. UNNAMED. HC PC %lx %lx\n",
1318 __FUNCTION__,
1319 Object,
1320 ObjectHeader->HandleCount,
1321 ObjectHeader->PointerCount);
1322
1323 /* Save the object header */
1324 NewEntry.Object = ObjectHeader;
1325
1326 /* Mask out the internal attributes */
1327 NewEntry.ObAttributes |= HandleAttributes & OBJ_HANDLE_ATTRIBUTES;
1328
1329 /* Check if this is a kernel handle */
1330 if (HandleAttributes & OBJ_KERNEL_HANDLE)
1331 {
1332 /* Set the handle table */
1333 HandleTable = ObpKernelHandleTable;
1334 KernelHandle = TRUE;
1335
1336 /* Check if we're not in the system process */
1337 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1338 {
1339 /* Attach to the system process */
1340 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1341 AttachedToProcess = TRUE;
1342 }
1343 }
1344 else
1345 {
1346 /* Get the current handle table */
1347 HandleTable = PsGetCurrentProcess()->ObjectTable;
1348 }
1349
1350 /* Increment the handle count */
1351 Status = ObpIncrementUnnamedHandleCount(Object,
1352 &DesiredAccess,
1353 AccessMode,
1354 HandleAttributes,
1355 PsGetCurrentProcess());
1356 if (!NT_SUCCESS(Status))
1357 {
1358 /*
1359 * We failed (meaning security failure, according to NT Internals)
1360 * detach and return
1361 */
1362 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1363 return Status;
1364 }
1365
1366 /* Remove what's not in the valid access mask */
1367 GrantedAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
1368 ACCESS_SYSTEM_SECURITY);
1369
1370 /* Handle extra references */
1371 if (AdditionalReferences)
1372 {
1373 /* Add them to the header */
1374 InterlockedExchangeAdd(&ObjectHeader->PointerCount,
1375 AdditionalReferences);
1376 }
1377
1378 /* Save the access mask */
1379 NewEntry.GrantedAccess = GrantedAccess;
1380
1381 /*
1382 * Create the actual handle. We'll need to do this *after* calling
1383 * ObpIncrementHandleCount to make sure that Object Security is valid
1384 * (specified in Gl00my documentation on Ob)
1385 */
1386 OBTRACE(OB_HANDLE_DEBUG,
1387 "%s - Handle Properties: [%p-%lx-%lx]\n",
1388 __FUNCTION__,
1389 NewEntry.Object, NewEntry.ObAttributes & 3, NewEntry.GrantedAccess);
1390 Handle = ExCreateHandle(HandleTable, &NewEntry);
1391
1392 /* Make sure we got a handle */
1393 if (Handle)
1394 {
1395 /* Check if this was a kernel handle */
1396 if (KernelHandle) Handle = ObMarkHandleAsKernelHandle(Handle);
1397
1398 /* Return handle and object */
1399 *ReturnedHandle = Handle;
1400
1401 /* Return the new object only if caller wanted it biased */
1402 if ((AdditionalReferences) && (ReturnedObject))
1403 {
1404 /* Return it */
1405 *ReturnedObject = Object;
1406 }
1407
1408 /* Detach if needed */
1409 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1410
1411 /* Trace and return */
1412 OBTRACE(OB_HANDLE_DEBUG,
1413 "%s - Returning Handle: %p HC PC %lx %lx\n",
1414 __FUNCTION__,
1415 Handle,
1416 ObjectHeader->HandleCount,
1417 ObjectHeader->PointerCount);
1418 return STATUS_SUCCESS;
1419 }
1420
1421 /* Handle extra references */
1422 if (AdditionalReferences)
1423 {
1424 /* Dereference it as many times as required */
1425 InterlockedExchangeAdd(&ObjectHeader->PointerCount,
1426 -(LONG)AdditionalReferences);
1427 }
1428
1429 /* Decrement the handle count and detach */
1430 ObpDecrementHandleCount(&ObjectHeader->Body,
1431 PsGetCurrentProcess(),
1432 GrantedAccess,
1433 ObjectType);
1434
1435 /* Detach and fail */
1436 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1437 return STATUS_INSUFFICIENT_RESOURCES;
1438 }
1439
1440 /*++
1441 * @name ObpCreateHandle
1442 *
1443 * The ObpCreateHandle routine <FILLMEIN>
1444 *
1445 * @param OpenReason
1446 * <FILLMEIN>.
1447 *
1448 * @param Object
1449 * <FILLMEIN>.
1450 *
1451 * @param Type
1452 * <FILLMEIN>.
1453 *
1454 * @param AccessState
1455 * <FILLMEIN>.
1456 *
1457 * @param AdditionalReferences
1458 * <FILLMEIN>.
1459 *
1460 * @param HandleAttributes
1461 * <FILLMEIN>.
1462 *
1463 * @param AccessMode
1464 * <FILLMEIN>.
1465 *
1466 * @param ReturnedObject
1467 * <FILLMEIN>.
1468 *
1469 * @param ReturnedHandle
1470 * <FILLMEIN>.
1471 *
1472 * @return <FILLMEIN>.
1473 *
1474 * @remarks Cleans up the Lookup Context on return.
1475 *
1476 *--*/
1477 NTSTATUS
1478 NTAPI
1479 ObpCreateHandle(IN OB_OPEN_REASON OpenReason,
1480 IN PVOID Object,
1481 IN POBJECT_TYPE Type OPTIONAL,
1482 IN PACCESS_STATE AccessState,
1483 IN ULONG AdditionalReferences,
1484 IN ULONG HandleAttributes,
1485 IN POBP_LOOKUP_CONTEXT Context,
1486 IN KPROCESSOR_MODE AccessMode,
1487 OUT PVOID *ReturnedObject,
1488 OUT PHANDLE ReturnedHandle)
1489 {
1490 HANDLE_TABLE_ENTRY NewEntry;
1491 POBJECT_HEADER ObjectHeader;
1492 HANDLE Handle;
1493 KAPC_STATE ApcState;
1494 BOOLEAN AttachedToProcess = FALSE, KernelHandle = FALSE;
1495 POBJECT_TYPE ObjectType;
1496 PVOID HandleTable;
1497 NTSTATUS Status;
1498 ACCESS_MASK DesiredAccess, GrantedAccess;
1499 PAUX_ACCESS_DATA AuxData;
1500 PAGED_CODE();
1501
1502 /* Get the object header and type */
1503 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1504 ObjectType = ObjectHeader->Type;
1505 OBTRACE(OB_HANDLE_DEBUG,
1506 "%s - Creating handle for: %p. Reason: %lx. HC PC %lx %lx\n",
1507 __FUNCTION__,
1508 Object,
1509 OpenReason,
1510 ObjectHeader->HandleCount,
1511 ObjectHeader->PointerCount);
1512
1513 /* Check if the types match */
1514 if ((Type) && (ObjectType != Type))
1515 {
1516 /* They don't, cleanup */
1517 if (Context) ObpReleaseLookupContext(Context);
1518 return STATUS_OBJECT_TYPE_MISMATCH;
1519 }
1520
1521 /* Save the object header */
1522 NewEntry.Object = ObjectHeader;
1523
1524 /* Check if this is a kernel handle */
1525 if (HandleAttributes & OBJ_KERNEL_HANDLE)
1526 {
1527 /* Set the handle table */
1528 HandleTable = ObpKernelHandleTable;
1529 KernelHandle = TRUE;
1530
1531 /* Check if we're not in the system process */
1532 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1533 {
1534 /* Attach to the system process */
1535 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1536 AttachedToProcess = TRUE;
1537 }
1538 }
1539 else
1540 {
1541 /* Get the current handle table */
1542 HandleTable = PsGetCurrentProcess()->ObjectTable;
1543 }
1544
1545 /* Increment the handle count */
1546 Status = ObpIncrementHandleCount(Object,
1547 AccessState,
1548 AccessMode,
1549 HandleAttributes,
1550 PsGetCurrentProcess(),
1551 OpenReason);
1552 if (!NT_SUCCESS(Status))
1553 {
1554 /*
1555 * We failed (meaning security failure, according to NT Internals)
1556 * detach and return
1557 */
1558 if (Context) ObpReleaseLookupContext(Context);
1559 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1560 return Status;
1561 }
1562
1563 /* Check if we are doing audits on close */
1564 if (AccessState->GenerateOnClose)
1565 {
1566 /* Force the attribute on */
1567 HandleAttributes |= OBJ_AUDIT_OBJECT_CLOSE;
1568 }
1569
1570 /* Mask out the internal attributes */
1571 NewEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
1572
1573 /* Get the original desired access */
1574 DesiredAccess = AccessState->RemainingDesiredAccess |
1575 AccessState->PreviouslyGrantedAccess;
1576
1577 /* Remove what's not in the valid access mask */
1578 GrantedAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
1579 ACCESS_SYSTEM_SECURITY);
1580
1581 /* Update the value in the access state */
1582 AccessState->PreviouslyGrantedAccess = GrantedAccess;
1583
1584 /* Get the auxiliary data */
1585 AuxData = AccessState->AuxData;
1586
1587 /* Handle extra references */
1588 if (AdditionalReferences)
1589 {
1590 /* Add them to the header */
1591 InterlockedExchangeAdd(&ObjectHeader->PointerCount, AdditionalReferences);
1592 }
1593
1594 /* Now we can release the object */
1595 if (Context) ObpReleaseLookupContext(Context);
1596
1597 /* Save the access mask */
1598 NewEntry.GrantedAccess = GrantedAccess;
1599
1600 /*
1601 * Create the actual handle. We'll need to do this *after* calling
1602 * ObpIncrementHandleCount to make sure that Object Security is valid
1603 * (specified in Gl00my documentation on Ob)
1604 */
1605 OBTRACE(OB_HANDLE_DEBUG,
1606 "%s - Handle Properties: [%p-%lx-%lx]\n",
1607 __FUNCTION__,
1608 NewEntry.Object, NewEntry.ObAttributes & 3, NewEntry.GrantedAccess);
1609 Handle = ExCreateHandle(HandleTable, &NewEntry);
1610
1611 /* Make sure we got a handle */
1612 if (Handle)
1613 {
1614 /* Check if this was a kernel handle */
1615 if (KernelHandle) Handle = ObMarkHandleAsKernelHandle(Handle);
1616
1617 /* Return it */
1618 *ReturnedHandle = Handle;
1619
1620 /* Check if we need to generate on audit */
1621 if (AccessState->GenerateAudit)
1622 {
1623 /* Audit the handle creation */
1624 //SeAuditHandleCreation(AccessState, Handle);
1625 }
1626
1627 /* Check if this was a create */
1628 if (OpenReason == ObCreateHandle)
1629 {
1630 /* Check if we need to audit the privileges */
1631 if ((AuxData->PrivilegeSet) &&
1632 (AuxData->PrivilegeSet->PrivilegeCount))
1633 {
1634 /* Do the audit */
1635 #if 0
1636 SePrivilegeObjectAuditAlarm(Handle,
1637 &AccessState->
1638 SubjectSecurityContext,
1639 GrantedAccess,
1640 AuxData->PrivilegeSet,
1641 TRUE,
1642 ExGetPreviousMode());
1643 #endif
1644 }
1645 }
1646
1647 /* Return the new object only if caller wanted it biased */
1648 if ((AdditionalReferences) && (ReturnedObject))
1649 {
1650 /* Return it */
1651 *ReturnedObject = Object;
1652 }
1653
1654 /* Detach if needed */
1655 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1656
1657 /* Trace and return */
1658 OBTRACE(OB_HANDLE_DEBUG,
1659 "%s - Returning Handle: %p HC PC %lx %lx\n",
1660 __FUNCTION__,
1661 Handle,
1662 ObjectHeader->HandleCount,
1663 ObjectHeader->PointerCount);
1664 return STATUS_SUCCESS;
1665 }
1666
1667 /* Decrement the handle count and detach */
1668 ObpDecrementHandleCount(&ObjectHeader->Body,
1669 PsGetCurrentProcess(),
1670 GrantedAccess,
1671 ObjectType);
1672
1673 /* Handle extra references */
1674 if (AdditionalReferences)
1675 {
1676 /* Check how many extra references were added */
1677 if (AdditionalReferences > 1)
1678 {
1679 /* Dereference it many times */
1680 InterlockedExchangeAdd(&ObjectHeader->PointerCount,
1681 -(LONG)(AdditionalReferences - 1));
1682 }
1683
1684 /* Dereference the object one last time */
1685 ObDereferenceObject(Object);
1686 }
1687
1688 /* Detach if necessary and fail */
1689 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1690 return STATUS_INSUFFICIENT_RESOURCES;
1691 }
1692
1693 /*++
1694 * @name ObpCloseHandle
1695 *
1696 * The ObpCloseHandle routine <FILLMEIN>
1697 *
1698 * @param Handle
1699 * <FILLMEIN>.
1700 *
1701 * @param AccessMode
1702 * <FILLMEIN>.
1703 *
1704 * @return <FILLMEIN>.
1705 *
1706 * @remarks None.
1707 *
1708 *--*/
1709 NTSTATUS
1710 NTAPI
1711 ObpCloseHandle(IN HANDLE Handle,
1712 IN KPROCESSOR_MODE AccessMode)
1713 {
1714 PVOID HandleTable;
1715 BOOLEAN AttachedToProcess = FALSE;
1716 KAPC_STATE ApcState;
1717 PHANDLE_TABLE_ENTRY HandleTableEntry;
1718 NTSTATUS Status;
1719 PEPROCESS Process = PsGetCurrentProcess();
1720 PAGED_CODE();
1721 OBTRACE(OB_HANDLE_DEBUG,
1722 "%s - Closing handle: %p\n", __FUNCTION__, Handle);
1723
1724 if (AccessMode == KernelMode && Handle == (HANDLE)-1)
1725 return STATUS_INVALID_HANDLE;
1726
1727 /* Check if we're dealing with a kernel handle */
1728 if (ObpIsKernelHandle(Handle, AccessMode))
1729 {
1730 /* Use the kernel table and convert the handle */
1731 HandleTable = ObpKernelHandleTable;
1732 Handle = ObKernelHandleToHandle(Handle);
1733
1734 /* Check if we're not in the system process */
1735 if (Process != PsInitialSystemProcess)
1736 {
1737 /* Attach to the system process */
1738 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1739 AttachedToProcess = TRUE;
1740 }
1741 }
1742 else
1743 {
1744 /* Use the process's handle table */
1745 HandleTable = Process->ObjectTable;
1746 }
1747
1748 /* Enter a critical region to protect handle access */
1749 KeEnterCriticalRegion();
1750
1751 /* Get the handle entry */
1752 HandleTableEntry = ExMapHandleToPointer(HandleTable, Handle);
1753 if (HandleTableEntry)
1754 {
1755 /* Now close the entry */
1756 Status = ObpCloseHandleTableEntry(HandleTable,
1757 HandleTableEntry,
1758 Handle,
1759 AccessMode,
1760 FALSE);
1761
1762 /* We can quit the critical region now */
1763 KeLeaveCriticalRegion();
1764
1765 /* Detach and return success */
1766 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1767 }
1768 else
1769 {
1770 /* We failed, quit the critical region */
1771 KeLeaveCriticalRegion();
1772
1773 /* Detach */
1774 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1775
1776 /* Check if we have a valid handle that's not the process or thread */
1777 if ((Handle) &&
1778 (Handle != NtCurrentProcess()) &&
1779 (Handle != NtCurrentThread()))
1780 {
1781 /* Check if we came from user mode */
1782 if (AccessMode != KernelMode)
1783 {
1784 /* Check if we have no debug port */
1785 if (Process->DebugPort)
1786 {
1787 /* Make sure we're not attached */
1788 if (!KeIsAttachedProcess())
1789 {
1790 /* Raise an exception */
1791 return KeRaiseUserException(STATUS_INVALID_HANDLE);
1792 }
1793 }
1794 }
1795 else
1796 {
1797 /* This is kernel mode. Check if we're exiting */
1798 if (!(PsIsThreadTerminating(PsGetCurrentThread())) &&
1799 (Process->Peb))
1800 {
1801 /* Check if the debugger is enabled */
1802 if (KdDebuggerEnabled)
1803 {
1804 /* Bugcheck */
1805 KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 1, 0, 0);
1806 }
1807 }
1808 }
1809 }
1810
1811 /* Set invalid status */
1812 Status = STATUS_INVALID_HANDLE;
1813 }
1814
1815 /* Return status */
1816 OBTRACE(OB_HANDLE_DEBUG,
1817 "%s - Closed handle: %p S: %lx\n",
1818 __FUNCTION__, Handle, Status);
1819 return Status;
1820 }
1821
1822 /*++
1823 * @name ObpSetHandleAttributes
1824 *
1825 * The ObpSetHandleAttributes routine <FILLMEIN>
1826 *
1827 * @param HandleTableEntry
1828 * <FILLMEIN>.
1829 *
1830 * @param Context
1831 * <FILLMEIN>.
1832 *
1833 * @return <FILLMEIN>.
1834 *
1835 * @remarks None.
1836 *
1837 *--*/
1838 BOOLEAN
1839 NTAPI
1840 ObpSetHandleAttributes(IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
1841 IN ULONG_PTR Context)
1842 {
1843 POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo = (PVOID)Context;
1844 POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1845
1846 /* Check if making the handle inheritable */
1847 if (SetHandleInfo->Information.Inherit)
1848 {
1849 /* Check if inheriting is not supported for this object */
1850 if (ObjectHeader->Type->TypeInfo.InvalidAttributes & OBJ_INHERIT)
1851 {
1852 /* Fail without changing anything */
1853 return FALSE;
1854 }
1855
1856 /* Set the flag */
1857 HandleTableEntry->ObAttributes |= OBJ_INHERIT;
1858 }
1859 else
1860 {
1861 /* Otherwise this implies we're removing the flag */
1862 HandleTableEntry->ObAttributes &= ~OBJ_INHERIT;
1863 }
1864
1865 /* Check if making the handle protected */
1866 if (SetHandleInfo->Information.ProtectFromClose)
1867 {
1868 /* Set the flag */
1869 HandleTableEntry->GrantedAccess |= ObpAccessProtectCloseBit;
1870 }
1871 else
1872 {
1873 /* Otherwise, remove it */
1874 HandleTableEntry->GrantedAccess &= ~ObpAccessProtectCloseBit;
1875 }
1876
1877 /* Return success */
1878 return TRUE;
1879 }
1880
1881 /*++
1882 * @name ObpCloseHandleCallback
1883 *
1884 * The ObpCloseHandleCallback routine <FILLMEIN>
1885 *
1886 * @param HandleTable
1887 * <FILLMEIN>.
1888 *
1889 * @param Object
1890 * <FILLMEIN>.
1891 *
1892 * @param GrantedAccess
1893 * <FILLMEIN>.
1894 *
1895 * @param Context
1896 * <FILLMEIN>.
1897 *
1898 * @return <FILLMEIN>.
1899 *
1900 * @remarks None.
1901 *
1902 *--*/
1903 BOOLEAN
1904 NTAPI
1905 ObpCloseHandleCallback(IN PHANDLE_TABLE_ENTRY HandleTableEntry,
1906 IN HANDLE Handle,
1907 IN PVOID Context)
1908 {
1909 POBP_CLOSE_HANDLE_CONTEXT CloseContext = (POBP_CLOSE_HANDLE_CONTEXT)Context;
1910
1911 /* Simply decrement the handle count */
1912 ObpCloseHandleTableEntry(CloseContext->HandleTable,
1913 HandleTableEntry,
1914 Handle,
1915 CloseContext->AccessMode,
1916 TRUE);
1917 return TRUE;
1918 }
1919
1920 /*++
1921 * @name ObpDuplicateHandleCallback
1922 *
1923 * The ObpDuplicateHandleCallback routine <FILLMEIN>
1924 *
1925 * @param HandleTable
1926 * <FILLMEIN>.
1927 *
1928 * @param HandleTableEntry
1929 * <FILLMEIN>.
1930 *
1931 * @param Context
1932 * <FILLMEIN>.
1933 *
1934 * @return <FILLMEIN>.
1935 *
1936 * @remarks None.
1937 *
1938 *--*/
1939 BOOLEAN
1940 NTAPI
1941 ObpDuplicateHandleCallback(IN PEPROCESS Process,
1942 IN PHANDLE_TABLE HandleTable,
1943 IN PHANDLE_TABLE_ENTRY OldEntry,
1944 IN PHANDLE_TABLE_ENTRY HandleTableEntry)
1945 {
1946 POBJECT_HEADER ObjectHeader;
1947 BOOLEAN Ret = FALSE;
1948 ACCESS_STATE AccessState;
1949 NTSTATUS Status;
1950 PAGED_CODE();
1951
1952 /* Make sure that the handle is inheritable */
1953 Ret = (HandleTableEntry->ObAttributes & OBJ_INHERIT) != 0;
1954 if (Ret)
1955 {
1956 /* Get the object header */
1957 ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1958
1959 /* Increment the pointer count */
1960 InterlockedIncrement(&ObjectHeader->PointerCount);
1961
1962 /* Release the handle lock */
1963 ExUnlockHandleTableEntry(HandleTable, OldEntry);
1964
1965 /* Setup the access state */
1966 AccessState.PreviouslyGrantedAccess = HandleTableEntry->GrantedAccess;
1967
1968 /* Call the shared routine for incrementing handles */
1969 Status = ObpIncrementHandleCount(&ObjectHeader->Body,
1970 &AccessState,
1971 KernelMode,
1972 HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES,
1973 Process,
1974 ObInheritHandle);
1975 if (!NT_SUCCESS(Status))
1976 {
1977 /* Return failure */
1978 ObDereferenceObject(&ObjectHeader->Body);
1979 Ret = FALSE;
1980 }
1981 }
1982 else
1983 {
1984 /* Release the handle lock */
1985 ExUnlockHandleTableEntry(HandleTable, OldEntry);
1986 }
1987
1988 /* Return duplication result */
1989 return Ret;
1990 }
1991
1992 VOID
1993 NTAPI
1994 ObClearProcessHandleTable(IN PEPROCESS Process)
1995 {
1996 /* FIXME */
1997 }
1998
1999 /*++
2000 * @name ObpCreateHandleTable
2001 *
2002 * The ObpCreateHandleTable routine <FILLMEIN>
2003 *
2004 * @param Parent
2005 * <FILLMEIN>.
2006 *
2007 * @param Process
2008 * <FILLMEIN>.
2009 *
2010 * @return <FILLMEIN>.
2011 *
2012 * @remarks None.
2013 *
2014 *--*/
2015 NTSTATUS
2016 NTAPI
2017 ObInitProcess(IN PEPROCESS Parent OPTIONAL,
2018 IN PEPROCESS Process)
2019 {
2020 PHANDLE_TABLE ParentTable, ObjectTable;
2021
2022 /* Check for a parent */
2023 if (Parent)
2024 {
2025 /* Reference the parent's table */
2026 ParentTable = ObReferenceProcessHandleTable(Parent);
2027 if (!ParentTable) return STATUS_PROCESS_IS_TERMINATING;
2028
2029 /* Duplicate it */
2030 ObjectTable = ExDupHandleTable(Process,
2031 ParentTable,
2032 ObpDuplicateHandleCallback,
2033 OBJ_INHERIT);
2034 }
2035 else
2036 {
2037 /* Otherwise just create a new table */
2038 ParentTable = NULL;
2039 ObjectTable = ExCreateHandleTable(Process);
2040 }
2041
2042 /* Make sure we have a table */
2043 if (ObjectTable)
2044 {
2045 /* Associate it */
2046 Process->ObjectTable = ObjectTable;
2047
2048 /* Check for auditing */
2049 if (SeDetailedAuditingWithToken(NULL))
2050 {
2051 /* FIXME: TODO */
2052 DPRINT1("Need auditing!\n");
2053 }
2054
2055 /* Get rid of the old table now */
2056 if (ParentTable) ObDereferenceProcessHandleTable(Parent);
2057
2058 /* We are done */
2059 return STATUS_SUCCESS;
2060 }
2061 else
2062 {
2063 /* Fail */
2064 Process->ObjectTable = NULL;
2065 if (ParentTable) ObDereferenceProcessHandleTable(Parent);
2066 return STATUS_INSUFFICIENT_RESOURCES;
2067 }
2068 }
2069
2070 /*++
2071 * @name ObKillProcess
2072 *
2073 * The ObKillProcess routine <FILLMEIN>
2074 *
2075 * @param Process
2076 * <FILLMEIN>.
2077 *
2078 * @return None.
2079 *
2080 * @remarks None.
2081 *
2082 *--*/
2083 VOID
2084 NTAPI
2085 ObKillProcess(IN PEPROCESS Process)
2086 {
2087 PHANDLE_TABLE HandleTable;
2088 OBP_CLOSE_HANDLE_CONTEXT Context;
2089 BOOLEAN HardErrors;
2090 PAGED_CODE();
2091
2092 /* Wait for process rundown and then complete it */
2093 ExWaitForRundownProtectionRelease(&Process->RundownProtect);
2094 ExRundownCompleted(&Process->RundownProtect);
2095
2096 /* Get the object table */
2097 HandleTable = Process->ObjectTable;
2098 if (!HandleTable) return;
2099
2100 /* Disable hard errors while we close handles */
2101 HardErrors = IoSetThreadHardErrorMode(FALSE);
2102
2103 /* Enter a critical region */
2104 KeEnterCriticalRegion();
2105
2106 /* Fill out the context */
2107 Context.AccessMode = KernelMode;
2108 Context.HandleTable = HandleTable;
2109
2110 /* Sweep the handle table to close all handles */
2111 ExSweepHandleTable(HandleTable,
2112 ObpCloseHandleCallback,
2113 &Context);
2114 ASSERT(HandleTable->HandleCount == 0);
2115
2116 /* Leave the critical region */
2117 KeLeaveCriticalRegion();
2118
2119 /* Re-enable hard errors */
2120 IoSetThreadHardErrorMode(HardErrors);
2121
2122 /* Destroy the object table */
2123 Process->ObjectTable = NULL;
2124 ExDestroyHandleTable(HandleTable, NULL);
2125 }
2126
2127 NTSTATUS
2128 NTAPI
2129 ObDuplicateObject(IN PEPROCESS SourceProcess,
2130 IN HANDLE SourceHandle,
2131 IN PEPROCESS TargetProcess OPTIONAL,
2132 IN PHANDLE TargetHandle OPTIONAL,
2133 IN ACCESS_MASK DesiredAccess,
2134 IN ULONG HandleAttributes,
2135 IN ULONG Options,
2136 IN KPROCESSOR_MODE PreviousMode)
2137 {
2138 HANDLE_TABLE_ENTRY NewHandleEntry;
2139 BOOLEAN AttachedToProcess = FALSE;
2140 PVOID SourceObject;
2141 POBJECT_HEADER ObjectHeader;
2142 POBJECT_TYPE ObjectType;
2143 HANDLE NewHandle;
2144 KAPC_STATE ApcState;
2145 NTSTATUS Status;
2146 ACCESS_MASK TargetAccess, SourceAccess;
2147 ACCESS_STATE AccessState;
2148 PACCESS_STATE PassedAccessState = NULL;
2149 AUX_ACCESS_DATA AuxData;
2150 PHANDLE_TABLE HandleTable;
2151 OBJECT_HANDLE_INFORMATION HandleInformation;
2152 ULONG AuditMask;
2153 BOOLEAN KernelHandle = FALSE;
2154
2155 PAGED_CODE();
2156 OBTRACE(OB_HANDLE_DEBUG,
2157 "%s - Duplicating handle: %p for %p into %p\n",
2158 __FUNCTION__,
2159 SourceHandle,
2160 SourceProcess,
2161 TargetProcess);
2162
2163 /* Assume failure */
2164 if (TargetHandle) *TargetHandle = NULL;
2165
2166 /* Check if we're not duplicating the same access */
2167 if (!(Options & DUPLICATE_SAME_ACCESS))
2168 {
2169 /* Validate the desired access */
2170 Status = STATUS_SUCCESS; //ObpValidateDesiredAccess(DesiredAccess);
2171 if (!NT_SUCCESS(Status)) return Status;
2172 }
2173
2174 /* Reference the object table */
2175 HandleTable = ObReferenceProcessHandleTable(SourceProcess);
2176 if (!HandleTable) return STATUS_PROCESS_IS_TERMINATING;
2177
2178 /* Reference the process object */
2179 Status = ObpReferenceProcessObjectByHandle(SourceHandle,
2180 SourceProcess,
2181 HandleTable,
2182 PreviousMode,
2183 &SourceObject,
2184 &HandleInformation,
2185 &AuditMask);
2186 if (!NT_SUCCESS(Status))
2187 {
2188 /* Fail */
2189 ObDereferenceProcessHandleTable(SourceProcess);
2190 return Status;
2191 }
2192 else
2193 {
2194 /* Check if we have to don't have to audit object close */
2195 if (!(HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE))
2196 {
2197 /* Then there is no audit mask */
2198 AuditMask = 0;
2199 }
2200 }
2201
2202 /* Check if there's no target process */
2203 if (!TargetProcess)
2204 {
2205 /* Check if the caller wanted actual duplication */
2206 if (!(Options & DUPLICATE_CLOSE_SOURCE))
2207 {
2208 /* Invalid request */
2209 Status = STATUS_INVALID_PARAMETER;
2210 }
2211 else
2212 {
2213 /* Otherwise, do the attach */
2214 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2215
2216 /* Close the handle and detach */
2217 NtClose(SourceHandle);
2218 KeUnstackDetachProcess(&ApcState);
2219 }
2220
2221 /* Return */
2222 ObDereferenceProcessHandleTable(SourceProcess);
2223 ObDereferenceObject(SourceObject);
2224 return Status;
2225 }
2226
2227 /* Create a kernel handle if asked, but only in the system process */
2228 if (PreviousMode == KernelMode &&
2229 HandleAttributes & OBJ_KERNEL_HANDLE &&
2230 TargetProcess == PsInitialSystemProcess)
2231 {
2232 KernelHandle = TRUE;
2233 }
2234
2235 /* Get the target handle table */
2236 HandleTable = ObReferenceProcessHandleTable(TargetProcess);
2237 if (!HandleTable)
2238 {
2239 /* Check if the caller wanted us to close the handle */
2240 if (Options & DUPLICATE_CLOSE_SOURCE)
2241 {
2242 /* Do the attach */
2243 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2244
2245 /* Close the handle and detach */
2246 NtClose(SourceHandle);
2247 KeUnstackDetachProcess(&ApcState);
2248 }
2249
2250 /* Return */
2251 ObDereferenceProcessHandleTable(SourceProcess);
2252 ObDereferenceObject(SourceObject);
2253 return STATUS_PROCESS_IS_TERMINATING;
2254 }
2255
2256 /* Get the source access */
2257 SourceAccess = HandleInformation.GrantedAccess;
2258
2259 /* Check if we're not in the target process */
2260 if (TargetProcess != PsGetCurrentProcess())
2261 {
2262 /* Attach to it */
2263 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
2264 AttachedToProcess = TRUE;
2265 }
2266
2267 /* Check if we're duplicating the attributes */
2268 if (Options & DUPLICATE_SAME_ATTRIBUTES)
2269 {
2270 /* Duplicate them */
2271 HandleAttributes = HandleInformation.HandleAttributes;
2272 }
2273 else
2274 {
2275 /* Don't allow caller to bypass auditing */
2276 HandleAttributes |= HandleInformation.HandleAttributes &
2277 OBJ_AUDIT_OBJECT_CLOSE;
2278 }
2279
2280 /* Check if we're duplicating the access */
2281 if (Options & DUPLICATE_SAME_ACCESS) DesiredAccess = SourceAccess;
2282
2283 /* Get object data */
2284 ObjectHeader = OBJECT_TO_OBJECT_HEADER(SourceObject);
2285 ObjectType = ObjectHeader->Type;
2286
2287 /* Fill out the entry */
2288 RtlZeroMemory(&NewHandleEntry, sizeof(HANDLE_TABLE_ENTRY));
2289 NewHandleEntry.Object = ObjectHeader;
2290 NewHandleEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
2291
2292 /* Check if we're using a generic mask */
2293 if (DesiredAccess & GENERIC_ACCESS)
2294 {
2295 /* Map it */
2296 RtlMapGenericMask(&DesiredAccess,
2297 &ObjectType->TypeInfo.GenericMapping);
2298 }
2299
2300 /* Set the target access, always propagate ACCESS_SYSTEM_SECURITY */
2301 TargetAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
2302 ACCESS_SYSTEM_SECURITY);
2303 NewHandleEntry.GrantedAccess = TargetAccess;
2304
2305 /* Check if we're asking for new access */
2306 if (TargetAccess & ~SourceAccess)
2307 {
2308 /* We are. We need the security procedure to validate this */
2309 if (ObjectType->TypeInfo.SecurityProcedure == SeDefaultObjectMethod)
2310 {
2311 /* Use our built-in access state */
2312 PassedAccessState = &AccessState;
2313 Status = SeCreateAccessState(&AccessState,
2314 &AuxData,
2315 TargetAccess,
2316 &ObjectType->TypeInfo.GenericMapping);
2317 }
2318 else
2319 {
2320 /* Otherwise we can't allow this privilege elevation */
2321 Status = STATUS_ACCESS_DENIED;
2322 }
2323 }
2324 else
2325 {
2326 /* We don't need an access state */
2327 Status = STATUS_SUCCESS;
2328 }
2329
2330 /* Make sure the access state was created OK */
2331 if (NT_SUCCESS(Status))
2332 {
2333 /* Add a new handle */
2334 Status = ObpIncrementHandleCount(SourceObject,
2335 PassedAccessState,
2336 PreviousMode,
2337 HandleAttributes,
2338 PsGetCurrentProcess(),
2339 ObDuplicateHandle);
2340 }
2341
2342 /* Check if we were attached */
2343 if (AttachedToProcess)
2344 {
2345 /* We can safely detach now */
2346 KeUnstackDetachProcess(&ApcState);
2347 AttachedToProcess = FALSE;
2348 }
2349
2350 /* Check if we have to close the source handle */
2351 if (Options & DUPLICATE_CLOSE_SOURCE)
2352 {
2353 /* Attach and close */
2354 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2355 NtClose(SourceHandle);
2356 KeUnstackDetachProcess(&ApcState);
2357 }
2358
2359 /* Check if we had an access state */
2360 if (PassedAccessState) SeDeleteAccessState(PassedAccessState);
2361
2362 /* Now check if incrementing actually failed */
2363 if (!NT_SUCCESS(Status))
2364 {
2365 /* Dereference handle tables */
2366 ObDereferenceProcessHandleTable(SourceProcess);
2367 ObDereferenceProcessHandleTable(TargetProcess);
2368
2369 /* Dereference the source object */
2370 ObDereferenceObject(SourceObject);
2371 return Status;
2372 }
2373
2374 /* Now create the handle */
2375 NewHandle = ExCreateHandle(HandleTable, &NewHandleEntry);
2376 if (!NewHandle)
2377 {
2378 /* Undo the increment */
2379 ObpDecrementHandleCount(SourceObject,
2380 TargetProcess,
2381 TargetAccess,
2382 ObjectType);
2383
2384 /* Deference the object and set failure status */
2385 ObDereferenceObject(SourceObject);
2386 Status = STATUS_INSUFFICIENT_RESOURCES;
2387 }
2388
2389 /* Mark it as a kernel handle if requested */
2390 if (KernelHandle)
2391 {
2392 NewHandle = ObMarkHandleAsKernelHandle(NewHandle);
2393 }
2394
2395 /* Return the handle */
2396 if (TargetHandle) *TargetHandle = NewHandle;
2397
2398 /* Dereference handle tables */
2399 ObDereferenceProcessHandleTable(SourceProcess);
2400 ObDereferenceProcessHandleTable(TargetProcess);
2401
2402 /* Return status */
2403 OBTRACE(OB_HANDLE_DEBUG,
2404 "%s - Duplicated handle: %p for %p into %p. Source: %p HC PC %lx %lx\n",
2405 __FUNCTION__,
2406 NewHandle,
2407 SourceProcess,
2408 TargetProcess,
2409 SourceObject,
2410 ObjectHeader->PointerCount,
2411 ObjectHeader->HandleCount);
2412 return Status;
2413 }
2414
2415 /* PUBLIC FUNCTIONS *********************************************************/
2416
2417 /*++
2418 * @name ObOpenObjectByName
2419 * @implemented NT4
2420 *
2421 * The ObOpenObjectByName routine <FILLMEIN>
2422 *
2423 * @param ObjectAttributes
2424 * <FILLMEIN>.
2425 *
2426 * @param ObjectType
2427 * <FILLMEIN>.
2428 *
2429 * @param AccessMode
2430 * <FILLMEIN>.
2431 *
2432 * @param PassedAccessState
2433 * <FILLMEIN>.
2434 *
2435 * @param DesiredAccess
2436 * <FILLMEIN>.
2437 *
2438 * @param ParseContext
2439 * <FILLMEIN>.
2440 *
2441 * @param Handle
2442 * <FILLMEIN>.
2443 *
2444 * @return <FILLMEIN>.
2445 *
2446 * @remarks None.
2447 *
2448 *--*/
2449 NTSTATUS
2450 NTAPI
2451 ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
2452 IN POBJECT_TYPE ObjectType,
2453 IN KPROCESSOR_MODE AccessMode,
2454 IN PACCESS_STATE PassedAccessState,
2455 IN ACCESS_MASK DesiredAccess,
2456 IN OUT PVOID ParseContext,
2457 OUT PHANDLE Handle)
2458 {
2459 PVOID Object = NULL;
2460 UNICODE_STRING ObjectName;
2461 NTSTATUS Status, Status2;
2462 POBJECT_HEADER ObjectHeader;
2463 PGENERIC_MAPPING GenericMapping = NULL;
2464 OB_OPEN_REASON OpenReason;
2465 POB_TEMP_BUFFER TempBuffer;
2466 PAGED_CODE();
2467
2468 /* Assume failure */
2469 *Handle = NULL;
2470
2471 /* Check if we didn't get any Object Attributes */
2472 if (!ObjectAttributes)
2473 {
2474 /* Fail with special status code */
2475 return STATUS_INVALID_PARAMETER;
2476 }
2477
2478 /* Allocate the temporary buffer */
2479 TempBuffer = ExAllocatePoolWithTag(NonPagedPool,
2480 sizeof(OB_TEMP_BUFFER),
2481 TAG_OB_TEMP_STORAGE);
2482 if (!TempBuffer) return STATUS_INSUFFICIENT_RESOURCES;
2483
2484 /* Capture all the info */
2485 Status = ObpCaptureObjectCreateInformation(ObjectAttributes,
2486 AccessMode,
2487 AccessMode,
2488 TRUE,
2489 &TempBuffer->ObjectCreateInfo,
2490 &ObjectName);
2491 if (!NT_SUCCESS(Status))
2492 {
2493 /* Fail */
2494 ExFreePoolWithTag(TempBuffer, TAG_OB_TEMP_STORAGE);
2495 return Status;
2496 }
2497
2498 /* Check if we didn't get an access state */
2499 if (!PassedAccessState)
2500 {
2501 /* Try to get the generic mapping if we can */
2502 if (ObjectType) GenericMapping = &ObjectType->TypeInfo.GenericMapping;
2503
2504 /* Use our built-in access state */
2505 PassedAccessState = &TempBuffer->LocalAccessState;
2506 Status = SeCreateAccessState(&TempBuffer->LocalAccessState,
2507 &TempBuffer->AuxData,
2508 DesiredAccess,
2509 GenericMapping);
2510 if (!NT_SUCCESS(Status)) goto Quickie;
2511 }
2512
2513 /* Get the security descriptor */
2514 if (TempBuffer->ObjectCreateInfo.SecurityDescriptor)
2515 {
2516 /* Save it in the access state */
2517 PassedAccessState->SecurityDescriptor =
2518 TempBuffer->ObjectCreateInfo.SecurityDescriptor;
2519 }
2520
2521 /* Validate the access mask */
2522 Status = ObpValidateAccessMask(PassedAccessState);
2523 if (!NT_SUCCESS(Status))
2524 {
2525 /* Cleanup after lookup */
2526 ObpReleaseLookupContext(&TempBuffer->LookupContext);
2527 goto Cleanup;
2528 }
2529
2530 /* Now do the lookup */
2531 Status = ObpLookupObjectName(TempBuffer->ObjectCreateInfo.RootDirectory,
2532 &ObjectName,
2533 TempBuffer->ObjectCreateInfo.Attributes,
2534 ObjectType,
2535 AccessMode,
2536 ParseContext,
2537 TempBuffer->ObjectCreateInfo.SecurityQos,
2538 NULL,
2539 PassedAccessState,
2540 &TempBuffer->LookupContext,
2541 &Object);
2542 if (!NT_SUCCESS(Status))
2543 {
2544 /* Cleanup after lookup */
2545 ObpReleaseLookupContext(&TempBuffer->LookupContext);
2546 goto Cleanup;
2547 }
2548
2549 /* Check if this object has create information */
2550 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2551 if (ObjectHeader->Flags & OB_FLAG_CREATE_INFO)
2552 {
2553 /* Then we are creating a new handle */
2554 OpenReason = ObCreateHandle;
2555
2556 /* Check if we still have create info */
2557 if (ObjectHeader->ObjectCreateInfo)
2558 {
2559 /* Free it */
2560 ObpFreeObjectCreateInformation(ObjectHeader->
2561 ObjectCreateInfo);
2562 ObjectHeader->ObjectCreateInfo = NULL;
2563 }
2564 }
2565 else
2566 {
2567 /* Otherwise, we are merely opening it */
2568 OpenReason = ObOpenHandle;
2569 }
2570
2571 /* Check if we have invalid object attributes */
2572 if (ObjectHeader->Type->TypeInfo.InvalidAttributes &
2573 TempBuffer->ObjectCreateInfo.Attributes)
2574 {
2575 /* Set failure code */
2576 Status = STATUS_INVALID_PARAMETER;
2577
2578 /* Cleanup after lookup */
2579 ObpReleaseLookupContext(&TempBuffer->LookupContext);
2580
2581 /* Dereference the object */
2582 ObDereferenceObject(Object);
2583 }
2584 else
2585 {
2586 /* Create the actual handle now */
2587 Status2 = ObpCreateHandle(OpenReason,
2588 Object,
2589 ObjectType,
2590 PassedAccessState,
2591 0,
2592 TempBuffer->ObjectCreateInfo.Attributes,
2593 &TempBuffer->LookupContext,
2594 AccessMode,
2595 NULL,
2596 Handle);
2597 if (!NT_SUCCESS(Status2))
2598 {
2599 ObDereferenceObject(Object);
2600 Status = Status2;
2601 }
2602 }
2603
2604 Cleanup:
2605 /* Delete the access state */
2606 if (PassedAccessState == &TempBuffer->LocalAccessState)
2607 {
2608 SeDeleteAccessState(PassedAccessState);
2609 }
2610
2611 Quickie:
2612 /* Release the object attributes and temporary buffer */
2613 ObpReleaseObjectCreateInformation(&TempBuffer->ObjectCreateInfo);
2614 if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
2615 ExFreePoolWithTag(TempBuffer, TAG_OB_TEMP_STORAGE);
2616
2617 /* Return status */
2618 OBTRACE(OB_HANDLE_DEBUG,
2619 "%s - returning Object %p with PC S: %lx %lx\n",
2620 __FUNCTION__,
2621 Object,
2622 Object ? OBJECT_TO_OBJECT_HEADER(Object)->PointerCount : -1,
2623 Status);
2624 return Status;
2625 }
2626
2627 /*++
2628 * @name ObOpenObjectByPointer
2629 * @implemented NT4
2630 *
2631 * The ObOpenObjectByPointer routine <FILLMEIN>
2632 *
2633 * @param Object
2634 * <FILLMEIN>.
2635 *
2636 * @param HandleAttributes
2637 * <FILLMEIN>.
2638 *
2639 * @param PassedAccessState
2640 * <FILLMEIN>.
2641 *
2642 * @param DesiredAccess
2643 * <FILLMEIN>.
2644 *
2645 * @param ObjectType
2646 * <FILLMEIN>.
2647 *
2648 * @param AccessMode
2649 * <FILLMEIN>.
2650 *
2651 * @param Handle
2652 * <FILLMEIN>.
2653 *
2654 * @return <FILLMEIN>.
2655 *
2656 * @remarks None.
2657 *
2658 *--*/
2659 NTSTATUS
2660 NTAPI
2661 ObOpenObjectByPointer(IN PVOID Object,
2662 IN ULONG HandleAttributes,
2663 IN PACCESS_STATE PassedAccessState,
2664 IN ACCESS_MASK DesiredAccess,
2665 IN POBJECT_TYPE ObjectType,
2666 IN KPROCESSOR_MODE AccessMode,
2667 OUT PHANDLE Handle)
2668 {
2669 POBJECT_HEADER Header;
2670 NTSTATUS Status;
2671 ACCESS_STATE AccessState;
2672 AUX_ACCESS_DATA AuxData;
2673 PAGED_CODE();
2674
2675 /* Assume failure */
2676 *Handle = NULL;
2677
2678 /* Reference the object */
2679 Status = ObReferenceObjectByPointer(Object,
2680 0,
2681 ObjectType,
2682 AccessMode);
2683 if (!NT_SUCCESS(Status)) return Status;
2684
2685 /* Get the Header Info */
2686 Header = OBJECT_TO_OBJECT_HEADER(Object);
2687
2688 /* Check if we didn't get an access state */
2689 if (!PassedAccessState)
2690 {
2691 /* Use our built-in access state */
2692 PassedAccessState = &AccessState;
2693 Status = SeCreateAccessState(&AccessState,
2694 &AuxData,
2695 DesiredAccess,
2696 &Header->Type->TypeInfo.GenericMapping);
2697 if (!NT_SUCCESS(Status))
2698 {
2699 /* Fail */
2700 ObDereferenceObject(Object);
2701 return Status;
2702 }
2703 }
2704
2705 /* Check if we have invalid object attributes */
2706 if (Header->Type->TypeInfo.InvalidAttributes & HandleAttributes)
2707 {
2708 /* Delete the access state */
2709 if (PassedAccessState == &AccessState)
2710 {
2711 SeDeleteAccessState(PassedAccessState);
2712 }
2713
2714 /* Dereference the object */
2715 ObDereferenceObject(Object);
2716 return STATUS_INVALID_PARAMETER;
2717 }
2718
2719 /* Create the handle */
2720 Status = ObpCreateHandle(ObOpenHandle,
2721 Object,
2722 ObjectType,
2723 PassedAccessState,
2724 0,
2725 HandleAttributes,
2726 NULL,
2727 AccessMode,
2728 NULL,
2729 Handle);
2730 if (!NT_SUCCESS(Status)) ObDereferenceObject(Object);
2731
2732 /* Delete the access state */
2733 if (PassedAccessState == &AccessState)
2734 {
2735 SeDeleteAccessState(PassedAccessState);
2736 }
2737
2738 /* Return */
2739 OBTRACE(OB_HANDLE_DEBUG,
2740 "%s - returning Object with PC S: %lx %lx\n",
2741 __FUNCTION__,
2742 OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
2743 Status);
2744 return Status;
2745 }
2746
2747 /*++
2748 * @name ObFindHandleForObject
2749 * @implemented NT4
2750 *
2751 * The ObFindHandleForObject routine <FILLMEIN>
2752 *
2753 * @param Process
2754 * <FILLMEIN>.
2755 *
2756 * @param Object
2757 * <FILLMEIN>.
2758 *
2759 * @param ObjectType
2760 * <FILLMEIN>.
2761 *
2762 * @param HandleInformation
2763 * <FILLMEIN>.
2764 *
2765 * @param HandleReturn
2766 * <FILLMEIN>.
2767 *
2768 * @return <FILLMEIN>.
2769 *
2770 * @remarks None.
2771 *
2772 *--*/
2773 BOOLEAN
2774 NTAPI
2775 ObFindHandleForObject(IN PEPROCESS Process,
2776 IN PVOID Object,
2777 IN POBJECT_TYPE ObjectType,
2778 IN POBJECT_HANDLE_INFORMATION HandleInformation,
2779 OUT PHANDLE Handle)
2780 {
2781 OBP_FIND_HANDLE_DATA FindData;
2782 BOOLEAN Result = FALSE;
2783 PVOID ObjectTable;
2784
2785 /* Make sure we have an object table */
2786 ObjectTable = ObReferenceProcessHandleTable(Process);
2787 if (ObjectTable)
2788 {
2789 /* Check if we have an object */
2790 if (Object)
2791 {
2792 /* Set its header */
2793 FindData.ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2794 }
2795 else
2796 {
2797 /* Otherwise, no object to match*/
2798 FindData.ObjectHeader = NULL;
2799 }
2800
2801 /* Set other information */
2802 FindData.ObjectType = ObjectType;
2803 FindData.HandleInformation = HandleInformation;
2804
2805 /* Enumerate the handle table */
2806 if (ExEnumHandleTable(Process->ObjectTable,
2807 ObpEnumFindHandleProcedure,
2808 &FindData,
2809 Handle))
2810 {
2811 /* Set success */
2812 Result = TRUE;
2813 }
2814
2815 /* Let go of the table */
2816 ObDereferenceProcessHandleTable(Process);
2817 }
2818
2819 /* Return the result */
2820 return Result;
2821 }
2822
2823 /*++
2824 * @name ObInsertObject
2825 * @implemented NT4
2826 *
2827 * The ObInsertObject routine <FILLMEIN>
2828 *
2829 * @param Object
2830 * <FILLMEIN>.
2831 *
2832 * @param PassedAccessState
2833 * <FILLMEIN>.
2834 *
2835 * @param DesiredAccess
2836 * <FILLMEIN>.
2837 *
2838 * @param AdditionalReferences
2839 * <FILLMEIN>.
2840 *
2841 * @param ReferencedObject
2842 * <FILLMEIN>.
2843 *
2844 * @param Handle
2845 * <FILLMEIN>.
2846 *
2847 * @return <FILLMEIN>.
2848 *
2849 * @remarks None.
2850 *
2851 *--*/
2852 NTSTATUS
2853 NTAPI
2854 ObInsertObject(IN PVOID Object,
2855 IN PACCESS_STATE AccessState OPTIONAL,
2856 IN ACCESS_MASK DesiredAccess,
2857 IN ULONG ObjectPointerBias,
2858 OUT PVOID *NewObject OPTIONAL,
2859 OUT PHANDLE Handle)
2860 {
2861 POBJECT_CREATE_INFORMATION ObjectCreateInfo;
2862 POBJECT_HEADER ObjectHeader;
2863 POBJECT_TYPE ObjectType;
2864 PUNICODE_STRING ObjectName;
2865 PVOID InsertObject;
2866 PSECURITY_DESCRIPTOR ParentDescriptor = NULL;
2867 BOOLEAN SdAllocated = FALSE;
2868 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
2869 OBP_LOOKUP_CONTEXT Context;
2870 ACCESS_STATE LocalAccessState;
2871 AUX_ACCESS_DATA AuxData;
2872 OB_OPEN_REASON OpenReason;
2873 KPROCESSOR_MODE PreviousMode;
2874 NTSTATUS Status = STATUS_SUCCESS, RealStatus;
2875 BOOLEAN IsNewObject;
2876 PAGED_CODE();
2877
2878 /* Get the Header */
2879 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2880
2881 /* Detect invalid insert */
2882 if (!(ObjectHeader->Flags & OB_FLAG_CREATE_INFO))
2883 {
2884 /* Display warning and break into debugger */
2885 DPRINT1("OB: Attempting to insert existing object %p\n", Object);
2886 DbgBreakPoint();
2887
2888 /* Allow debugger to continue */
2889 ObDereferenceObject(Object);
2890 return STATUS_INVALID_PARAMETER;
2891 }
2892
2893 /* Get the create and name info, as well as the object type */
2894 ObjectCreateInfo = ObjectHeader->ObjectCreateInfo;
2895 ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
2896 ObjectType = ObjectHeader->Type;
2897 ObjectName = NULL;
2898
2899 /* Check if this is an named object */
2900 if ((ObjectNameInfo) && (ObjectNameInfo->Name.Buffer))
2901 {
2902 /* Get the object name */
2903 ObjectName = &ObjectNameInfo->Name;
2904 }
2905
2906 /* Sanity check */
2907 ASSERT((Handle) ||
2908 ((ObjectPointerBias == 0) &&
2909 (ObjectName == NULL) &&
2910 (ObjectType->TypeInfo.SecurityRequired) &&
2911 (NewObject == NULL)));
2912
2913 /* Check if the object is unnamed and also doesn't have security */
2914 PreviousMode = KeGetPreviousMode();
2915 if (!(ObjectType->TypeInfo.SecurityRequired) && !(ObjectName))
2916 {
2917 /* Assume failure */
2918 *Handle = NULL;
2919 ObjectHeader->ObjectCreateInfo = NULL;
2920
2921 /* Create the handle */
2922 Status = ObpCreateUnnamedHandle(Object,
2923 DesiredAccess,
2924 ObjectPointerBias + 1,
2925 ObjectCreateInfo->Attributes,
2926 PreviousMode,
2927 NewObject,
2928 Handle);
2929
2930 /* Free the create information */
2931 ObpFreeObjectCreateInformation(ObjectCreateInfo);
2932
2933 /* Release the object name information */
2934 ObpDereferenceNameInfo(ObjectNameInfo);
2935
2936 /* Remove the extra keep-alive reference */
2937 ObDereferenceObject(Object);
2938
2939 /* Return */
2940 OBTRACE(OB_HANDLE_DEBUG,
2941 "%s - returning Object with PC S: %lx %lx\n",
2942 __FUNCTION__,
2943 ObjectHeader->PointerCount,
2944 Status);
2945 return Status;
2946 }
2947
2948 /* Check if we didn't get an access state */
2949 if (!AccessState)
2950 {
2951 /* Use our built-in access state */
2952 AccessState = &LocalAccessState;
2953 Status = SeCreateAccessState(&LocalAccessState,
2954 &AuxData,
2955 DesiredAccess,
2956 &ObjectType->TypeInfo.GenericMapping);
2957 if (!NT_SUCCESS(Status))
2958 {
2959 /* Fail */
2960 ObpDereferenceNameInfo(ObjectNameInfo);
2961 ObDereferenceObject(Object);
2962 return Status;
2963 }
2964 }
2965
2966 /* Save the security descriptor */
2967 AccessState->SecurityDescriptor = ObjectCreateInfo->SecurityDescriptor;
2968
2969 /* Validate the access mask */
2970 Status = ObpValidateAccessMask(AccessState);
2971 if (!NT_SUCCESS(Status))
2972 {
2973 /* Fail */
2974 ObpDereferenceNameInfo(ObjectNameInfo);
2975 ObDereferenceObject(Object);
2976 return Status;
2977 }
2978
2979 /* Setup a lookup context */
2980 ObpInitializeLookupContext(&Context);
2981 InsertObject = Object;
2982 OpenReason = ObCreateHandle;
2983
2984 /* Check if the object is named */
2985 if (ObjectName)
2986 {
2987 /* Look it up */
2988 Status = ObpLookupObjectName(ObjectCreateInfo->RootDirectory,
2989 ObjectName,
2990 ObjectCreateInfo->Attributes,
2991 ObjectType,
2992 (ObjectHeader->Flags & OB_FLAG_KERNEL_MODE) ?
2993 KernelMode : UserMode,
2994 ObjectCreateInfo->ParseContext,
2995 ObjectCreateInfo->SecurityQos,
2996 Object,
2997 AccessState,
2998 &Context,
2999 &InsertObject);
3000
3001 /* Check if we found an object that doesn't match the one requested */
3002 if ((NT_SUCCESS(Status)) && (InsertObject) && (Object != InsertObject))
3003 {
3004 /* This means we're opening an object, not creating a new one */
3005 OpenReason = ObOpenHandle;
3006
3007 /* Make sure the caller said it's OK to do this */
3008 if (ObjectCreateInfo->Attributes & OBJ_OPENIF)
3009 {
3010 /* He did, but did he want this type? */
3011 if (ObjectType != OBJECT_TO_OBJECT_HEADER(InsertObject)->Type)
3012 {
3013 /* Wrong type, so fail */
3014 Status = STATUS_OBJECT_TYPE_MISMATCH;
3015 }
3016 else
3017 {
3018 /* Right type, so warn */
3019 Status = STATUS_OBJECT_NAME_EXISTS;
3020 }
3021 }
3022 else
3023 {
3024 /* Check if this was a symbolic link */
3025 if (OBJECT_TO_OBJECT_HEADER(InsertObject)->Type ==
3026 ObSymbolicLinkType)
3027 {
3028 /* Dereference it */
3029 ObDereferenceObject(InsertObject);
3030 }
3031
3032 /* Caller wanted to create a new object, fail */
3033 Status = STATUS_OBJECT_NAME_COLLISION;
3034 }
3035 }
3036
3037 /* Check if anything until now failed */
3038 if (!NT_SUCCESS(Status))
3039 {
3040 /* Cleanup after lookup */
3041 ObpReleaseLookupContext(&Context);
3042
3043 /* Remove query reference that we added */
3044 ObpDereferenceNameInfo(ObjectNameInfo);
3045
3046 /* Dereference the object and delete the access state */
3047 ObDereferenceObject(Object);
3048 if (AccessState == &LocalAccessState)
3049 {
3050 /* We used a local one; delete it */
3051 SeDeleteAccessState(AccessState);
3052 }
3053
3054 /* Return failure code */
3055 return Status;
3056 }
3057 else
3058 {
3059 /* Check if this is a symbolic link */
3060 if (ObjectType == ObSymbolicLinkType)
3061 {
3062 /* Create the internal name */
3063 ObpCreateSymbolicLinkName(Object);
3064 }
3065 }
3066 }
3067
3068 /* Now check if this object is being created */
3069 if (InsertObject == Object)
3070 {
3071 /* Check if it's named or forces security */
3072 if ((ObjectName) || (ObjectType->TypeInfo.SecurityRequired))
3073 {
3074 /* Make sure it's inserted into an object directory */
3075 if ((ObjectNameInfo) && (ObjectNameInfo->Directory))
3076 {
3077 /* Get the current descriptor */
3078 ObGetObjectSecurity(ObjectNameInfo->Directory,
3079 &ParentDescriptor,
3080 &SdAllocated);
3081 }
3082
3083 /* Now assign it */
3084 Status = ObAssignSecurity(AccessState,
3085 ParentDescriptor,
3086 Object,
3087 ObjectType);
3088
3089 /* Check if we captured one */
3090 if (ParentDescriptor)
3091 {
3092 /* We did, release it */
3093 ObReleaseObjectSecurity(ParentDescriptor, SdAllocated);
3094 }
3095 else if (NT_SUCCESS(Status))
3096 {
3097 /* Other we didn't, but we were able to use the current SD */
3098 SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor,
3099 ObjectCreateInfo->ProbeMode,
3100 TRUE);
3101
3102 /* Clear the current one */
3103 AccessState->SecurityDescriptor =
3104 ObjectCreateInfo->SecurityDescriptor = NULL;
3105 }
3106 }
3107
3108 /* Check if anything until now failed */
3109 if (!NT_SUCCESS(Status))
3110 {
3111 /* Check if the directory was added */
3112 if (Context.DirectoryLocked)
3113 {
3114 /* Weird case where we need to do a manual delete */
3115 DPRINT1("Unhandled path\n");
3116 ASSERT(FALSE);
3117 }
3118
3119 /* Cleanup the lookup */
3120 ObpReleaseLookupContext(&Context);
3121
3122 /* Remove query reference that we added */
3123 ObpDereferenceNameInfo(ObjectNameInfo);
3124
3125 /* Dereference the object and delete the access state */
3126 ObDereferenceObject(Object);
3127 if (AccessState == &LocalAccessState)
3128 {
3129 /* We used a local one; delete it */
3130 SeDeleteAccessState(AccessState);
3131 }
3132
3133 /* Return failure code */
3134 ASSERT(FALSE);
3135 return Status;
3136 }
3137 }
3138
3139 /* Save the actual status until here */
3140 RealStatus = Status;
3141
3142 /* Check if caller wants us to create a handle */
3143 ObjectHeader->ObjectCreateInfo = NULL;
3144 if (Handle)
3145 {
3146 /* Create the handle */
3147 Status = ObpCreateHandle(OpenReason,
3148 InsertObject,
3149 NULL,
3150 AccessState,
3151 ObjectPointerBias + 1,
3152 ObjectCreateInfo->Attributes,
3153 &Context,
3154 PreviousMode,
3155 NewObject,
3156 Handle);
3157 if (!NT_SUCCESS(Status))
3158 {
3159 /* If the object had a name, backout everything */
3160 if (ObjectName) ObpDeleteNameCheck(Object);
3161
3162 /* Return the status of the failure */
3163 *Handle = NULL;
3164 RealStatus = Status;
3165 }
3166
3167 /* Remove a query reference */
3168 ObpDereferenceNameInfo(ObjectNameInfo);
3169
3170 /* Remove the extra keep-alive reference */
3171 ObDereferenceObject(Object);
3172 }
3173 else
3174 {
3175 /* Otherwise, lock the object */
3176 ObpAcquireObjectLock(ObjectHeader);
3177
3178 /* And charge quota for the process to make it appear as used */
3179 RealStatus = ObpChargeQuotaForObject(ObjectHeader,
3180 ObjectType,
3181 &IsNewObject);
3182
3183 /* Release the lock */
3184 ObpReleaseObjectLock(ObjectHeader);
3185
3186 /* Check if we failed and dereference the object if so */
3187 if (!NT_SUCCESS(RealStatus)) ObDereferenceObject(Object);
3188 }
3189
3190 /* We can delete the Create Info now */
3191 ObpFreeObjectCreateInformation(ObjectCreateInfo);
3192
3193 /* Check if we created our own access state and delete it if so */
3194 if (AccessState == &LocalAccessState) SeDeleteAccessState(AccessState);
3195
3196 /* Return status code */
3197 OBTRACE(OB_HANDLE_DEBUG,
3198 "%s - returning Object with PC RS/S: %lx %lx %lx\n",
3199 __FUNCTION__,
3200 OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
3201 RealStatus, Status);
3202 return RealStatus;
3203 }
3204
3205 /*++
3206 * @name ObSetHandleAttributes
3207 * @implemented NT5.1
3208 *
3209 * The ObSetHandleAttributes routine <FILLMEIN>
3210 *
3211 * @param Handle
3212 * <FILLMEIN>.
3213 *
3214 * @param HandleFlags
3215 * <FILLMEIN>.
3216 *
3217 * @param PreviousMode
3218 * <FILLMEIN>.
3219 *
3220 * @return <FILLMEIN>.
3221 *
3222 * @remarks None.
3223 *
3224 *--*/
3225 NTSTATUS
3226 NTAPI
3227 ObSetHandleAttributes(IN HANDLE Handle,
3228 IN POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags,
3229 IN KPROCESSOR_MODE PreviousMode)
3230 {
3231 OBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleAttributesContext;
3232 BOOLEAN Result, AttachedToSystemProcess = FALSE;
3233 PHANDLE_TABLE HandleTable;
3234 KAPC_STATE ApcState;
3235 PAGED_CODE();
3236
3237 /* Check if this is a kernel handle */
3238 if (ObpIsKernelHandle(Handle, PreviousMode))
3239 {
3240 /* Use the kernel table and convert the handle */
3241 HandleTable = ObpKernelHandleTable;
3242 Handle = ObKernelHandleToHandle(Handle);
3243
3244 /* Check if we're not in the system process */
3245 if (PsGetCurrentProcess() != PsInitialSystemProcess)
3246 {
3247 /* Attach to the system process */
3248 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
3249 AttachedToSystemProcess = TRUE;
3250 }
3251 }
3252 else
3253 {
3254 /* Get the current process' handle table */
3255 HandleTable = PsGetCurrentProcess()->ObjectTable;
3256 }
3257
3258 /* Initialize the handle attribute context */
3259 SetHandleAttributesContext.PreviousMode = PreviousMode;
3260 SetHandleAttributesContext.Information = *HandleFlags;
3261
3262 /* Invoke the ObpSetHandleAttributes callback */
3263 Result = ExChangeHandle(HandleTable,
3264 Handle,
3265 ObpSetHandleAttributes,
3266 (ULONG_PTR)&SetHandleAttributesContext);
3267
3268 /* Did we attach to the system process? */
3269 if (AttachedToSystemProcess)
3270 {
3271 /* Detach from it */
3272 KeUnstackDetachProcess(&ApcState);
3273 }
3274
3275 /* Return the result as an NTSTATUS value */
3276 return Result ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
3277 }
3278
3279 /*++
3280 * @name ObCloseHandle
3281 * @implemented NT5.1
3282 *
3283 * The ObCloseHandle routine <FILLMEIN>
3284 *
3285 * @param Handle
3286 * <FILLMEIN>.
3287 *
3288 * @param AccessMode
3289 * <FILLMEIN>.
3290 *
3291 * @return <FILLMEIN>.
3292 *
3293 * @remarks None.
3294 *
3295 *--*/
3296 NTSTATUS
3297 NTAPI
3298 ObCloseHandle(IN HANDLE Handle,
3299 IN KPROCESSOR_MODE AccessMode)
3300 {
3301 /* Call the internal API */
3302 return ObpCloseHandle(Handle, AccessMode);
3303 }
3304
3305 /*++
3306 * @name NtClose
3307 * @implemented NT4
3308 *
3309 * The NtClose routine <FILLMEIN>
3310 *
3311 * @param Handle
3312 * <FILLMEIN>.
3313 *
3314 * @return <FILLMEIN>.
3315 *
3316 * @remarks None.
3317 *
3318 *--*/
3319 NTSTATUS
3320 NTAPI
3321 NtClose(IN HANDLE Handle)
3322 {
3323 /* Call the internal API */
3324 return ObpCloseHandle(Handle, ExGetPreviousMode());
3325 }
3326
3327 NTSTATUS
3328 NTAPI
3329 NtDuplicateObject(IN HANDLE SourceProcessHandle,
3330 IN HANDLE SourceHandle,
3331 IN HANDLE TargetProcessHandle OPTIONAL,
3332 OUT PHANDLE TargetHandle OPTIONAL,
3333 IN ACCESS_MASK DesiredAccess,
3334 IN ULONG HandleAttributes,
3335 IN ULONG Options)
3336 {
3337 PEPROCESS SourceProcess, TargetProcess, Target;
3338 HANDLE hTarget;
3339 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
3340 NTSTATUS Status;
3341 OBTRACE(OB_HANDLE_DEBUG,
3342 "%s - Duplicating handle: %p for %p into %p.\n",
3343 __FUNCTION__,
3344 SourceHandle,
3345 SourceProcessHandle,
3346 TargetProcessHandle);
3347
3348 /* Check if we have a target handle */
3349 if ((TargetHandle) && (PreviousMode != KernelMode))
3350 {
3351 /* Enter SEH */
3352 _SEH2_TRY
3353 {
3354 /* Probe the handle and assume failure */
3355 ProbeForWriteHandle(TargetHandle);
3356 *TargetHandle = NULL;
3357 }
3358 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3359 {
3360 /* Return the exception code */
3361 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3362 }
3363 _SEH2_END;
3364 }
3365
3366 /* Now reference the input handle */
3367 Status = ObReferenceObjectByHandle(SourceProcessHandle,
3368 PROCESS_DUP_HANDLE,
3369 PsProcessType,
3370 PreviousMode,
3371 (PVOID*)&SourceProcess,
3372 NULL);
3373 if (!NT_SUCCESS(Status)) return Status;
3374
3375 /* Check if got a target handle */
3376 if (TargetProcessHandle)
3377 {
3378 /* Now reference the output handle */
3379 Status = ObReferenceObjectByHandle(TargetProcessHandle,
3380 PROCESS_DUP_HANDLE,
3381 PsProcessType,
3382 PreviousMode,
3383 (PVOID*)&TargetProcess,
3384 NULL);
3385 if (NT_SUCCESS(Status))
3386 {
3387 /* Use this target process */
3388 Target = TargetProcess;
3389 }
3390 else
3391 {
3392 /* No target process */
3393 Target = NULL;
3394 }
3395 }
3396 else
3397 {
3398 /* No target process */
3399 Status = STATUS_SUCCESS;
3400 Target = NULL;
3401 }
3402
3403 /* Call the internal routine */
3404 Status = ObDuplicateObject(SourceProcess,
3405 SourceHandle,
3406 Target,
3407 &hTarget,
3408 DesiredAccess,
3409 HandleAttributes,
3410 Options,
3411 PreviousMode);
3412
3413 /* Check if the caller wanted the return handle */
3414 if (TargetHandle)
3415 {
3416 /* Protect the write to user mode */
3417 _SEH2_TRY
3418 {
3419 /* Write the new handle */
3420 *TargetHandle = hTarget;
3421 }
3422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3423 {
3424 /* Otherwise, get the exception code */
3425 Status = _SEH2_GetExceptionCode();
3426 }
3427 _SEH2_END;
3428 }
3429
3430 /* Dereference the processes */
3431 OBTRACE(OB_HANDLE_DEBUG,
3432 "%s - Duplicated handle: %p into %p S %lx\n",
3433 __FUNCTION__,
3434 hTarget,
3435 TargetProcessHandle,
3436 Status);
3437 if (Target) ObDereferenceObject(Target);
3438 ObDereferenceObject(SourceProcess);
3439 return Status;
3440 }
3441
3442 BOOLEAN
3443 NTAPI
3444 ObIsKernelHandle(IN HANDLE Handle)
3445 {
3446 /* Use the inlined version. We know we are in kernel mode. */
3447 return ObpIsKernelHandle(Handle, KernelMode);
3448 }
3449
3450 /* EOF */