* Sync with recent trunk (r52637).
[reactos.git] / 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: %lx 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: %lx for %p. HC PC %lx %lx\n",
757 __FUNCTION__,
758 Handle,
759 Body,
760 ObjectHeader->HandleCount,
761 ObjectHeader->PointerCount);
762 return STATUS_SUCCESS;
763 }
764
765 /*++
766 * @name ObpIncrementHandleCount
767 *
768 * The ObpIncrementHandleCount routine <FILLMEIN>
769 *
770 * @param Object
771 * <FILLMEIN>.
772 *
773 * @param AccessState
774 * <FILLMEIN>.
775 *
776 * @param AccessMode
777 * <FILLMEIN>.
778 *
779 * @param HandleAttributes
780 * <FILLMEIN>.
781 *
782 * @param Process
783 * <FILLMEIN>.
784 *
785 * @param OpenReason
786 * <FILLMEIN>.
787 *
788 * @return <FILLMEIN>.
789 *
790 * @remarks None.
791 *
792 *--*/
793 NTSTATUS
794 NTAPI
795 ObpIncrementHandleCount(IN PVOID Object,
796 IN PACCESS_STATE AccessState OPTIONAL,
797 IN KPROCESSOR_MODE AccessMode,
798 IN ULONG HandleAttributes,
799 IN PEPROCESS Process,
800 IN OB_OPEN_REASON OpenReason)
801 {
802 POBJECT_HEADER ObjectHeader;
803 POBJECT_TYPE ObjectType;
804 ULONG ProcessHandleCount;
805 NTSTATUS Status;
806 PEPROCESS ExclusiveProcess;
807 BOOLEAN Exclusive = FALSE, NewObject;
808 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
809 KIRQL CalloutIrql;
810 KPROCESSOR_MODE ProbeMode;
811 ULONG Total;
812 PAGED_CODE();
813
814 /* Get the object header and type */
815 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
816 ObjectType = ObjectHeader->Type;
817 OBTRACE(OB_HANDLE_DEBUG,
818 "%s - Incrementing count for: %p. Reason: %lx. HC PC %lx %lx\n",
819 __FUNCTION__,
820 Object,
821 OpenReason,
822 ObjectHeader->HandleCount,
823 ObjectHeader->PointerCount);
824
825 /* Check if caller is forcing user mode */
826 if (HandleAttributes & OBJ_FORCE_ACCESS_CHECK)
827 {
828 /* Force it */
829 ProbeMode = UserMode;
830 }
831 else
832 {
833 /* Keep original setting */
834 ProbeMode = AccessMode;
835 }
836
837 /* Lock the object */
838 ObpAcquireObjectLock(ObjectHeader);
839
840 /* Charge quota and remove the creator info flag */
841 Status = ObpChargeQuotaForObject(ObjectHeader, ObjectType, &NewObject);
842 if (!NT_SUCCESS(Status)) return Status;
843
844 /* Check if the open is exclusive */
845 if (HandleAttributes & OBJ_EXCLUSIVE)
846 {
847 /* Check if the object allows this, or if the inherit flag was given */
848 if ((HandleAttributes & OBJ_INHERIT) ||
849 !(ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
850 {
851 /* Incorrect attempt */
852 Status = STATUS_INVALID_PARAMETER;
853 goto Quickie;
854 }
855
856 /* Check if we have access to it */
857 ExclusiveProcess = OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader);
858 if ((!(ExclusiveProcess) && (ObjectHeader->HandleCount)) ||
859 ((ExclusiveProcess) && (ExclusiveProcess != PsGetCurrentProcess())))
860 {
861 /* This isn't the right process */
862 Status = STATUS_ACCESS_DENIED;
863 goto Quickie;
864 }
865
866 /* Now you got exclusive access */
867 Exclusive = TRUE;
868 }
869 else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) &&
870 (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader)))
871 {
872 /* Caller didn't want exclusive access, but the object is exclusive */
873 Status = STATUS_ACCESS_DENIED;
874 goto Quickie;
875 }
876
877 /*
878 * Check if this is an object that went from 0 handles back to existence,
879 * but doesn't have an open procedure, only a close procedure. This means
880 * that it will never realize that the object is back alive, so we must
881 * fail the request.
882 */
883 if (!(ObjectHeader->HandleCount) &&
884 !(NewObject) &&
885 (ObjectType->TypeInfo.MaintainHandleCount) &&
886 !(ObjectType->TypeInfo.OpenProcedure) &&
887 (ObjectType->TypeInfo.CloseProcedure))
888 {
889 /* Fail */
890 Status = STATUS_UNSUCCESSFUL;
891 goto Quickie;
892 }
893
894 /* Check if we're opening an existing handle */
895 if ((OpenReason == ObOpenHandle) ||
896 ((OpenReason == ObDuplicateHandle) && (AccessState)))
897 {
898 /* Validate the caller's access to this object */
899 if (!ObCheckObjectAccess(Object,
900 AccessState,
901 TRUE,
902 ProbeMode,
903 &Status))
904 {
905 /* Access was denied, so fail */
906 goto Quickie;
907 }
908 }
909 else if (OpenReason == ObCreateHandle)
910 {
911 /* Convert MAXIMUM_ALLOWED to GENERIC_ALL */
912 if (AccessState->RemainingDesiredAccess & MAXIMUM_ALLOWED)
913 {
914 /* Mask out MAXIMUM_ALLOWED and stick GENERIC_ALL instead */
915 AccessState->RemainingDesiredAccess &= ~MAXIMUM_ALLOWED;
916 AccessState->RemainingDesiredAccess |= GENERIC_ALL;
917 }
918
919 /* Check if we have to map the GENERIC mask */
920 if (AccessState->RemainingDesiredAccess & GENERIC_ACCESS)
921 {
922 /* Map it to the correct access masks */
923 RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
924 &ObjectType->TypeInfo.GenericMapping);
925 }
926
927 /* Check if the caller is trying to access system security */
928 if (AccessState->RemainingDesiredAccess & ACCESS_SYSTEM_SECURITY)
929 {
930 /* FIXME: TODO */
931 DPRINT1("ACCESS_SYSTEM_SECURITY not validated!\n");
932 }
933 }
934
935 /* Check if this is an exclusive handle */
936 if (Exclusive)
937 {
938 /* Save the owner process */
939 OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
940 }
941
942 /* Increase the handle count */
943 InterlockedIncrement(&ObjectHeader->HandleCount);
944 ProcessHandleCount = 0;
945
946 /* Check if we have a handle database */
947 if (ObjectType->TypeInfo.MaintainHandleCount)
948 {
949 /* Increment the handle database */
950 Status = ObpIncrementHandleDataBase(ObjectHeader,
951 Process,
952 &ProcessHandleCount);
953 if (!NT_SUCCESS(Status))
954 {
955 /* FIXME: This should never happen for now */
956 DPRINT1("Unhandled case\n");
957 ASSERT(FALSE);
958 goto Quickie;
959 }
960 }
961
962 /* Release the lock */
963 ObpReleaseObjectLock(ObjectHeader);
964
965 /* Check if we have an open procedure */
966 Status = STATUS_SUCCESS;
967 if (ObjectType->TypeInfo.OpenProcedure)
968 {
969 /* Call it */
970 ObpCalloutStart(&CalloutIrql);
971 Status = ObjectType->TypeInfo.OpenProcedure(OpenReason,
972 Process,
973 Object,
974 AccessState ?
975 AccessState->
976 PreviouslyGrantedAccess :
977 0,
978 ProcessHandleCount);
979 ObpCalloutEnd(CalloutIrql, "Open", ObjectType, Object);
980
981 /* Check if the open procedure failed */
982 if (!NT_SUCCESS(Status))
983 {
984 /* FIXME: This should never happen for now */
985 DPRINT1("Unhandled case\n");
986 ASSERT(FALSE);
987 return Status;
988 }
989 }
990
991 /* Check if this is a create operation */
992 if (OpenReason == ObCreateHandle)
993 {
994 /* Check if we have creator info */
995 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(ObjectHeader);
996 if (CreatorInfo)
997 {
998 /* We do, acquire the lock */
999 ObpEnterObjectTypeMutex(ObjectType);
1000
1001 /* Insert us on the list */
1002 InsertTailList(&ObjectType->TypeList, &CreatorInfo->TypeList);
1003
1004 /* Release the lock */
1005 ObpLeaveObjectTypeMutex(ObjectType);
1006 }
1007 }
1008
1009 /* Increase total number of handles */
1010 Total = InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfHandles);
1011 if (Total > ObjectType->HighWaterNumberOfHandles)
1012 {
1013 /* Fixup count */
1014 ObjectType->HighWaterNumberOfHandles = Total;
1015 }
1016
1017 /* Trace call and return */
1018 OBTRACE(OB_HANDLE_DEBUG,
1019 "%s - Incremented count for: %p. Reason: %lx HC PC %lx %lx\n",
1020 __FUNCTION__,
1021 Object,
1022 OpenReason,
1023 ObjectHeader->HandleCount,
1024 ObjectHeader->PointerCount);
1025 return Status;
1026
1027 Quickie:
1028 /* Release lock and return */
1029 ObpReleaseObjectLock(ObjectHeader);
1030 return Status;
1031 }
1032
1033 /*++
1034 * @name ObpIncrementUnnamedHandleCount
1035 *
1036 * The ObpIncrementUnnamedHandleCount routine <FILLMEIN>
1037 *
1038 * @param Object
1039 * <FILLMEIN>.
1040 *
1041 * @param AccessState
1042 * <FILLMEIN>.
1043 *
1044 * @param AccessMode
1045 * <FILLMEIN>.
1046 *
1047 * @param HandleAttributes
1048 * <FILLMEIN>.
1049 *
1050 * @param Process
1051 * <FILLMEIN>.
1052 *
1053 * @param OpenReason
1054 * <FILLMEIN>.
1055 *
1056 * @return <FILLMEIN>.
1057 *
1058 * @remarks None.
1059 *
1060 *--*/
1061 NTSTATUS
1062 NTAPI
1063 ObpIncrementUnnamedHandleCount(IN PVOID Object,
1064 IN PACCESS_MASK DesiredAccess,
1065 IN KPROCESSOR_MODE AccessMode,
1066 IN ULONG HandleAttributes,
1067 IN PEPROCESS Process)
1068 {
1069 POBJECT_HEADER ObjectHeader;
1070 POBJECT_TYPE ObjectType;
1071 ULONG ProcessHandleCount;
1072 NTSTATUS Status;
1073 PEPROCESS ExclusiveProcess;
1074 BOOLEAN Exclusive = FALSE, NewObject;
1075 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
1076 KIRQL CalloutIrql;
1077 ULONG Total;
1078
1079 /* Get the object header and type */
1080 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1081 ObjectType = ObjectHeader->Type;
1082 OBTRACE(OB_HANDLE_DEBUG,
1083 "%s - Incrementing count for: %p. UNNAMED. HC PC %lx %lx\n",
1084 __FUNCTION__,
1085 Object,
1086 ObjectHeader->HandleCount,
1087 ObjectHeader->PointerCount);
1088
1089 /* Lock the object */
1090 ObpAcquireObjectLock(ObjectHeader);
1091
1092 /* Charge quota and remove the creator info flag */
1093 Status = ObpChargeQuotaForObject(ObjectHeader, ObjectType, &NewObject);
1094 if (!NT_SUCCESS(Status)) return Status;
1095
1096 /* Check if the open is exclusive */
1097 if (HandleAttributes & OBJ_EXCLUSIVE)
1098 {
1099 /* Check if the object allows this, or if the inherit flag was given */
1100 if ((HandleAttributes & OBJ_INHERIT) ||
1101 !(ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
1102 {
1103 /* Incorrect attempt */
1104 Status = STATUS_INVALID_PARAMETER;
1105 goto Quickie;
1106 }
1107
1108 /* Check if we have access to it */
1109 ExclusiveProcess = OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader);
1110 if ((!(ExclusiveProcess) && (ObjectHeader->HandleCount)) ||
1111 ((ExclusiveProcess) && (ExclusiveProcess != PsGetCurrentProcess())))
1112 {
1113 /* This isn't the right process */
1114 Status = STATUS_ACCESS_DENIED;
1115 goto Quickie;
1116 }
1117
1118 /* Now you got exclusive access */
1119 Exclusive = TRUE;
1120 }
1121 else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) &&
1122 (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader)))
1123 {
1124 /* Caller didn't want exclusive access, but the object is exclusive */
1125 Status = STATUS_ACCESS_DENIED;
1126 goto Quickie;
1127 }
1128
1129 /*
1130 * Check if this is an object that went from 0 handles back to existence,
1131 * but doesn't have an open procedure, only a close procedure. This means
1132 * that it will never realize that the object is back alive, so we must
1133 * fail the request.
1134 */
1135 if (!(ObjectHeader->HandleCount) &&
1136 !(NewObject) &&
1137 (ObjectType->TypeInfo.MaintainHandleCount) &&
1138 !(ObjectType->TypeInfo.OpenProcedure) &&
1139 (ObjectType->TypeInfo.CloseProcedure))
1140 {
1141 /* Fail */
1142 Status = STATUS_UNSUCCESSFUL;
1143 goto Quickie;
1144 }
1145
1146 /* Convert MAXIMUM_ALLOWED to GENERIC_ALL */
1147 if (*DesiredAccess & MAXIMUM_ALLOWED)
1148 {
1149 /* Mask out MAXIMUM_ALLOWED and stick GENERIC_ALL instead */
1150 *DesiredAccess &= ~MAXIMUM_ALLOWED;
1151 *DesiredAccess |= GENERIC_ALL;
1152 }
1153
1154 /* Check if we have to map the GENERIC mask */
1155 if (*DesiredAccess & GENERIC_ACCESS)
1156 {
1157 /* Map it to the correct access masks */
1158 RtlMapGenericMask(DesiredAccess,
1159 &ObjectType->TypeInfo.GenericMapping);
1160 }
1161
1162 /* Check if this is an exclusive handle */
1163 if (Exclusive)
1164 {
1165 /* Save the owner process */
1166 OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
1167 }
1168
1169 /* Increase the handle count */
1170 InterlockedIncrement(&ObjectHeader->HandleCount);
1171 ProcessHandleCount = 0;
1172
1173 /* Check if we have a handle database */
1174 if (ObjectType->TypeInfo.MaintainHandleCount)
1175 {
1176 /* Increment the handle database */
1177 Status = ObpIncrementHandleDataBase(ObjectHeader,
1178 Process,
1179 &ProcessHandleCount);
1180 if (!NT_SUCCESS(Status))
1181 {
1182 /* FIXME: This should never happen for now */
1183 DPRINT1("Unhandled case\n");
1184 ASSERT(FALSE);
1185 goto Quickie;
1186 }
1187 }
1188
1189 /* Release the lock */
1190 ObpReleaseObjectLock(ObjectHeader);
1191
1192 /* Check if we have an open procedure */
1193 Status = STATUS_SUCCESS;
1194 if (ObjectType->TypeInfo.OpenProcedure)
1195 {
1196 /* Call it */
1197 ObpCalloutStart(&CalloutIrql);
1198 Status = ObjectType->TypeInfo.OpenProcedure(ObCreateHandle,
1199 Process,
1200 Object,
1201 *DesiredAccess,
1202 ProcessHandleCount);
1203 ObpCalloutEnd(CalloutIrql, "Open", ObjectType, Object);
1204
1205 /* Check if the open procedure failed */
1206 if (!NT_SUCCESS(Status))
1207 {
1208 /* FIXME: This should never happen for now */
1209 DPRINT1("Unhandled case\n");
1210 ASSERT(FALSE);
1211 return Status;
1212 }
1213 }
1214
1215 /* Check if we have creator info */
1216 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(ObjectHeader);
1217 if (CreatorInfo)
1218 {
1219 /* We do, acquire the lock */
1220 ObpEnterObjectTypeMutex(ObjectType);
1221
1222 /* Insert us on the list */
1223 InsertTailList(&ObjectType->TypeList, &CreatorInfo->TypeList);
1224
1225 /* Release the lock */
1226 ObpLeaveObjectTypeMutex(ObjectType);
1227 }
1228
1229 /* Increase total number of handles */
1230 Total = InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfHandles);
1231 if (Total > ObjectType->HighWaterNumberOfHandles)
1232 {
1233 /* Fixup count */
1234 ObjectType->HighWaterNumberOfHandles = Total;
1235 }
1236
1237 /* Trace call and return */
1238 OBTRACE(OB_HANDLE_DEBUG,
1239 "%s - Incremented count for: %p. UNNAMED HC PC %lx %lx\n",
1240 __FUNCTION__,
1241 Object,
1242 ObjectHeader->HandleCount,
1243 ObjectHeader->PointerCount);
1244 return Status;
1245
1246 Quickie:
1247 /* Release lock and return */
1248 ObpReleaseObjectLock(ObjectHeader);
1249 return Status;
1250 }
1251
1252 /*++
1253 * @name ObpCreateUnnamedHandle
1254 *
1255 * The ObpCreateUnnamedHandle routine <FILLMEIN>
1256 *
1257 * @param Object
1258 * <FILLMEIN>.
1259 *
1260 * @param DesiredAccess
1261 * <FILLMEIN>.
1262 *
1263 * @param AdditionalReferences
1264 * <FILLMEIN>.
1265 *
1266 * @param HandleAttributes
1267 * <FILLMEIN>.
1268 *
1269 * @param AccessMode
1270 * <FILLMEIN>.
1271 *
1272 * @param ReturnedObject
1273 * <FILLMEIN>.
1274 *
1275 * @param ReturnedHandle
1276 * <FILLMEIN>.
1277 *
1278 * @return <FILLMEIN>.
1279 *
1280 * @remarks None.
1281 *
1282 *--*/
1283 NTSTATUS
1284 NTAPI
1285 ObpCreateUnnamedHandle(IN PVOID Object,
1286 IN ACCESS_MASK DesiredAccess,
1287 IN ULONG AdditionalReferences,
1288 IN ULONG HandleAttributes,
1289 IN KPROCESSOR_MODE AccessMode,
1290 OUT PVOID *ReturnedObject,
1291 OUT PHANDLE ReturnedHandle)
1292 {
1293 HANDLE_TABLE_ENTRY NewEntry;
1294 POBJECT_HEADER ObjectHeader;
1295 HANDLE Handle;
1296 KAPC_STATE ApcState;
1297 BOOLEAN AttachedToProcess = FALSE, KernelHandle = FALSE;
1298 PVOID HandleTable;
1299 NTSTATUS Status;
1300 ACCESS_MASK GrantedAccess;
1301 POBJECT_TYPE ObjectType;
1302 PAGED_CODE();
1303
1304 /* Get the object header and type */
1305 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1306 ObjectType = ObjectHeader->Type;
1307 OBTRACE(OB_HANDLE_DEBUG,
1308 "%s - Creating handle for: %p. UNNAMED. HC PC %lx %lx\n",
1309 __FUNCTION__,
1310 Object,
1311 ObjectHeader->HandleCount,
1312 ObjectHeader->PointerCount);
1313
1314 /* Save the object header */
1315 NewEntry.Object = ObjectHeader;
1316
1317 /* Mask out the internal attributes */
1318 NewEntry.ObAttributes |= HandleAttributes & OBJ_HANDLE_ATTRIBUTES;
1319
1320 /* Check if this is a kernel handle */
1321 if (HandleAttributes & OBJ_KERNEL_HANDLE)
1322 {
1323 /* Set the handle table */
1324 HandleTable = ObpKernelHandleTable;
1325 KernelHandle = TRUE;
1326
1327 /* Check if we're not in the system process */
1328 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1329 {
1330 /* Attach to the system process */
1331 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1332 AttachedToProcess = TRUE;
1333 }
1334 }
1335 else
1336 {
1337 /* Get the current handle table */
1338 HandleTable = PsGetCurrentProcess()->ObjectTable;
1339 }
1340
1341 /* Increment the handle count */
1342 Status = ObpIncrementUnnamedHandleCount(Object,
1343 &DesiredAccess,
1344 AccessMode,
1345 HandleAttributes,
1346 PsGetCurrentProcess());
1347 if (!NT_SUCCESS(Status))
1348 {
1349 /*
1350 * We failed (meaning security failure, according to NT Internals)
1351 * detach and return
1352 */
1353 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1354 return Status;
1355 }
1356
1357 /* Remove what's not in the valid access mask */
1358 GrantedAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
1359 ACCESS_SYSTEM_SECURITY);
1360
1361 /* Handle extra references */
1362 if (AdditionalReferences)
1363 {
1364 /* Add them to the header */
1365 InterlockedExchangeAdd(&ObjectHeader->PointerCount,
1366 AdditionalReferences);
1367 }
1368
1369 /* Save the access mask */
1370 NewEntry.GrantedAccess = GrantedAccess;
1371
1372 /*
1373 * Create the actual handle. We'll need to do this *after* calling
1374 * ObpIncrementHandleCount to make sure that Object Security is valid
1375 * (specified in Gl00my documentation on Ob)
1376 */
1377 OBTRACE(OB_HANDLE_DEBUG,
1378 "%s - Handle Properties: [%p-%lx-%lx]\n",
1379 __FUNCTION__,
1380 NewEntry.Object, NewEntry.ObAttributes & 3, NewEntry.GrantedAccess);
1381 Handle = ExCreateHandle(HandleTable, &NewEntry);
1382
1383 /* Make sure we got a handle */
1384 if (Handle)
1385 {
1386 /* Check if this was a kernel handle */
1387 if (KernelHandle) Handle = ObMarkHandleAsKernelHandle(Handle);
1388
1389 /* Return handle and object */
1390 *ReturnedHandle = Handle;
1391
1392 /* Return the new object only if caller wanted it biased */
1393 if ((AdditionalReferences) && (ReturnedObject))
1394 {
1395 /* Return it */
1396 *ReturnedObject = Object;
1397 }
1398
1399 /* Detach if needed */
1400 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1401
1402 /* Trace and return */
1403 OBTRACE(OB_HANDLE_DEBUG,
1404 "%s - Returning Handle: %lx HC PC %lx %lx\n",
1405 __FUNCTION__,
1406 Handle,
1407 ObjectHeader->HandleCount,
1408 ObjectHeader->PointerCount);
1409 return STATUS_SUCCESS;
1410 }
1411
1412 /* Handle extra references */
1413 if (AdditionalReferences)
1414 {
1415 /* Dereference it as many times as required */
1416 InterlockedExchangeAdd(&ObjectHeader->PointerCount,
1417 -(LONG)AdditionalReferences);
1418 }
1419
1420 /* Decrement the handle count and detach */
1421 ObpDecrementHandleCount(&ObjectHeader->Body,
1422 PsGetCurrentProcess(),
1423 GrantedAccess,
1424 ObjectType);
1425
1426 /* Detach and fail */
1427 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1428 return STATUS_INSUFFICIENT_RESOURCES;
1429 }
1430
1431 /*++
1432 * @name ObpCreateHandle
1433 *
1434 * The ObpCreateHandle routine <FILLMEIN>
1435 *
1436 * @param OpenReason
1437 * <FILLMEIN>.
1438 *
1439 * @param Object
1440 * <FILLMEIN>.
1441 *
1442 * @param Type
1443 * <FILLMEIN>.
1444 *
1445 * @param AccessState
1446 * <FILLMEIN>.
1447 *
1448 * @param AdditionalReferences
1449 * <FILLMEIN>.
1450 *
1451 * @param HandleAttributes
1452 * <FILLMEIN>.
1453 *
1454 * @param AccessMode
1455 * <FILLMEIN>.
1456 *
1457 * @param ReturnedObject
1458 * <FILLMEIN>.
1459 *
1460 * @param ReturnedHandle
1461 * <FILLMEIN>.
1462 *
1463 * @return <FILLMEIN>.
1464 *
1465 * @remarks Cleans up the Lookup Context on return.
1466 *
1467 *--*/
1468 NTSTATUS
1469 NTAPI
1470 ObpCreateHandle(IN OB_OPEN_REASON OpenReason,
1471 IN PVOID Object,
1472 IN POBJECT_TYPE Type OPTIONAL,
1473 IN PACCESS_STATE AccessState,
1474 IN ULONG AdditionalReferences,
1475 IN ULONG HandleAttributes,
1476 IN POBP_LOOKUP_CONTEXT Context,
1477 IN KPROCESSOR_MODE AccessMode,
1478 OUT PVOID *ReturnedObject,
1479 OUT PHANDLE ReturnedHandle)
1480 {
1481 HANDLE_TABLE_ENTRY NewEntry;
1482 POBJECT_HEADER ObjectHeader;
1483 HANDLE Handle;
1484 KAPC_STATE ApcState;
1485 BOOLEAN AttachedToProcess = FALSE, KernelHandle = FALSE;
1486 POBJECT_TYPE ObjectType;
1487 PVOID HandleTable;
1488 NTSTATUS Status;
1489 ACCESS_MASK DesiredAccess, GrantedAccess;
1490 PAUX_ACCESS_DATA AuxData;
1491 PAGED_CODE();
1492
1493 /* Get the object header and type */
1494 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1495 ObjectType = ObjectHeader->Type;
1496 OBTRACE(OB_HANDLE_DEBUG,
1497 "%s - Creating handle for: %p. Reason: %lx. HC PC %lx %lx\n",
1498 __FUNCTION__,
1499 Object,
1500 OpenReason,
1501 ObjectHeader->HandleCount,
1502 ObjectHeader->PointerCount);
1503
1504 /* Check if the types match */
1505 if ((Type) && (ObjectType != Type))
1506 {
1507 /* They don't, cleanup */
1508 if (Context) ObpReleaseLookupContext(Context);
1509 return STATUS_OBJECT_TYPE_MISMATCH;
1510 }
1511
1512 /* Save the object header */
1513 NewEntry.Object = ObjectHeader;
1514
1515 /* Check if this is a kernel handle */
1516 if (HandleAttributes & OBJ_KERNEL_HANDLE)
1517 {
1518 /* Set the handle table */
1519 HandleTable = ObpKernelHandleTable;
1520 KernelHandle = TRUE;
1521
1522 /* Check if we're not in the system process */
1523 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1524 {
1525 /* Attach to the system process */
1526 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1527 AttachedToProcess = TRUE;
1528 }
1529 }
1530 else
1531 {
1532 /* Get the current handle table */
1533 HandleTable = PsGetCurrentProcess()->ObjectTable;
1534 }
1535
1536 /* Increment the handle count */
1537 Status = ObpIncrementHandleCount(Object,
1538 AccessState,
1539 AccessMode,
1540 HandleAttributes,
1541 PsGetCurrentProcess(),
1542 OpenReason);
1543 if (!NT_SUCCESS(Status))
1544 {
1545 /*
1546 * We failed (meaning security failure, according to NT Internals)
1547 * detach and return
1548 */
1549 if (Context) ObpReleaseLookupContext(Context);
1550 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1551 return Status;
1552 }
1553
1554 /* Check if we are doing audits on close */
1555 if (AccessState->GenerateOnClose)
1556 {
1557 /* Force the attribute on */
1558 HandleAttributes |= OBJ_AUDIT_OBJECT_CLOSE;
1559 }
1560
1561 /* Mask out the internal attributes */
1562 NewEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
1563
1564 /* Get the original desired access */
1565 DesiredAccess = AccessState->RemainingDesiredAccess |
1566 AccessState->PreviouslyGrantedAccess;
1567
1568 /* Remove what's not in the valid access mask */
1569 GrantedAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
1570 ACCESS_SYSTEM_SECURITY);
1571
1572 /* Update the value in the access state */
1573 AccessState->PreviouslyGrantedAccess = GrantedAccess;
1574
1575 /* Get the auxiliary data */
1576 AuxData = AccessState->AuxData;
1577
1578 /* Handle extra references */
1579 if (AdditionalReferences)
1580 {
1581 /* Add them to the header */
1582 InterlockedExchangeAdd(&ObjectHeader->PointerCount, AdditionalReferences);
1583 }
1584
1585 /* Now we can release the object */
1586 if (Context) ObpReleaseLookupContext(Context);
1587
1588 /* Save the access mask */
1589 NewEntry.GrantedAccess = GrantedAccess;
1590
1591 /*
1592 * Create the actual handle. We'll need to do this *after* calling
1593 * ObpIncrementHandleCount to make sure that Object Security is valid
1594 * (specified in Gl00my documentation on Ob)
1595 */
1596 OBTRACE(OB_HANDLE_DEBUG,
1597 "%s - Handle Properties: [%p-%lx-%lx]\n",
1598 __FUNCTION__,
1599 NewEntry.Object, NewEntry.ObAttributes & 3, NewEntry.GrantedAccess);
1600 Handle = ExCreateHandle(HandleTable, &NewEntry);
1601
1602 /* Make sure we got a handle */
1603 if (Handle)
1604 {
1605 /* Check if this was a kernel handle */
1606 if (KernelHandle) Handle = ObMarkHandleAsKernelHandle(Handle);
1607
1608 /* Return it */
1609 *ReturnedHandle = Handle;
1610
1611 /* Check if we need to generate on audit */
1612 if (AccessState->GenerateAudit)
1613 {
1614 /* Audit the handle creation */
1615 //SeAuditHandleCreation(AccessState, Handle);
1616 }
1617
1618 /* Check if this was a create */
1619 if (OpenReason == ObCreateHandle)
1620 {
1621 /* Check if we need to audit the privileges */
1622 if ((AuxData->PrivilegeSet) &&
1623 (AuxData->PrivilegeSet->PrivilegeCount))
1624 {
1625 /* Do the audit */
1626 #if 0
1627 SePrivilegeObjectAuditAlarm(Handle,
1628 &AccessState->
1629 SubjectSecurityContext,
1630 GrantedAccess,
1631 AuxData->PrivilegeSet,
1632 TRUE,
1633 ExGetPreviousMode());
1634 #endif
1635 }
1636 }
1637
1638 /* Return the new object only if caller wanted it biased */
1639 if ((AdditionalReferences) && (ReturnedObject))
1640 {
1641 /* Return it */
1642 *ReturnedObject = Object;
1643 }
1644
1645 /* Detach if needed */
1646 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1647
1648 /* Trace and return */
1649 OBTRACE(OB_HANDLE_DEBUG,
1650 "%s - Returning Handle: %lx HC PC %lx %lx\n",
1651 __FUNCTION__,
1652 Handle,
1653 ObjectHeader->HandleCount,
1654 ObjectHeader->PointerCount);
1655 return STATUS_SUCCESS;
1656 }
1657
1658 /* Decrement the handle count and detach */
1659 ObpDecrementHandleCount(&ObjectHeader->Body,
1660 PsGetCurrentProcess(),
1661 GrantedAccess,
1662 ObjectType);
1663
1664 /* Handle extra references */
1665 if (AdditionalReferences)
1666 {
1667 /* Check how many extra references were added */
1668 if (AdditionalReferences > 1)
1669 {
1670 /* Dereference it many times */
1671 InterlockedExchangeAdd(&ObjectHeader->PointerCount,
1672 -(LONG)(AdditionalReferences - 1));
1673 }
1674
1675 /* Dereference the object one last time */
1676 ObDereferenceObject(Object);
1677 }
1678
1679 /* Detach if necessary and fail */
1680 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1681 return STATUS_INSUFFICIENT_RESOURCES;
1682 }
1683
1684 /*++
1685 * @name ObpCloseHandle
1686 *
1687 * The ObpCloseHandle routine <FILLMEIN>
1688 *
1689 * @param Handle
1690 * <FILLMEIN>.
1691 *
1692 * @param AccessMode
1693 * <FILLMEIN>.
1694 *
1695 * @return <FILLMEIN>.
1696 *
1697 * @remarks None.
1698 *
1699 *--*/
1700 NTSTATUS
1701 NTAPI
1702 ObpCloseHandle(IN HANDLE Handle,
1703 IN KPROCESSOR_MODE AccessMode)
1704 {
1705 PVOID HandleTable;
1706 BOOLEAN AttachedToProcess = FALSE;
1707 KAPC_STATE ApcState;
1708 PHANDLE_TABLE_ENTRY HandleTableEntry;
1709 NTSTATUS Status;
1710 PEPROCESS Process = PsGetCurrentProcess();
1711 PAGED_CODE();
1712 OBTRACE(OB_HANDLE_DEBUG,
1713 "%s - Closing handle: %lx\n", __FUNCTION__, Handle);
1714
1715 /* Check if we're dealing with a kernel handle */
1716 if (ObIsKernelHandle(Handle, AccessMode))
1717 {
1718 /* Use the kernel table and convert the handle */
1719 HandleTable = ObpKernelHandleTable;
1720 Handle = ObKernelHandleToHandle(Handle);
1721
1722 /* Check if we're not in the system process */
1723 if (Process != PsInitialSystemProcess)
1724 {
1725 /* Attach to the system process */
1726 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1727 AttachedToProcess = TRUE;
1728 }
1729 }
1730 else
1731 {
1732 /* Use the process's handle table */
1733 HandleTable = Process->ObjectTable;
1734 }
1735
1736 /* Enter a critical region to protect handle access */
1737 KeEnterCriticalRegion();
1738
1739 /* Get the handle entry */
1740 HandleTableEntry = ExMapHandleToPointer(HandleTable, Handle);
1741 if (HandleTableEntry)
1742 {
1743 /* Now close the entry */
1744 Status = ObpCloseHandleTableEntry(HandleTable,
1745 HandleTableEntry,
1746 Handle,
1747 AccessMode,
1748 FALSE);
1749
1750 /* We can quit the critical region now */
1751 KeLeaveCriticalRegion();
1752
1753 /* Detach and return success */
1754 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1755 }
1756 else
1757 {
1758 /* We failed, quit the critical region */
1759 KeLeaveCriticalRegion();
1760
1761 /* Detach */
1762 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1763
1764 /* Check if we have a valid handle that's not the process or thread */
1765 if ((Handle) &&
1766 (Handle != NtCurrentProcess()) &&
1767 (Handle != NtCurrentThread()))
1768 {
1769 /* Check if we came from user mode */
1770 if (AccessMode != KernelMode)
1771 {
1772 /* Check if we have no debug port */
1773 if (Process->DebugPort)
1774 {
1775 /* Make sure we're not attached */
1776 if (!KeIsAttachedProcess())
1777 {
1778 /* Raise an exception */
1779 return KeRaiseUserException(STATUS_INVALID_HANDLE);
1780 }
1781 }
1782 }
1783 else
1784 {
1785 /* This is kernel mode. Check if we're exiting */
1786 if (!(PsIsThreadTerminating(PsGetCurrentThread())) &&
1787 (Process->Peb))
1788 {
1789 /* Check if the debugger is enabled */
1790 if (KdDebuggerEnabled)
1791 {
1792 /* Bugcheck */
1793 KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 1, 0, 0);
1794 }
1795 }
1796 }
1797 }
1798
1799 /* Set invalid status */
1800 Status = STATUS_INVALID_HANDLE;
1801 }
1802
1803 /* Return status */
1804 OBTRACE(OB_HANDLE_DEBUG,
1805 "%s - Closed handle: %lx S: %lx\n",
1806 __FUNCTION__, Handle, Status);
1807 return Status;
1808 }
1809
1810 /*++
1811 * @name ObpSetHandleAttributes
1812 *
1813 * The ObpSetHandleAttributes routine <FILLMEIN>
1814 *
1815 * @param HandleTableEntry
1816 * <FILLMEIN>.
1817 *
1818 * @param Context
1819 * <FILLMEIN>.
1820 *
1821 * @return <FILLMEIN>.
1822 *
1823 * @remarks None.
1824 *
1825 *--*/
1826 BOOLEAN
1827 NTAPI
1828 ObpSetHandleAttributes(IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
1829 IN ULONG_PTR Context)
1830 {
1831 POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo = (PVOID)Context;
1832 POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1833
1834 /* Check if making the handle inheritable */
1835 if (SetHandleInfo->Information.Inherit)
1836 {
1837 /* Check if inheriting is not supported for this object */
1838 if (ObjectHeader->Type->TypeInfo.InvalidAttributes & OBJ_INHERIT)
1839 {
1840 /* Fail without changing anything */
1841 return FALSE;
1842 }
1843
1844 /* Set the flag */
1845 HandleTableEntry->ObAttributes |= OBJ_INHERIT;
1846 }
1847 else
1848 {
1849 /* Otherwise this implies we're removing the flag */
1850 HandleTableEntry->ObAttributes &= ~OBJ_INHERIT;
1851 }
1852
1853 /* Check if making the handle protected */
1854 if (SetHandleInfo->Information.ProtectFromClose)
1855 {
1856 /* Set the flag */
1857 HandleTableEntry->GrantedAccess |= ObpAccessProtectCloseBit;
1858 }
1859 else
1860 {
1861 /* Otherwise, remove it */
1862 HandleTableEntry->GrantedAccess &= ~ObpAccessProtectCloseBit;
1863 }
1864
1865 /* Return success */
1866 return TRUE;
1867 }
1868
1869 /*++
1870 * @name ObpCloseHandleCallback
1871 *
1872 * The ObpCloseHandleCallback routine <FILLMEIN>
1873 *
1874 * @param HandleTable
1875 * <FILLMEIN>.
1876 *
1877 * @param Object
1878 * <FILLMEIN>.
1879 *
1880 * @param GrantedAccess
1881 * <FILLMEIN>.
1882 *
1883 * @param Context
1884 * <FILLMEIN>.
1885 *
1886 * @return <FILLMEIN>.
1887 *
1888 * @remarks None.
1889 *
1890 *--*/
1891 BOOLEAN
1892 NTAPI
1893 ObpCloseHandleCallback(IN PHANDLE_TABLE_ENTRY HandleTableEntry,
1894 IN HANDLE Handle,
1895 IN PVOID Context)
1896 {
1897 POBP_CLOSE_HANDLE_CONTEXT CloseContext = (POBP_CLOSE_HANDLE_CONTEXT)Context;
1898
1899 /* Simply decrement the handle count */
1900 ObpCloseHandleTableEntry(CloseContext->HandleTable,
1901 HandleTableEntry,
1902 Handle,
1903 CloseContext->AccessMode,
1904 TRUE);
1905 return TRUE;
1906 }
1907
1908 /*++
1909 * @name ObpDuplicateHandleCallback
1910 *
1911 * The ObpDuplicateHandleCallback routine <FILLMEIN>
1912 *
1913 * @param HandleTable
1914 * <FILLMEIN>.
1915 *
1916 * @param HandleTableEntry
1917 * <FILLMEIN>.
1918 *
1919 * @param Context
1920 * <FILLMEIN>.
1921 *
1922 * @return <FILLMEIN>.
1923 *
1924 * @remarks None.
1925 *
1926 *--*/
1927 BOOLEAN
1928 NTAPI
1929 ObpDuplicateHandleCallback(IN PEPROCESS Process,
1930 IN PHANDLE_TABLE HandleTable,
1931 IN PHANDLE_TABLE_ENTRY OldEntry,
1932 IN PHANDLE_TABLE_ENTRY HandleTableEntry)
1933 {
1934 POBJECT_HEADER ObjectHeader;
1935 BOOLEAN Ret = FALSE;
1936 ACCESS_STATE AccessState;
1937 NTSTATUS Status;
1938 PAGED_CODE();
1939
1940 /* Make sure that the handle is inheritable */
1941 Ret = (HandleTableEntry->ObAttributes & OBJ_INHERIT) != 0;
1942 if (Ret)
1943 {
1944 /* Get the object header */
1945 ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1946
1947 /* Increment the pointer count */
1948 InterlockedIncrement(&ObjectHeader->PointerCount);
1949
1950 /* Release the handle lock */
1951 ExUnlockHandleTableEntry(HandleTable, OldEntry);
1952
1953 /* Setup the access state */
1954 AccessState.PreviouslyGrantedAccess = HandleTableEntry->GrantedAccess;
1955
1956 /* Call the shared routine for incrementing handles */
1957 Status = ObpIncrementHandleCount(&ObjectHeader->Body,
1958 &AccessState,
1959 KernelMode,
1960 HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES,
1961 Process,
1962 ObInheritHandle);
1963 if (!NT_SUCCESS(Status))
1964 {
1965 /* Return failure */
1966 ObDereferenceObject(&ObjectHeader->Body);
1967 Ret = FALSE;
1968 }
1969 }
1970 else
1971 {
1972 /* Release the handle lock */
1973 ExUnlockHandleTableEntry(HandleTable, OldEntry);
1974 }
1975
1976 /* Return duplication result */
1977 return Ret;
1978 }
1979
1980 VOID
1981 NTAPI
1982 ObClearProcessHandleTable(IN PEPROCESS Process)
1983 {
1984 /* FIXME */
1985 }
1986
1987 /*++
1988 * @name ObpCreateHandleTable
1989 *
1990 * The ObpCreateHandleTable routine <FILLMEIN>
1991 *
1992 * @param Parent
1993 * <FILLMEIN>.
1994 *
1995 * @param Process
1996 * <FILLMEIN>.
1997 *
1998 * @return <FILLMEIN>.
1999 *
2000 * @remarks None.
2001 *
2002 *--*/
2003 NTSTATUS
2004 NTAPI
2005 ObInitProcess(IN PEPROCESS Parent OPTIONAL,
2006 IN PEPROCESS Process)
2007 {
2008 PHANDLE_TABLE ParentTable, ObjectTable;
2009
2010 /* Check for a parent */
2011 if (Parent)
2012 {
2013 /* Reference the parent's table */
2014 ParentTable = ObReferenceProcessHandleTable(Parent);
2015 if (!ParentTable) return STATUS_PROCESS_IS_TERMINATING;
2016
2017 /* Duplicate it */
2018 ObjectTable = ExDupHandleTable(Process,
2019 ParentTable,
2020 ObpDuplicateHandleCallback,
2021 OBJ_INHERIT);
2022 }
2023 else
2024 {
2025 /* Otherwise just create a new table */
2026 ParentTable = NULL;
2027 ObjectTable = ExCreateHandleTable(Process);
2028 }
2029
2030 /* Make sure we have a table */
2031 if (ObjectTable)
2032 {
2033 /* Associate it */
2034 Process->ObjectTable = ObjectTable;
2035
2036 /* Check for auditing */
2037 if (SeDetailedAuditingWithToken(NULL))
2038 {
2039 /* FIXME: TODO */
2040 DPRINT1("Need auditing!\n");
2041 }
2042
2043 /* Get rid of the old table now */
2044 if (ParentTable) ObDereferenceProcessHandleTable(Parent);
2045
2046 /* We are done */
2047 return STATUS_SUCCESS;
2048 }
2049 else
2050 {
2051 /* Fail */
2052 Process->ObjectTable = NULL;
2053 if (ParentTable) ObDereferenceProcessHandleTable(Parent);
2054 return STATUS_INSUFFICIENT_RESOURCES;
2055 }
2056 }
2057
2058 /*++
2059 * @name ObKillProcess
2060 *
2061 * The ObKillProcess routine <FILLMEIN>
2062 *
2063 * @param Process
2064 * <FILLMEIN>.
2065 *
2066 * @return None.
2067 *
2068 * @remarks None.
2069 *
2070 *--*/
2071 VOID
2072 NTAPI
2073 ObKillProcess(IN PEPROCESS Process)
2074 {
2075 PHANDLE_TABLE HandleTable;
2076 OBP_CLOSE_HANDLE_CONTEXT Context;
2077 BOOLEAN HardErrors;
2078 PAGED_CODE();
2079
2080 /* Wait for process rundown and then complete it */
2081 ExWaitForRundownProtectionRelease(&Process->RundownProtect);
2082 ExRundownCompleted(&Process->RundownProtect);
2083
2084 /* Get the object table */
2085 HandleTable = Process->ObjectTable;
2086 if (!HandleTable) return;
2087
2088 /* Disable hard errors while we close handles */
2089 HardErrors = IoSetThreadHardErrorMode(FALSE);
2090
2091 /* Enter a critical region */
2092 KeEnterCriticalRegion();
2093
2094 /* Fill out the context */
2095 Context.AccessMode = KernelMode;
2096 Context.HandleTable = HandleTable;
2097
2098 /* Sweep the handle table to close all handles */
2099 ExSweepHandleTable(HandleTable,
2100 ObpCloseHandleCallback,
2101 &Context);
2102 ASSERT(HandleTable->HandleCount == 0);
2103
2104 /* Leave the critical region */
2105 KeLeaveCriticalRegion();
2106
2107 /* Re-enable hard errors */
2108 IoSetThreadHardErrorMode(HardErrors);
2109
2110 /* Destroy the object table */
2111 Process->ObjectTable = NULL;
2112 ExDestroyHandleTable(HandleTable, NULL);
2113 }
2114
2115 NTSTATUS
2116 NTAPI
2117 ObDuplicateObject(IN PEPROCESS SourceProcess,
2118 IN HANDLE SourceHandle,
2119 IN PEPROCESS TargetProcess OPTIONAL,
2120 IN PHANDLE TargetHandle OPTIONAL,
2121 IN ACCESS_MASK DesiredAccess,
2122 IN ULONG HandleAttributes,
2123 IN ULONG Options,
2124 IN KPROCESSOR_MODE PreviousMode)
2125 {
2126 HANDLE_TABLE_ENTRY NewHandleEntry;
2127 BOOLEAN AttachedToProcess = FALSE;
2128 PVOID SourceObject;
2129 POBJECT_HEADER ObjectHeader;
2130 POBJECT_TYPE ObjectType;
2131 HANDLE NewHandle;
2132 KAPC_STATE ApcState;
2133 NTSTATUS Status;
2134 ACCESS_MASK TargetAccess, SourceAccess;
2135 ACCESS_STATE AccessState;
2136 PACCESS_STATE PassedAccessState = NULL;
2137 AUX_ACCESS_DATA AuxData;
2138 PHANDLE_TABLE HandleTable;
2139 OBJECT_HANDLE_INFORMATION HandleInformation;
2140 ULONG AuditMask;
2141 PAGED_CODE();
2142 OBTRACE(OB_HANDLE_DEBUG,
2143 "%s - Duplicating handle: %lx for %p into %p\n",
2144 __FUNCTION__,
2145 SourceHandle,
2146 SourceProcess,
2147 TargetProcess);
2148
2149 /* Assume failure */
2150 if (TargetHandle) *TargetHandle = NULL;
2151
2152 /* Check if we're not duplicating the same access */
2153 if (!(Options & DUPLICATE_SAME_ACCESS))
2154 {
2155 /* Validate the desired access */
2156 Status = STATUS_SUCCESS; //ObpValidateDesiredAccess(DesiredAccess);
2157 if (!NT_SUCCESS(Status)) return Status;
2158 }
2159
2160 /* Reference the object table */
2161 HandleTable = ObReferenceProcessHandleTable(SourceProcess);
2162 if (!HandleTable) return STATUS_PROCESS_IS_TERMINATING;
2163
2164 /* Reference the process object */
2165 Status = ObpReferenceProcessObjectByHandle(SourceHandle,
2166 SourceProcess,
2167 HandleTable,
2168 PreviousMode,
2169 &SourceObject,
2170 &HandleInformation,
2171 &AuditMask);
2172 if (!NT_SUCCESS(Status))
2173 {
2174 /* Fail */
2175 ObDereferenceProcessHandleTable(SourceProcess);
2176 return Status;
2177 }
2178 else
2179 {
2180 /* Check if we have to don't have to audit object close */
2181 if (!(HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE))
2182 {
2183 /* Then there is no audit mask */
2184 AuditMask = 0;
2185 }
2186 }
2187
2188 /* Check if there's no target process */
2189 if (!TargetProcess)
2190 {
2191 /* Check if the caller wanted actual duplication */
2192 if (!(Options & DUPLICATE_CLOSE_SOURCE))
2193 {
2194 /* Invalid request */
2195 Status = STATUS_INVALID_PARAMETER;
2196 }
2197 else
2198 {
2199 /* Otherwise, do the attach */
2200 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2201
2202 /* Close the handle and detach */
2203 NtClose(SourceHandle);
2204 KeUnstackDetachProcess(&ApcState);
2205 }
2206
2207 /* Return */
2208 ObDereferenceProcessHandleTable(SourceProcess);
2209 ObDereferenceObject(SourceObject);
2210 return Status;
2211 }
2212
2213 /* Get the target handle table */
2214 HandleTable = ObReferenceProcessHandleTable(TargetProcess);
2215 if (!HandleTable)
2216 {
2217 /* Check if the caller wanted us to close the handle */
2218 if (Options & DUPLICATE_CLOSE_SOURCE)
2219 {
2220 /* Do the attach */
2221 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2222
2223 /* Close the handle and detach */
2224 NtClose(SourceHandle);
2225 KeUnstackDetachProcess(&ApcState);
2226 }
2227
2228 /* Return */
2229 ObDereferenceProcessHandleTable(SourceProcess);
2230 ObDereferenceObject(SourceObject);
2231 return STATUS_PROCESS_IS_TERMINATING;
2232 }
2233
2234 /* Get the source access */
2235 SourceAccess = HandleInformation.GrantedAccess;
2236
2237 /* Check if we're not in the target process */
2238 if (TargetProcess != PsGetCurrentProcess())
2239 {
2240 /* Attach to it */
2241 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
2242 AttachedToProcess = TRUE;
2243 }
2244
2245 /* Check if we're duplicating the attributes */
2246 if (Options & DUPLICATE_SAME_ATTRIBUTES)
2247 {
2248 /* Duplicate them */
2249 HandleAttributes = HandleInformation.HandleAttributes;
2250 }
2251 else
2252 {
2253 /* Don't allow caller to bypass auditing */
2254 HandleAttributes |= HandleInformation.HandleAttributes &
2255 OBJ_AUDIT_OBJECT_CLOSE;
2256 }
2257
2258 /* Check if we're duplicating the access */
2259 if (Options & DUPLICATE_SAME_ACCESS) DesiredAccess = SourceAccess;
2260
2261 /* Get object data */
2262 ObjectHeader = OBJECT_TO_OBJECT_HEADER(SourceObject);
2263 ObjectType = ObjectHeader->Type;
2264
2265 /* Fill out the entry */
2266 RtlZeroMemory(&NewHandleEntry, sizeof(HANDLE_TABLE_ENTRY));
2267 NewHandleEntry.Object = ObjectHeader;
2268 NewHandleEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
2269
2270 /* Check if we're using a generic mask */
2271 if (DesiredAccess & GENERIC_ACCESS)
2272 {
2273 /* Map it */
2274 RtlMapGenericMask(&DesiredAccess,
2275 &ObjectType->TypeInfo.GenericMapping);
2276 }
2277
2278 /* Set the target access, always propagate ACCESS_SYSTEM_SECURITY */
2279 TargetAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
2280 ACCESS_SYSTEM_SECURITY);
2281 NewHandleEntry.GrantedAccess = TargetAccess;
2282
2283 /* Check if we're asking for new access */
2284 if (TargetAccess & ~SourceAccess)
2285 {
2286 /* We are. We need the security procedure to validate this */
2287 if (ObjectType->TypeInfo.SecurityProcedure == SeDefaultObjectMethod)
2288 {
2289 /* Use our built-in access state */
2290 PassedAccessState = &AccessState;
2291 Status = SeCreateAccessState(&AccessState,
2292 &AuxData,
2293 TargetAccess,
2294 &ObjectType->TypeInfo.GenericMapping);
2295 }
2296 else
2297 {
2298 /* Otherwise we can't allow this privilege elevation */
2299 Status = STATUS_ACCESS_DENIED;
2300 }
2301 }
2302 else
2303 {
2304 /* We don't need an access state */
2305 Status = STATUS_SUCCESS;
2306 }
2307
2308 /* Make sure the access state was created OK */
2309 if (NT_SUCCESS(Status))
2310 {
2311 /* Add a new handle */
2312 Status = ObpIncrementHandleCount(SourceObject,
2313 PassedAccessState,
2314 PreviousMode,
2315 HandleAttributes,
2316 PsGetCurrentProcess(),
2317 ObDuplicateHandle);
2318 }
2319
2320 /* Check if we were attached */
2321 if (AttachedToProcess)
2322 {
2323 /* We can safely detach now */
2324 KeUnstackDetachProcess(&ApcState);
2325 AttachedToProcess = FALSE;
2326 }
2327
2328 /* Check if we have to close the source handle */
2329 if (Options & DUPLICATE_CLOSE_SOURCE)
2330 {
2331 /* Attach and close */
2332 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2333 NtClose(SourceHandle);
2334 KeUnstackDetachProcess(&ApcState);
2335 }
2336
2337 /* Check if we had an access state */
2338 if (PassedAccessState) SeDeleteAccessState(PassedAccessState);
2339
2340 /* Now check if incrementing actually failed */
2341 if (!NT_SUCCESS(Status))
2342 {
2343 /* Dereference handle tables */
2344 ObDereferenceProcessHandleTable(SourceProcess);
2345 ObDereferenceProcessHandleTable(TargetProcess);
2346
2347 /* Dereference the source object */
2348 ObDereferenceObject(SourceObject);
2349 return Status;
2350 }
2351
2352 /* Now create the handle */
2353 NewHandle = ExCreateHandle(HandleTable, &NewHandleEntry);
2354 if (!NewHandle)
2355 {
2356 /* Undo the increment */
2357 ObpDecrementHandleCount(SourceObject,
2358 TargetProcess,
2359 TargetAccess,
2360 ObjectType);
2361
2362 /* Deference the object and set failure status */
2363 ObDereferenceObject(SourceObject);
2364 Status = STATUS_INSUFFICIENT_RESOURCES;
2365 }
2366
2367 /* Return the handle */
2368 if (TargetHandle) *TargetHandle = NewHandle;
2369
2370 /* Dereference handle tables */
2371 ObDereferenceProcessHandleTable(SourceProcess);
2372 ObDereferenceProcessHandleTable(TargetProcess);
2373
2374 /* Return status */
2375 OBTRACE(OB_HANDLE_DEBUG,
2376 "%s - Duplicated handle: %lx for %p into %p. Source: %p HC PC %lx %lx\n",
2377 __FUNCTION__,
2378 NewHandle,
2379 SourceProcess,
2380 TargetProcess,
2381 SourceObject,
2382 ObjectHeader->PointerCount,
2383 ObjectHeader->HandleCount);
2384 return Status;
2385 }
2386
2387 /* PUBLIC FUNCTIONS *********************************************************/
2388
2389 /*++
2390 * @name ObOpenObjectByName
2391 * @implemented NT4
2392 *
2393 * The ObOpenObjectByName routine <FILLMEIN>
2394 *
2395 * @param ObjectAttributes
2396 * <FILLMEIN>.
2397 *
2398 * @param ObjectType
2399 * <FILLMEIN>.
2400 *
2401 * @param AccessMode
2402 * <FILLMEIN>.
2403 *
2404 * @param PassedAccessState
2405 * <FILLMEIN>.
2406 *
2407 * @param DesiredAccess
2408 * <FILLMEIN>.
2409 *
2410 * @param ParseContext
2411 * <FILLMEIN>.
2412 *
2413 * @param Handle
2414 * <FILLMEIN>.
2415 *
2416 * @return <FILLMEIN>.
2417 *
2418 * @remarks None.
2419 *
2420 *--*/
2421 NTSTATUS
2422 NTAPI
2423 ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
2424 IN POBJECT_TYPE ObjectType,
2425 IN KPROCESSOR_MODE AccessMode,
2426 IN PACCESS_STATE PassedAccessState,
2427 IN ACCESS_MASK DesiredAccess,
2428 IN OUT PVOID ParseContext,
2429 OUT PHANDLE Handle)
2430 {
2431 PVOID Object = NULL;
2432 UNICODE_STRING ObjectName;
2433 NTSTATUS Status;
2434 POBJECT_HEADER ObjectHeader;
2435 PGENERIC_MAPPING GenericMapping = NULL;
2436 OB_OPEN_REASON OpenReason;
2437 POB_TEMP_BUFFER TempBuffer;
2438 PAGED_CODE();
2439
2440 /* Assume failure */
2441 *Handle = NULL;
2442
2443 /* Check if we didn't get any Object Attributes */
2444 if (!ObjectAttributes)
2445 {
2446 /* Fail with special status code */
2447 return STATUS_INVALID_PARAMETER;
2448 }
2449
2450 /* Allocate the temporary buffer */
2451 TempBuffer = ExAllocatePoolWithTag(NonPagedPool,
2452 sizeof(OB_TEMP_BUFFER),
2453 TAG_OB_TEMP_STORAGE);
2454 if (!TempBuffer) return STATUS_INSUFFICIENT_RESOURCES;
2455
2456 /* Capture all the info */
2457 Status = ObpCaptureObjectCreateInformation(ObjectAttributes,
2458 AccessMode,
2459 TRUE,
2460 &TempBuffer->ObjectCreateInfo,
2461 &ObjectName);
2462 if (!NT_SUCCESS(Status))
2463 {
2464 /* Fail */
2465 ExFreePoolWithTag(TempBuffer, TAG_OB_TEMP_STORAGE);
2466 return Status;
2467 }
2468
2469 /* Check if we didn't get an access state */
2470 if (!PassedAccessState)
2471 {
2472 /* Try to get the generic mapping if we can */
2473 if (ObjectType) GenericMapping = &ObjectType->TypeInfo.GenericMapping;
2474
2475 /* Use our built-in access state */
2476 PassedAccessState = &TempBuffer->LocalAccessState;
2477 Status = SeCreateAccessState(&TempBuffer->LocalAccessState,
2478 &TempBuffer->AuxData,
2479 DesiredAccess,
2480 GenericMapping);
2481 if (!NT_SUCCESS(Status)) goto Quickie;
2482 }
2483
2484 /* Get the security descriptor */
2485 if (TempBuffer->ObjectCreateInfo.SecurityDescriptor)
2486 {
2487 /* Save it in the access state */
2488 PassedAccessState->SecurityDescriptor =
2489 TempBuffer->ObjectCreateInfo.SecurityDescriptor;
2490 }
2491
2492 /* Now do the lookup */
2493 Status = ObpLookupObjectName(TempBuffer->ObjectCreateInfo.RootDirectory,
2494 &ObjectName,
2495 TempBuffer->ObjectCreateInfo.Attributes,
2496 ObjectType,
2497 AccessMode,
2498 ParseContext,
2499 TempBuffer->ObjectCreateInfo.SecurityQos,
2500 NULL,
2501 PassedAccessState,
2502 &TempBuffer->LookupContext,
2503 &Object);
2504 if (!NT_SUCCESS(Status))
2505 {
2506 /* Cleanup after lookup */
2507 ObpReleaseLookupContext(&TempBuffer->LookupContext);
2508 goto Cleanup;
2509 }
2510
2511 /* Check if this object has create information */
2512 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2513 if (ObjectHeader->Flags & OB_FLAG_CREATE_INFO)
2514 {
2515 /* Then we are creating a new handle */
2516 OpenReason = ObCreateHandle;
2517
2518 /* Check if we still have create info */
2519 if (ObjectHeader->ObjectCreateInfo)
2520 {
2521 /* Free it */
2522 ObpFreeObjectCreateInformation(ObjectHeader->
2523 ObjectCreateInfo);
2524 ObjectHeader->ObjectCreateInfo = NULL;
2525 }
2526 }
2527 else
2528 {
2529 /* Otherwise, we are merely opening it */
2530 OpenReason = ObOpenHandle;
2531 }
2532
2533 /* Check if we have invalid object attributes */
2534 if (ObjectHeader->Type->TypeInfo.InvalidAttributes &
2535 TempBuffer->ObjectCreateInfo.Attributes)
2536 {
2537 /* Set failure code */
2538 Status = STATUS_INVALID_PARAMETER;
2539
2540 /* Cleanup after lookup */
2541 ObpReleaseLookupContext(&TempBuffer->LookupContext);
2542
2543 /* Dereference the object */
2544 ObDereferenceObject(Object);
2545 }
2546 else
2547 {
2548 /* Create the actual handle now */
2549 Status = ObpCreateHandle(OpenReason,
2550 Object,
2551 ObjectType,
2552 PassedAccessState,
2553 0,
2554 TempBuffer->ObjectCreateInfo.Attributes,
2555 &TempBuffer->LookupContext,
2556 AccessMode,
2557 NULL,
2558 Handle);
2559 if (!NT_SUCCESS(Status)) ObDereferenceObject(Object);
2560 }
2561
2562 Cleanup:
2563 /* Delete the access state */
2564 if (PassedAccessState == &TempBuffer->LocalAccessState)
2565 {
2566 SeDeleteAccessState(PassedAccessState);
2567 }
2568
2569 Quickie:
2570 /* Release the object attributes and temporary buffer */
2571 ObpReleaseObjectCreateInformation(&TempBuffer->ObjectCreateInfo);
2572 if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
2573 ExFreePoolWithTag(TempBuffer, TAG_OB_TEMP_STORAGE);
2574
2575 /* Return status */
2576 OBTRACE(OB_HANDLE_DEBUG,
2577 "%s - returning Object %p with PC S: %lx %lx\n",
2578 __FUNCTION__,
2579 Object,
2580 Object ? OBJECT_TO_OBJECT_HEADER(Object)->PointerCount : -1,
2581 Status);
2582 return Status;
2583 }
2584
2585 /*++
2586 * @name ObOpenObjectByPointer
2587 * @implemented NT4
2588 *
2589 * The ObOpenObjectByPointer routine <FILLMEIN>
2590 *
2591 * @param Object
2592 * <FILLMEIN>.
2593 *
2594 * @param HandleAttributes
2595 * <FILLMEIN>.
2596 *
2597 * @param PassedAccessState
2598 * <FILLMEIN>.
2599 *
2600 * @param DesiredAccess
2601 * <FILLMEIN>.
2602 *
2603 * @param ObjectType
2604 * <FILLMEIN>.
2605 *
2606 * @param AccessMode
2607 * <FILLMEIN>.
2608 *
2609 * @param Handle
2610 * <FILLMEIN>.
2611 *
2612 * @return <FILLMEIN>.
2613 *
2614 * @remarks None.
2615 *
2616 *--*/
2617 NTSTATUS
2618 NTAPI
2619 ObOpenObjectByPointer(IN PVOID Object,
2620 IN ULONG HandleAttributes,
2621 IN PACCESS_STATE PassedAccessState,
2622 IN ACCESS_MASK DesiredAccess,
2623 IN POBJECT_TYPE ObjectType,
2624 IN KPROCESSOR_MODE AccessMode,
2625 OUT PHANDLE Handle)
2626 {
2627 POBJECT_HEADER Header;
2628 NTSTATUS Status;
2629 ACCESS_STATE AccessState;
2630 AUX_ACCESS_DATA AuxData;
2631 PAGED_CODE();
2632
2633 /* Assume failure */
2634 *Handle = NULL;
2635
2636 /* Reference the object */
2637 Status = ObReferenceObjectByPointer(Object,
2638 0,
2639 ObjectType,
2640 AccessMode);
2641 if (!NT_SUCCESS(Status)) return Status;
2642
2643 /* Get the Header Info */
2644 Header = OBJECT_TO_OBJECT_HEADER(Object);
2645
2646 /* Check if we didn't get an access state */
2647 if (!PassedAccessState)
2648 {
2649 /* Use our built-in access state */
2650 PassedAccessState = &AccessState;
2651 Status = SeCreateAccessState(&AccessState,
2652 &AuxData,
2653 DesiredAccess,
2654 &Header->Type->TypeInfo.GenericMapping);
2655 if (!NT_SUCCESS(Status))
2656 {
2657 /* Fail */
2658 ObDereferenceObject(Object);
2659 return Status;
2660 }
2661 }
2662
2663 /* Check if we have invalid object attributes */
2664 if (Header->Type->TypeInfo.InvalidAttributes & HandleAttributes)
2665 {
2666 /* Delete the access state */
2667 if (PassedAccessState == &AccessState)
2668 {
2669 SeDeleteAccessState(PassedAccessState);
2670 }
2671
2672 /* Dereference the object */
2673 ObDereferenceObject(Object);
2674 return STATUS_INVALID_PARAMETER;
2675 }
2676
2677 /* Create the handle */
2678 Status = ObpCreateHandle(ObOpenHandle,
2679 Object,
2680 ObjectType,
2681 PassedAccessState,
2682 0,
2683 HandleAttributes,
2684 NULL,
2685 AccessMode,
2686 NULL,
2687 Handle);
2688 if (!NT_SUCCESS(Status)) ObDereferenceObject(Object);
2689
2690 /* Delete the access state */
2691 if (PassedAccessState == &AccessState)
2692 {
2693 SeDeleteAccessState(PassedAccessState);
2694 }
2695
2696 /* Return */
2697 OBTRACE(OB_HANDLE_DEBUG,
2698 "%s - returning Object with PC S: %lx %lx\n",
2699 __FUNCTION__,
2700 OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
2701 Status);
2702 return Status;
2703 }
2704
2705 /*++
2706 * @name ObFindHandleForObject
2707 * @implemented NT4
2708 *
2709 * The ObFindHandleForObject routine <FILLMEIN>
2710 *
2711 * @param Process
2712 * <FILLMEIN>.
2713 *
2714 * @param Object
2715 * <FILLMEIN>.
2716 *
2717 * @param ObjectType
2718 * <FILLMEIN>.
2719 *
2720 * @param HandleInformation
2721 * <FILLMEIN>.
2722 *
2723 * @param HandleReturn
2724 * <FILLMEIN>.
2725 *
2726 * @return <FILLMEIN>.
2727 *
2728 * @remarks None.
2729 *
2730 *--*/
2731 BOOLEAN
2732 NTAPI
2733 ObFindHandleForObject(IN PEPROCESS Process,
2734 IN PVOID Object,
2735 IN POBJECT_TYPE ObjectType,
2736 IN POBJECT_HANDLE_INFORMATION HandleInformation,
2737 OUT PHANDLE Handle)
2738 {
2739 OBP_FIND_HANDLE_DATA FindData;
2740 BOOLEAN Result = FALSE;
2741 PVOID ObjectTable;
2742
2743 /* Make sure we have an object table */
2744 ObjectTable = ObReferenceProcessHandleTable(Process);
2745 if (ObjectTable)
2746 {
2747 /* Check if we have an object */
2748 if (Object)
2749 {
2750 /* Set its header */
2751 FindData.ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2752 }
2753 else
2754 {
2755 /* Otherwise, no object to match*/
2756 FindData.ObjectHeader = NULL;
2757 }
2758
2759 /* Set other information */
2760 FindData.ObjectType = ObjectType;
2761 FindData.HandleInformation = HandleInformation;
2762
2763 /* Enumerate the handle table */
2764 if (ExEnumHandleTable(Process->ObjectTable,
2765 ObpEnumFindHandleProcedure,
2766 &FindData,
2767 Handle))
2768 {
2769 /* Set success */
2770 Result = TRUE;
2771 }
2772
2773 /* Let go of the table */
2774 ObDereferenceProcessHandleTable(Process);
2775 }
2776
2777 /* Return the result */
2778 return Result;
2779 }
2780
2781 /*++
2782 * @name ObInsertObject
2783 * @implemented NT4
2784 *
2785 * The ObInsertObject routine <FILLMEIN>
2786 *
2787 * @param Object
2788 * <FILLMEIN>.
2789 *
2790 * @param PassedAccessState
2791 * <FILLMEIN>.
2792 *
2793 * @param DesiredAccess
2794 * <FILLMEIN>.
2795 *
2796 * @param AdditionalReferences
2797 * <FILLMEIN>.
2798 *
2799 * @param ReferencedObject
2800 * <FILLMEIN>.
2801 *
2802 * @param Handle
2803 * <FILLMEIN>.
2804 *
2805 * @return <FILLMEIN>.
2806 *
2807 * @remarks None.
2808 *
2809 *--*/
2810 NTSTATUS
2811 NTAPI
2812 ObInsertObject(IN PVOID Object,
2813 IN PACCESS_STATE AccessState OPTIONAL,
2814 IN ACCESS_MASK DesiredAccess,
2815 IN ULONG ObjectPointerBias,
2816 OUT PVOID *NewObject OPTIONAL,
2817 OUT PHANDLE Handle)
2818 {
2819 POBJECT_CREATE_INFORMATION ObjectCreateInfo;
2820 POBJECT_HEADER ObjectHeader;
2821 POBJECT_TYPE ObjectType;
2822 PUNICODE_STRING ObjectName;
2823 PVOID InsertObject;
2824 PSECURITY_DESCRIPTOR ParentDescriptor = NULL;
2825 BOOLEAN SdAllocated = FALSE;
2826 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
2827 OBP_LOOKUP_CONTEXT Context;
2828 ACCESS_STATE LocalAccessState;
2829 AUX_ACCESS_DATA AuxData;
2830 OB_OPEN_REASON OpenReason;
2831 KPROCESSOR_MODE PreviousMode;
2832 NTSTATUS Status = STATUS_SUCCESS, RealStatus;
2833 BOOLEAN IsNewObject;
2834 PAGED_CODE();
2835
2836 /* Get the Header */
2837 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2838
2839 /* Detect invalid insert */
2840 if (!(ObjectHeader->Flags & OB_FLAG_CREATE_INFO))
2841 {
2842 /* Display warning and break into debugger */
2843 DPRINT1("OB: Attempting to insert existing object %08x\n", Object);
2844 DbgBreakPoint();
2845
2846 /* Allow debugger to continue */
2847 ObDereferenceObject(Object);
2848 return STATUS_INVALID_PARAMETER;
2849 }
2850
2851 /* Get the create and name info, as well as the object type */
2852 ObjectCreateInfo = ObjectHeader->ObjectCreateInfo;
2853 ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
2854 ObjectType = ObjectHeader->Type;
2855 ObjectName = NULL;
2856
2857 /* Check if this is an named object */
2858 if ((ObjectNameInfo) && (ObjectNameInfo->Name.Buffer))
2859 {
2860 /* Get the object name */
2861 ObjectName = &ObjectNameInfo->Name;
2862 }
2863
2864 /* Sanity check */
2865 ASSERT((Handle) ||
2866 ((ObjectPointerBias == 0) &&
2867 (ObjectName == NULL) &&
2868 (ObjectType->TypeInfo.SecurityRequired) &&
2869 (NewObject == NULL)));
2870
2871 /* Check if the object is unnamed and also doesn't have security */
2872 PreviousMode = KeGetPreviousMode();
2873 if (!(ObjectType->TypeInfo.SecurityRequired) && !(ObjectName))
2874 {
2875 /* Assume failure */
2876 *Handle = NULL;
2877 ObjectHeader->ObjectCreateInfo = NULL;
2878
2879 /* Create the handle */
2880 Status = ObpCreateUnnamedHandle(Object,
2881 DesiredAccess,
2882 ObjectPointerBias + 1,
2883 ObjectCreateInfo->Attributes,
2884 PreviousMode,
2885 NewObject,
2886 Handle);
2887
2888 /* Free the create information */
2889 ObpFreeObjectCreateInformation(ObjectCreateInfo);
2890
2891 /* Release the object name information */
2892 ObpDereferenceNameInfo(ObjectNameInfo);
2893
2894 /* Remove the extra keep-alive reference */
2895 ObDereferenceObject(Object);
2896
2897 /* Return */
2898 OBTRACE(OB_HANDLE_DEBUG,
2899 "%s - returning Object with PC S: %lx %lx\n",
2900 __FUNCTION__,
2901 ObjectHeader->PointerCount,
2902 Status);
2903 return Status;
2904 }
2905
2906 /* Check if we didn't get an access state */
2907 if (!AccessState)
2908 {
2909 /* Use our built-in access state */
2910 AccessState = &LocalAccessState;
2911 Status = SeCreateAccessState(&LocalAccessState,
2912 &AuxData,
2913 DesiredAccess,
2914 &ObjectType->TypeInfo.GenericMapping);
2915 if (!NT_SUCCESS(Status))
2916 {
2917 /* Fail */
2918 ObpDereferenceNameInfo(ObjectNameInfo);
2919 ObDereferenceObject(Object);
2920 return Status;
2921 }
2922 }
2923
2924 /* Save the security descriptor */
2925 AccessState->SecurityDescriptor = ObjectCreateInfo->SecurityDescriptor;
2926
2927 /* Validate the access mask */
2928 Status = ObpValidateAccessMask(AccessState);
2929 if (!NT_SUCCESS(Status))
2930 {
2931 /* Fail */
2932 ObpDereferenceNameInfo(ObjectNameInfo);
2933 ObDereferenceObject(Object);
2934 return Status;
2935 }
2936
2937 /* Setup a lookup context */
2938 ObpInitializeLookupContext(&Context);
2939 InsertObject = Object;
2940 OpenReason = ObCreateHandle;
2941
2942 /* Check if the object is named */
2943 if (ObjectName)
2944 {
2945 /* Look it up */
2946 Status = ObpLookupObjectName(ObjectCreateInfo->RootDirectory,
2947 ObjectName,
2948 ObjectCreateInfo->Attributes,
2949 ObjectType,
2950 (ObjectHeader->Flags & OB_FLAG_KERNEL_MODE) ?
2951 KernelMode : UserMode,
2952 ObjectCreateInfo->ParseContext,
2953 ObjectCreateInfo->SecurityQos,
2954 Object,
2955 AccessState,
2956 &Context,
2957 &InsertObject);
2958
2959 /* Check if we found an object that doesn't match the one requested */
2960 if ((NT_SUCCESS(Status)) && (InsertObject) && (Object != InsertObject))
2961 {
2962 /* This means we're opening an object, not creating a new one */
2963 OpenReason = ObOpenHandle;
2964
2965 /* Make sure the caller said it's OK to do this */
2966 if (ObjectCreateInfo->Attributes & OBJ_OPENIF)
2967 {
2968 /* He did, but did he want this type? */
2969 if (ObjectType != OBJECT_TO_OBJECT_HEADER(InsertObject)->Type)
2970 {
2971 /* Wrong type, so fail */
2972 Status = STATUS_OBJECT_TYPE_MISMATCH;
2973 }
2974 else
2975 {
2976 /* Right type, so warn */
2977 Status = STATUS_OBJECT_NAME_EXISTS;
2978 }
2979 }
2980 else
2981 {
2982 /* Check if this was a symbolic link */
2983 if (OBJECT_TO_OBJECT_HEADER(InsertObject)->Type ==
2984 ObSymbolicLinkType)
2985 {
2986 /* Dereference it */
2987 ObDereferenceObject(InsertObject);
2988 }
2989
2990 /* Caller wanted to create a new object, fail */
2991 Status = STATUS_OBJECT_NAME_COLLISION;
2992 }
2993 }
2994
2995 /* Check if anything until now failed */
2996 if (!NT_SUCCESS(Status))
2997 {
2998 /* Cleanup after lookup */
2999 ObpReleaseLookupContext(&Context);
3000
3001 /* Remove query reference that we added */
3002 ObpDereferenceNameInfo(ObjectNameInfo);
3003
3004 /* Dereference the object and delete the access state */
3005 ObDereferenceObject(Object);
3006 if (AccessState == &LocalAccessState)
3007 {
3008 /* We used a local one; delete it */
3009 SeDeleteAccessState(AccessState);
3010 }
3011
3012 /* Return failure code */
3013 return Status;
3014 }
3015 else
3016 {
3017 /* Check if this is a symbolic link */
3018 if (ObjectType == ObSymbolicLinkType)
3019 {
3020 /* Create the internal name */
3021 ObpCreateSymbolicLinkName(Object);
3022 }
3023 }
3024 }
3025
3026 /* Now check if this object is being created */
3027 if (InsertObject == Object)
3028 {
3029 /* Check if it's named or forces security */
3030 if ((ObjectName) || (ObjectType->TypeInfo.SecurityRequired))
3031 {
3032 /* Make sure it's inserted into an object directory */
3033 if ((ObjectNameInfo) && (ObjectNameInfo->Directory))
3034 {
3035 /* Get the current descriptor */
3036 ObGetObjectSecurity(ObjectNameInfo->Directory,
3037 &ParentDescriptor,
3038 &SdAllocated);
3039 }
3040
3041 /* Now assign it */
3042 Status = ObAssignSecurity(AccessState,
3043 ParentDescriptor,
3044 Object,
3045 ObjectType);
3046
3047 /* Check if we captured one */
3048 if (ParentDescriptor)
3049 {
3050 /* We did, release it */
3051 ObReleaseObjectSecurity(ParentDescriptor, SdAllocated);
3052 }
3053 else if (NT_SUCCESS(Status))
3054 {
3055 /* Other we didn't, but we were able to use the current SD */
3056 SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor,
3057 ObjectCreateInfo->ProbeMode,
3058 TRUE);
3059
3060 /* Clear the current one */
3061 AccessState->SecurityDescriptor =
3062 ObjectCreateInfo->SecurityDescriptor = NULL;
3063 }
3064 }
3065
3066 /* Check if anything until now failed */
3067 if (!NT_SUCCESS(Status))
3068 {
3069 /* Check if the directory was added */
3070 if (Context.DirectoryLocked)
3071 {
3072 /* Weird case where we need to do a manual delete */
3073 DPRINT1("Unhandled path\n");
3074 ASSERT(FALSE);
3075 }
3076
3077 /* Cleanup the lookup */
3078 ObpReleaseLookupContext(&Context);
3079
3080 /* Remove query reference that we added */
3081 ObpDereferenceNameInfo(ObjectNameInfo);
3082
3083 /* Dereference the object and delete the access state */
3084 ObDereferenceObject(Object);
3085 if (AccessState == &LocalAccessState)
3086 {
3087 /* We used a local one; delete it */
3088 SeDeleteAccessState(AccessState);
3089 }
3090
3091 /* Return failure code */
3092 ASSERT(FALSE);
3093 return Status;
3094 }
3095 }
3096
3097 /* Save the actual status until here */
3098 RealStatus = Status;
3099
3100 /* Check if caller wants us to create a handle */
3101 ObjectHeader->ObjectCreateInfo = NULL;
3102 if (Handle)
3103 {
3104 /* Create the handle */
3105 Status = ObpCreateHandle(OpenReason,
3106 InsertObject,
3107 NULL,
3108 AccessState,
3109 ObjectPointerBias + 1,
3110 ObjectCreateInfo->Attributes,
3111 &Context,
3112 PreviousMode,
3113 NewObject,
3114 Handle);
3115 if (!NT_SUCCESS(Status))
3116 {
3117 /* If the object had a name, backout everything */
3118 if (ObjectName) ObpDeleteNameCheck(Object);
3119
3120 /* Return the status of the failure */
3121 *Handle = NULL;
3122 RealStatus = Status;
3123 }
3124
3125 /* Remove a query reference */
3126 ObpDereferenceNameInfo(ObjectNameInfo);
3127
3128 /* Remove the extra keep-alive reference */
3129 ObDereferenceObject(Object);
3130 }
3131 else
3132 {
3133 /* Otherwise, lock the object */
3134 ObpAcquireObjectLock(ObjectHeader);
3135
3136 /* And charge quota for the process to make it appear as used */
3137 RealStatus = ObpChargeQuotaForObject(ObjectHeader,
3138 ObjectType,
3139 &IsNewObject);
3140
3141 /* Release the lock */
3142 ObpReleaseObjectLock(ObjectHeader);
3143
3144 /* Check if we failed and dereference the object if so */
3145 if (!NT_SUCCESS(RealStatus)) ObDereferenceObject(Object);
3146 }
3147
3148 /* We can delete the Create Info now */
3149 ObpFreeObjectCreateInformation(ObjectCreateInfo);
3150
3151 /* Check if we created our own access state and delete it if so */
3152 if (AccessState == &LocalAccessState) SeDeleteAccessState(AccessState);
3153
3154 /* Return status code */
3155 OBTRACE(OB_HANDLE_DEBUG,
3156 "%s - returning Object with PC RS/S: %lx %lx %lx\n",
3157 __FUNCTION__,
3158 OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
3159 RealStatus, Status);
3160 return RealStatus;
3161 }
3162
3163 /*++
3164 * @name ObCloseHandle
3165 * @implemented NT5.1
3166 *
3167 * The ObCloseHandle routine <FILLMEIN>
3168 *
3169 * @param Handle
3170 * <FILLMEIN>.
3171 *
3172 * @param AccessMode
3173 * <FILLMEIN>.
3174 *
3175 * @return <FILLMEIN>.
3176 *
3177 * @remarks None.
3178 *
3179 *--*/
3180 NTSTATUS
3181 NTAPI
3182 ObCloseHandle(IN HANDLE Handle,
3183 IN KPROCESSOR_MODE AccessMode)
3184 {
3185 /* Call the internal API */
3186 return ObpCloseHandle(Handle, AccessMode);
3187 }
3188
3189 /*++
3190 * @name NtClose
3191 * @implemented NT4
3192 *
3193 * The NtClose routine <FILLMEIN>
3194 *
3195 * @param Handle
3196 * <FILLMEIN>.
3197 *
3198 * @return <FILLMEIN>.
3199 *
3200 * @remarks None.
3201 *
3202 *--*/
3203 NTSTATUS
3204 NTAPI
3205 NtClose(IN HANDLE Handle)
3206 {
3207 /* Call the internal API */
3208 return ObpCloseHandle(Handle, ExGetPreviousMode());
3209 }
3210
3211 NTSTATUS
3212 NTAPI
3213 NtDuplicateObject(IN HANDLE SourceProcessHandle,
3214 IN HANDLE SourceHandle,
3215 IN HANDLE TargetProcessHandle OPTIONAL,
3216 OUT PHANDLE TargetHandle OPTIONAL,
3217 IN ACCESS_MASK DesiredAccess,
3218 IN ULONG HandleAttributes,
3219 IN ULONG Options)
3220 {
3221 PEPROCESS SourceProcess, TargetProcess, Target;
3222 HANDLE hTarget;
3223 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
3224 NTSTATUS Status;
3225 OBTRACE(OB_HANDLE_DEBUG,
3226 "%s - Duplicating handle: %lx for %lx into %lx.\n",
3227 __FUNCTION__,
3228 SourceHandle,
3229 SourceProcessHandle,
3230 TargetProcessHandle);
3231
3232 /* Check if we have a target handle */
3233 if ((TargetHandle) && (PreviousMode != KernelMode))
3234 {
3235 /* Enter SEH */
3236 _SEH2_TRY
3237 {
3238 /* Probe the handle and assume failure */
3239 ProbeForWriteHandle(TargetHandle);
3240 *TargetHandle = NULL;
3241 }
3242 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3243 {
3244 /* Return the exception code */
3245 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3246 }
3247 _SEH2_END;
3248 }
3249
3250 /* Now reference the input handle */
3251 Status = ObReferenceObjectByHandle(SourceProcessHandle,
3252 PROCESS_DUP_HANDLE,
3253 PsProcessType,
3254 PreviousMode,
3255 (PVOID*)&SourceProcess,
3256 NULL);
3257 if (!NT_SUCCESS(Status)) return(Status);
3258
3259 /* Check if got a target handle */
3260 if (TargetProcessHandle)
3261 {
3262 /* Now reference the output handle */
3263 Status = ObReferenceObjectByHandle(TargetProcessHandle,
3264 PROCESS_DUP_HANDLE,
3265 PsProcessType,
3266 PreviousMode,
3267 (PVOID*)&TargetProcess,
3268 NULL);
3269 if (NT_SUCCESS(Status))
3270 {
3271 /* Use this target process */
3272 Target = TargetProcess;
3273 }
3274 else
3275 {
3276 /* No target process */
3277 Target = NULL;
3278 }
3279 }
3280 else
3281 {
3282 /* No target process */
3283 Status = STATUS_SUCCESS;
3284 Target = NULL;
3285 }
3286
3287 /* Call the internal routine */
3288 Status = ObDuplicateObject(SourceProcess,
3289 SourceHandle,
3290 Target,
3291 &hTarget,
3292 DesiredAccess,
3293 HandleAttributes,
3294 Options,
3295 PreviousMode);
3296
3297 /* Check if the caller wanted the return handle */
3298 if (TargetHandle)
3299 {
3300 /* Protect the write to user mode */
3301 _SEH2_TRY
3302 {
3303 /* Write the new handle */
3304 *TargetHandle = hTarget;
3305 }
3306 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3307 {
3308 /* Otherwise, get the exception code */
3309 Status = _SEH2_GetExceptionCode();
3310 }
3311 _SEH2_END;
3312 }
3313
3314 /* Dereference the processes */
3315 OBTRACE(OB_HANDLE_DEBUG,
3316 "%s - Duplicated handle: %lx into %lx S %lx\n",
3317 __FUNCTION__,
3318 hTarget,
3319 TargetProcessHandle,
3320 Status);
3321 if (Target) ObDereferenceObject(Target);
3322 ObDereferenceObject(SourceProcess);
3323 return Status;
3324 }
3325
3326 #undef ObIsKernelHandle
3327 BOOLEAN
3328 NTAPI
3329 ObIsKernelHandle(IN HANDLE Handle)
3330 {
3331 /* We know we're kernel mode, so just check for the kernel handle flag */
3332 return (BOOLEAN)(((ULONG_PTR)Handle & KERNEL_HANDLE_FLAG) != 0);
3333 }
3334
3335 /* EOF */