[CMAKE]
[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 Status = STATUS_SUCCESS;
1756 }
1757 else
1758 {
1759 /* We failed, quit the critical region */
1760 KeLeaveCriticalRegion();
1761
1762 /* Detach */
1763 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1764
1765 /* Check if we have a valid handle that's not the process or thread */
1766 if ((Handle) &&
1767 (Handle != NtCurrentProcess()) &&
1768 (Handle != NtCurrentThread()))
1769 {
1770 /* Check if we came from user mode */
1771 if (AccessMode != KernelMode)
1772 {
1773 /* Check if we have no debug port */
1774 if (Process->DebugPort)
1775 {
1776 /* Make sure we're not attached */
1777 if (!KeIsAttachedProcess())
1778 {
1779 /* Raise an exception */
1780 return KeRaiseUserException(STATUS_INVALID_HANDLE);
1781 }
1782 }
1783 }
1784 else
1785 {
1786 /* This is kernel mode. Check if we're exiting */
1787 if (!(PsIsThreadTerminating(PsGetCurrentThread())) &&
1788 (Process->Peb))
1789 {
1790 /* Check if the debugger is enabled */
1791 if (KdDebuggerEnabled)
1792 {
1793 /* Bugcheck */
1794 KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 1, 0, 0);
1795 }
1796 }
1797 }
1798 }
1799
1800 /* Set invalid status */
1801 Status = STATUS_INVALID_HANDLE;
1802 }
1803
1804 /* Return status */
1805 OBTRACE(OB_HANDLE_DEBUG,
1806 "%s - Closed handle: %lx S: %lx\n",
1807 __FUNCTION__, Handle, Status);
1808 return Status;
1809 }
1810
1811 /*++
1812 * @name ObpSetHandleAttributes
1813 *
1814 * The ObpSetHandleAttributes routine <FILLMEIN>
1815 *
1816 * @param HandleTableEntry
1817 * <FILLMEIN>.
1818 *
1819 * @param Context
1820 * <FILLMEIN>.
1821 *
1822 * @return <FILLMEIN>.
1823 *
1824 * @remarks None.
1825 *
1826 *--*/
1827 BOOLEAN
1828 NTAPI
1829 ObpSetHandleAttributes(IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
1830 IN ULONG_PTR Context)
1831 {
1832 POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo = (PVOID)Context;
1833 POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1834
1835 /* Check if making the handle inheritable */
1836 if (SetHandleInfo->Information.Inherit)
1837 {
1838 /* Check if inheriting is not supported for this object */
1839 if (ObjectHeader->Type->TypeInfo.InvalidAttributes & OBJ_INHERIT)
1840 {
1841 /* Fail without changing anything */
1842 return FALSE;
1843 }
1844
1845 /* Set the flag */
1846 HandleTableEntry->ObAttributes |= OBJ_INHERIT;
1847 }
1848 else
1849 {
1850 /* Otherwise this implies we're removing the flag */
1851 HandleTableEntry->ObAttributes &= ~OBJ_INHERIT;
1852 }
1853
1854 /* Check if making the handle protected */
1855 if (SetHandleInfo->Information.ProtectFromClose)
1856 {
1857 /* Set the flag */
1858 HandleTableEntry->GrantedAccess |= ObpAccessProtectCloseBit;
1859 }
1860 else
1861 {
1862 /* Otherwise, remove it */
1863 HandleTableEntry->GrantedAccess &= ~ObpAccessProtectCloseBit;
1864 }
1865
1866 /* Return success */
1867 return TRUE;
1868 }
1869
1870 /*++
1871 * @name ObpCloseHandleCallback
1872 *
1873 * The ObpCloseHandleCallback routine <FILLMEIN>
1874 *
1875 * @param HandleTable
1876 * <FILLMEIN>.
1877 *
1878 * @param Object
1879 * <FILLMEIN>.
1880 *
1881 * @param GrantedAccess
1882 * <FILLMEIN>.
1883 *
1884 * @param Context
1885 * <FILLMEIN>.
1886 *
1887 * @return <FILLMEIN>.
1888 *
1889 * @remarks None.
1890 *
1891 *--*/
1892 BOOLEAN
1893 NTAPI
1894 ObpCloseHandleCallback(IN PHANDLE_TABLE_ENTRY HandleTableEntry,
1895 IN HANDLE Handle,
1896 IN PVOID Context)
1897 {
1898 POBP_CLOSE_HANDLE_CONTEXT CloseContext = (POBP_CLOSE_HANDLE_CONTEXT)Context;
1899
1900 /* Simply decrement the handle count */
1901 ObpCloseHandleTableEntry(CloseContext->HandleTable,
1902 HandleTableEntry,
1903 Handle,
1904 CloseContext->AccessMode,
1905 TRUE);
1906 return TRUE;
1907 }
1908
1909 /*++
1910 * @name ObpDuplicateHandleCallback
1911 *
1912 * The ObpDuplicateHandleCallback routine <FILLMEIN>
1913 *
1914 * @param HandleTable
1915 * <FILLMEIN>.
1916 *
1917 * @param HandleTableEntry
1918 * <FILLMEIN>.
1919 *
1920 * @param Context
1921 * <FILLMEIN>.
1922 *
1923 * @return <FILLMEIN>.
1924 *
1925 * @remarks None.
1926 *
1927 *--*/
1928 BOOLEAN
1929 NTAPI
1930 ObpDuplicateHandleCallback(IN PEPROCESS Process,
1931 IN PHANDLE_TABLE HandleTable,
1932 IN PHANDLE_TABLE_ENTRY OldEntry,
1933 IN PHANDLE_TABLE_ENTRY HandleTableEntry)
1934 {
1935 POBJECT_HEADER ObjectHeader;
1936 BOOLEAN Ret = FALSE;
1937 ACCESS_STATE AccessState;
1938 NTSTATUS Status;
1939 PAGED_CODE();
1940
1941 /* Make sure that the handle is inheritable */
1942 Ret = (HandleTableEntry->ObAttributes & OBJ_INHERIT) != 0;
1943 if (Ret)
1944 {
1945 /* Get the object header */
1946 ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1947
1948 /* Increment the pointer count */
1949 InterlockedIncrement(&ObjectHeader->PointerCount);
1950
1951 /* Release the handle lock */
1952 ExUnlockHandleTableEntry(HandleTable, OldEntry);
1953
1954 /* Setup the access state */
1955 AccessState.PreviouslyGrantedAccess = HandleTableEntry->GrantedAccess;
1956
1957 /* Call the shared routine for incrementing handles */
1958 Status = ObpIncrementHandleCount(&ObjectHeader->Body,
1959 &AccessState,
1960 KernelMode,
1961 HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES,
1962 Process,
1963 ObInheritHandle);
1964 if (!NT_SUCCESS(Status))
1965 {
1966 /* Return failure */
1967 ObDereferenceObject(&ObjectHeader->Body);
1968 Ret = FALSE;
1969 }
1970 }
1971 else
1972 {
1973 /* Release the handle lock */
1974 ExUnlockHandleTableEntry(HandleTable, OldEntry);
1975 }
1976
1977 /* Return duplication result */
1978 return Ret;
1979 }
1980
1981 VOID
1982 NTAPI
1983 ObClearProcessHandleTable(IN PEPROCESS Process)
1984 {
1985 /* FIXME */
1986 }
1987
1988 /*++
1989 * @name ObpCreateHandleTable
1990 *
1991 * The ObpCreateHandleTable routine <FILLMEIN>
1992 *
1993 * @param Parent
1994 * <FILLMEIN>.
1995 *
1996 * @param Process
1997 * <FILLMEIN>.
1998 *
1999 * @return <FILLMEIN>.
2000 *
2001 * @remarks None.
2002 *
2003 *--*/
2004 NTSTATUS
2005 NTAPI
2006 ObInitProcess(IN PEPROCESS Parent OPTIONAL,
2007 IN PEPROCESS Process)
2008 {
2009 PHANDLE_TABLE ParentTable, ObjectTable;
2010
2011 /* Check for a parent */
2012 if (Parent)
2013 {
2014 /* Reference the parent's table */
2015 ParentTable = ObReferenceProcessHandleTable(Parent);
2016 if (!ParentTable) return STATUS_PROCESS_IS_TERMINATING;
2017
2018 /* Duplicate it */
2019 ObjectTable = ExDupHandleTable(Process,
2020 ParentTable,
2021 ObpDuplicateHandleCallback,
2022 OBJ_INHERIT);
2023 }
2024 else
2025 {
2026 /* Otherwise just create a new table */
2027 ParentTable = NULL;
2028 ObjectTable = ExCreateHandleTable(Process);
2029 }
2030
2031 /* Make sure we have a table */
2032 if (ObjectTable)
2033 {
2034 /* Associate it */
2035 Process->ObjectTable = ObjectTable;
2036
2037 /* Check for auditing */
2038 if (SeDetailedAuditingWithToken(NULL))
2039 {
2040 /* FIXME: TODO */
2041 DPRINT1("Need auditing!\n");
2042 }
2043
2044 /* Get rid of the old table now */
2045 if (ParentTable) ObDereferenceProcessHandleTable(Parent);
2046
2047 /* We are done */
2048 return STATUS_SUCCESS;
2049 }
2050 else
2051 {
2052 /* Fail */
2053 Process->ObjectTable = NULL;
2054 if (ParentTable) ObDereferenceProcessHandleTable(Parent);
2055 return STATUS_INSUFFICIENT_RESOURCES;
2056 }
2057 }
2058
2059 /*++
2060 * @name ObKillProcess
2061 *
2062 * The ObKillProcess routine <FILLMEIN>
2063 *
2064 * @param Process
2065 * <FILLMEIN>.
2066 *
2067 * @return None.
2068 *
2069 * @remarks None.
2070 *
2071 *--*/
2072 VOID
2073 NTAPI
2074 ObKillProcess(IN PEPROCESS Process)
2075 {
2076 PHANDLE_TABLE HandleTable;
2077 OBP_CLOSE_HANDLE_CONTEXT Context;
2078 BOOLEAN HardErrors;
2079 PAGED_CODE();
2080
2081 /* Wait for process rundown and then complete it */
2082 ExWaitForRundownProtectionRelease(&Process->RundownProtect);
2083 ExRundownCompleted(&Process->RundownProtect);
2084
2085 /* Get the object table */
2086 HandleTable = Process->ObjectTable;
2087 if (!HandleTable) return;
2088
2089 /* Disable hard errors while we close handles */
2090 HardErrors = IoSetThreadHardErrorMode(FALSE);
2091
2092 /* Enter a critical region */
2093 KeEnterCriticalRegion();
2094
2095 /* Fill out the context */
2096 Context.AccessMode = KernelMode;
2097 Context.HandleTable = HandleTable;
2098
2099 /* Sweep the handle table to close all handles */
2100 ExSweepHandleTable(HandleTable,
2101 ObpCloseHandleCallback,
2102 &Context);
2103 ASSERT(HandleTable->HandleCount == 0);
2104
2105 /* Leave the critical region */
2106 KeLeaveCriticalRegion();
2107
2108 /* Re-enable hard errors */
2109 IoSetThreadHardErrorMode(HardErrors);
2110
2111 /* Destroy the object table */
2112 Process->ObjectTable = NULL;
2113 ExDestroyHandleTable(HandleTable, NULL);
2114 }
2115
2116 NTSTATUS
2117 NTAPI
2118 ObDuplicateObject(IN PEPROCESS SourceProcess,
2119 IN HANDLE SourceHandle,
2120 IN PEPROCESS TargetProcess OPTIONAL,
2121 IN PHANDLE TargetHandle OPTIONAL,
2122 IN ACCESS_MASK DesiredAccess,
2123 IN ULONG HandleAttributes,
2124 IN ULONG Options,
2125 IN KPROCESSOR_MODE PreviousMode)
2126 {
2127 HANDLE_TABLE_ENTRY NewHandleEntry;
2128 BOOLEAN AttachedToProcess = FALSE;
2129 PVOID SourceObject;
2130 POBJECT_HEADER ObjectHeader;
2131 POBJECT_TYPE ObjectType;
2132 HANDLE NewHandle;
2133 KAPC_STATE ApcState;
2134 NTSTATUS Status;
2135 ACCESS_MASK TargetAccess, SourceAccess;
2136 ACCESS_STATE AccessState;
2137 PACCESS_STATE PassedAccessState = NULL;
2138 AUX_ACCESS_DATA AuxData;
2139 PHANDLE_TABLE HandleTable;
2140 OBJECT_HANDLE_INFORMATION HandleInformation;
2141 ULONG AuditMask;
2142 PAGED_CODE();
2143 OBTRACE(OB_HANDLE_DEBUG,
2144 "%s - Duplicating handle: %lx for %p into %p\n",
2145 __FUNCTION__,
2146 SourceHandle,
2147 SourceProcess,
2148 TargetProcess);
2149
2150 /* Assume failure */
2151 if (TargetHandle) *TargetHandle = NULL;
2152
2153 /* Check if we're not duplicating the same access */
2154 if (!(Options & DUPLICATE_SAME_ACCESS))
2155 {
2156 /* Validate the desired access */
2157 Status = STATUS_SUCCESS; //ObpValidateDesiredAccess(DesiredAccess);
2158 if (!NT_SUCCESS(Status)) return Status;
2159 }
2160
2161 /* Reference the object table */
2162 HandleTable = ObReferenceProcessHandleTable(SourceProcess);
2163 if (!HandleTable) return STATUS_PROCESS_IS_TERMINATING;
2164
2165 /* Reference the process object */
2166 Status = ObpReferenceProcessObjectByHandle(SourceHandle,
2167 SourceProcess,
2168 HandleTable,
2169 PreviousMode,
2170 &SourceObject,
2171 &HandleInformation,
2172 &AuditMask);
2173 if (!NT_SUCCESS(Status))
2174 {
2175 /* Fail */
2176 ObDereferenceProcessHandleTable(SourceProcess);
2177 return Status;
2178 }
2179 else
2180 {
2181 /* Check if we have to don't have to audit object close */
2182 if (!(HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE))
2183 {
2184 /* Then there is no audit mask */
2185 AuditMask = 0;
2186 }
2187 }
2188
2189 /* Check if there's no target process */
2190 if (!TargetProcess)
2191 {
2192 /* Check if the caller wanted actual duplication */
2193 if (!(Options & DUPLICATE_CLOSE_SOURCE))
2194 {
2195 /* Invalid request */
2196 Status = STATUS_INVALID_PARAMETER;
2197 }
2198 else
2199 {
2200 /* Otherwise, do the attach */
2201 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2202
2203 /* Close the handle and detach */
2204 NtClose(SourceHandle);
2205 KeUnstackDetachProcess(&ApcState);
2206 }
2207
2208 /* Return */
2209 ObDereferenceProcessHandleTable(SourceProcess);
2210 ObDereferenceObject(SourceObject);
2211 return Status;
2212 }
2213
2214 /* Get the target handle table */
2215 HandleTable = ObReferenceProcessHandleTable(TargetProcess);
2216 if (!HandleTable)
2217 {
2218 /* Check if the caller wanted us to close the handle */
2219 if (Options & DUPLICATE_CLOSE_SOURCE)
2220 {
2221 /* Do the attach */
2222 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2223
2224 /* Close the handle and detach */
2225 NtClose(SourceHandle);
2226 KeUnstackDetachProcess(&ApcState);
2227 }
2228
2229 /* Return */
2230 ObDereferenceProcessHandleTable(SourceProcess);
2231 ObDereferenceObject(SourceObject);
2232 return STATUS_PROCESS_IS_TERMINATING;
2233 }
2234
2235 /* Get the source access */
2236 SourceAccess = HandleInformation.GrantedAccess;
2237
2238 /* Check if we're not in the target process */
2239 if (TargetProcess != PsGetCurrentProcess())
2240 {
2241 /* Attach to it */
2242 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
2243 AttachedToProcess = TRUE;
2244 }
2245
2246 /* Check if we're duplicating the attributes */
2247 if (Options & DUPLICATE_SAME_ATTRIBUTES)
2248 {
2249 /* Duplicate them */
2250 HandleAttributes = HandleInformation.HandleAttributes;
2251 }
2252 else
2253 {
2254 /* Don't allow caller to bypass auditing */
2255 HandleAttributes |= HandleInformation.HandleAttributes &
2256 OBJ_AUDIT_OBJECT_CLOSE;
2257 }
2258
2259 /* Check if we're duplicating the access */
2260 if (Options & DUPLICATE_SAME_ACCESS) DesiredAccess = SourceAccess;
2261
2262 /* Get object data */
2263 ObjectHeader = OBJECT_TO_OBJECT_HEADER(SourceObject);
2264 ObjectType = ObjectHeader->Type;
2265
2266 /* Fill out the entry */
2267 RtlZeroMemory(&NewHandleEntry, sizeof(HANDLE_TABLE_ENTRY));
2268 NewHandleEntry.Object = ObjectHeader;
2269 NewHandleEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
2270
2271 /* Check if we're using a generic mask */
2272 if (DesiredAccess & GENERIC_ACCESS)
2273 {
2274 /* Map it */
2275 RtlMapGenericMask(&DesiredAccess,
2276 &ObjectType->TypeInfo.GenericMapping);
2277 }
2278
2279 /* Set the target access, always propagate ACCESS_SYSTEM_SECURITY */
2280 TargetAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
2281 ACCESS_SYSTEM_SECURITY);
2282 NewHandleEntry.GrantedAccess = TargetAccess;
2283
2284 /* Check if we're asking for new access */
2285 if (TargetAccess & ~SourceAccess)
2286 {
2287 /* We are. We need the security procedure to validate this */
2288 if (ObjectType->TypeInfo.SecurityProcedure == SeDefaultObjectMethod)
2289 {
2290 /* Use our built-in access state */
2291 PassedAccessState = &AccessState;
2292 Status = SeCreateAccessState(&AccessState,
2293 &AuxData,
2294 TargetAccess,
2295 &ObjectType->TypeInfo.GenericMapping);
2296 }
2297 else
2298 {
2299 /* Otherwise we can't allow this privilege elevation */
2300 Status = STATUS_ACCESS_DENIED;
2301 }
2302 }
2303 else
2304 {
2305 /* We don't need an access state */
2306 Status = STATUS_SUCCESS;
2307 }
2308
2309 /* Make sure the access state was created OK */
2310 if (NT_SUCCESS(Status))
2311 {
2312 /* Add a new handle */
2313 Status = ObpIncrementHandleCount(SourceObject,
2314 PassedAccessState,
2315 PreviousMode,
2316 HandleAttributes,
2317 PsGetCurrentProcess(),
2318 ObDuplicateHandle);
2319 }
2320
2321 /* Check if we were attached */
2322 if (AttachedToProcess)
2323 {
2324 /* We can safely detach now */
2325 KeUnstackDetachProcess(&ApcState);
2326 AttachedToProcess = FALSE;
2327 }
2328
2329 /* Check if we have to close the source handle */
2330 if (Options & DUPLICATE_CLOSE_SOURCE)
2331 {
2332 /* Attach and close */
2333 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2334 NtClose(SourceHandle);
2335 KeUnstackDetachProcess(&ApcState);
2336 }
2337
2338 /* Check if we had an access state */
2339 if (PassedAccessState) SeDeleteAccessState(PassedAccessState);
2340
2341 /* Now check if incrementing actually failed */
2342 if (!NT_SUCCESS(Status))
2343 {
2344 /* Dereference handle tables */
2345 ObDereferenceProcessHandleTable(SourceProcess);
2346 ObDereferenceProcessHandleTable(TargetProcess);
2347
2348 /* Dereference the source object */
2349 ObDereferenceObject(SourceObject);
2350 return Status;
2351 }
2352
2353 /* Now create the handle */
2354 NewHandle = ExCreateHandle(HandleTable, &NewHandleEntry);
2355 if (!NewHandle)
2356 {
2357 /* Undo the increment */
2358 ObpDecrementHandleCount(SourceObject,
2359 TargetProcess,
2360 TargetAccess,
2361 ObjectType);
2362
2363 /* Deference the object and set failure status */
2364 ObDereferenceObject(SourceObject);
2365 Status = STATUS_INSUFFICIENT_RESOURCES;
2366 }
2367
2368 /* Return the handle */
2369 if (TargetHandle) *TargetHandle = NewHandle;
2370
2371 /* Dereference handle tables */
2372 ObDereferenceProcessHandleTable(SourceProcess);
2373 ObDereferenceProcessHandleTable(TargetProcess);
2374
2375 /* Return status */
2376 OBTRACE(OB_HANDLE_DEBUG,
2377 "%s - Duplicated handle: %lx for %p into %p. Source: %p HC PC %lx %lx\n",
2378 __FUNCTION__,
2379 NewHandle,
2380 SourceProcess,
2381 TargetProcess,
2382 SourceObject,
2383 ObjectHeader->PointerCount,
2384 ObjectHeader->HandleCount);
2385 return Status;
2386 }
2387
2388 /* PUBLIC FUNCTIONS *********************************************************/
2389
2390 /*++
2391 * @name ObOpenObjectByName
2392 * @implemented NT4
2393 *
2394 * The ObOpenObjectByName routine <FILLMEIN>
2395 *
2396 * @param ObjectAttributes
2397 * <FILLMEIN>.
2398 *
2399 * @param ObjectType
2400 * <FILLMEIN>.
2401 *
2402 * @param AccessMode
2403 * <FILLMEIN>.
2404 *
2405 * @param PassedAccessState
2406 * <FILLMEIN>.
2407 *
2408 * @param DesiredAccess
2409 * <FILLMEIN>.
2410 *
2411 * @param ParseContext
2412 * <FILLMEIN>.
2413 *
2414 * @param Handle
2415 * <FILLMEIN>.
2416 *
2417 * @return <FILLMEIN>.
2418 *
2419 * @remarks None.
2420 *
2421 *--*/
2422 NTSTATUS
2423 NTAPI
2424 ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
2425 IN POBJECT_TYPE ObjectType,
2426 IN KPROCESSOR_MODE AccessMode,
2427 IN PACCESS_STATE PassedAccessState,
2428 IN ACCESS_MASK DesiredAccess,
2429 IN OUT PVOID ParseContext,
2430 OUT PHANDLE Handle)
2431 {
2432 PVOID Object = NULL;
2433 UNICODE_STRING ObjectName;
2434 NTSTATUS Status;
2435 POBJECT_HEADER ObjectHeader;
2436 PGENERIC_MAPPING GenericMapping = NULL;
2437 OB_OPEN_REASON OpenReason;
2438 POB_TEMP_BUFFER TempBuffer;
2439 PAGED_CODE();
2440
2441 /* Assume failure */
2442 *Handle = NULL;
2443
2444 /* Check if we didn't get any Object Attributes */
2445 if (!ObjectAttributes)
2446 {
2447 /* Fail with special status code */
2448 return STATUS_INVALID_PARAMETER;
2449 }
2450
2451 /* Allocate the temporary buffer */
2452 TempBuffer = ExAllocatePoolWithTag(NonPagedPool,
2453 sizeof(OB_TEMP_BUFFER),
2454 TAG_OB_TEMP_STORAGE);
2455 if (!TempBuffer) return STATUS_INSUFFICIENT_RESOURCES;
2456
2457 /* Capture all the info */
2458 Status = ObpCaptureObjectCreateInformation(ObjectAttributes,
2459 AccessMode,
2460 TRUE,
2461 &TempBuffer->ObjectCreateInfo,
2462 &ObjectName);
2463 if (!NT_SUCCESS(Status))
2464 {
2465 /* Fail */
2466 ExFreePoolWithTag(TempBuffer, TAG_OB_TEMP_STORAGE);
2467 return Status;
2468 }
2469
2470 /* Check if we didn't get an access state */
2471 if (!PassedAccessState)
2472 {
2473 /* Try to get the generic mapping if we can */
2474 if (ObjectType) GenericMapping = &ObjectType->TypeInfo.GenericMapping;
2475
2476 /* Use our built-in access state */
2477 PassedAccessState = &TempBuffer->LocalAccessState;
2478 Status = SeCreateAccessState(&TempBuffer->LocalAccessState,
2479 &TempBuffer->AuxData,
2480 DesiredAccess,
2481 GenericMapping);
2482 if (!NT_SUCCESS(Status)) goto Quickie;
2483 }
2484
2485 /* Get the security descriptor */
2486 if (TempBuffer->ObjectCreateInfo.SecurityDescriptor)
2487 {
2488 /* Save it in the access state */
2489 PassedAccessState->SecurityDescriptor =
2490 TempBuffer->ObjectCreateInfo.SecurityDescriptor;
2491 }
2492
2493 /* Now do the lookup */
2494 Status = ObpLookupObjectName(TempBuffer->ObjectCreateInfo.RootDirectory,
2495 &ObjectName,
2496 TempBuffer->ObjectCreateInfo.Attributes,
2497 ObjectType,
2498 AccessMode,
2499 ParseContext,
2500 TempBuffer->ObjectCreateInfo.SecurityQos,
2501 NULL,
2502 PassedAccessState,
2503 &TempBuffer->LookupContext,
2504 &Object);
2505 if (!NT_SUCCESS(Status))
2506 {
2507 /* Cleanup after lookup */
2508 ObpReleaseLookupContext(&TempBuffer->LookupContext);
2509 goto Cleanup;
2510 }
2511
2512 /* Check if this object has create information */
2513 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2514 if (ObjectHeader->Flags & OB_FLAG_CREATE_INFO)
2515 {
2516 /* Then we are creating a new handle */
2517 OpenReason = ObCreateHandle;
2518
2519 /* Check if we still have create info */
2520 if (ObjectHeader->ObjectCreateInfo)
2521 {
2522 /* Free it */
2523 ObpFreeObjectCreateInformation(ObjectHeader->
2524 ObjectCreateInfo);
2525 ObjectHeader->ObjectCreateInfo = NULL;
2526 }
2527 }
2528 else
2529 {
2530 /* Otherwise, we are merely opening it */
2531 OpenReason = ObOpenHandle;
2532 }
2533
2534 /* Check if we have invalid object attributes */
2535 if (ObjectHeader->Type->TypeInfo.InvalidAttributes &
2536 TempBuffer->ObjectCreateInfo.Attributes)
2537 {
2538 /* Set failure code */
2539 Status = STATUS_INVALID_PARAMETER;
2540
2541 /* Cleanup after lookup */
2542 ObpReleaseLookupContext(&TempBuffer->LookupContext);
2543
2544 /* Dereference the object */
2545 ObDereferenceObject(Object);
2546 }
2547 else
2548 {
2549 /* Create the actual handle now */
2550 Status = ObpCreateHandle(OpenReason,
2551 Object,
2552 ObjectType,
2553 PassedAccessState,
2554 0,
2555 TempBuffer->ObjectCreateInfo.Attributes,
2556 &TempBuffer->LookupContext,
2557 AccessMode,
2558 NULL,
2559 Handle);
2560 if (!NT_SUCCESS(Status)) ObDereferenceObject(Object);
2561 }
2562
2563 Cleanup:
2564 /* Delete the access state */
2565 if (PassedAccessState == &TempBuffer->LocalAccessState)
2566 {
2567 SeDeleteAccessState(PassedAccessState);
2568 }
2569
2570 Quickie:
2571 /* Release the object attributes and temporary buffer */
2572 ObpReleaseObjectCreateInformation(&TempBuffer->ObjectCreateInfo);
2573 if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
2574 ExFreePoolWithTag(TempBuffer, TAG_OB_TEMP_STORAGE);
2575
2576 /* Return status */
2577 OBTRACE(OB_HANDLE_DEBUG,
2578 "%s - returning Object %p with PC S: %lx %lx\n",
2579 __FUNCTION__,
2580 Object,
2581 Object ? OBJECT_TO_OBJECT_HEADER(Object)->PointerCount : -1,
2582 Status);
2583 return Status;
2584 }
2585
2586 /*++
2587 * @name ObOpenObjectByPointer
2588 * @implemented NT4
2589 *
2590 * The ObOpenObjectByPointer routine <FILLMEIN>
2591 *
2592 * @param Object
2593 * <FILLMEIN>.
2594 *
2595 * @param HandleAttributes
2596 * <FILLMEIN>.
2597 *
2598 * @param PassedAccessState
2599 * <FILLMEIN>.
2600 *
2601 * @param DesiredAccess
2602 * <FILLMEIN>.
2603 *
2604 * @param ObjectType
2605 * <FILLMEIN>.
2606 *
2607 * @param AccessMode
2608 * <FILLMEIN>.
2609 *
2610 * @param Handle
2611 * <FILLMEIN>.
2612 *
2613 * @return <FILLMEIN>.
2614 *
2615 * @remarks None.
2616 *
2617 *--*/
2618 NTSTATUS
2619 NTAPI
2620 ObOpenObjectByPointer(IN PVOID Object,
2621 IN ULONG HandleAttributes,
2622 IN PACCESS_STATE PassedAccessState,
2623 IN ACCESS_MASK DesiredAccess,
2624 IN POBJECT_TYPE ObjectType,
2625 IN KPROCESSOR_MODE AccessMode,
2626 OUT PHANDLE Handle)
2627 {
2628 POBJECT_HEADER Header;
2629 NTSTATUS Status;
2630 ACCESS_STATE AccessState;
2631 AUX_ACCESS_DATA AuxData;
2632 PAGED_CODE();
2633
2634 /* Assume failure */
2635 *Handle = NULL;
2636
2637 /* Reference the object */
2638 Status = ObReferenceObjectByPointer(Object,
2639 0,
2640 ObjectType,
2641 AccessMode);
2642 if (!NT_SUCCESS(Status)) return Status;
2643
2644 /* Get the Header Info */
2645 Header = OBJECT_TO_OBJECT_HEADER(Object);
2646
2647 /* Check if we didn't get an access state */
2648 if (!PassedAccessState)
2649 {
2650 /* Use our built-in access state */
2651 PassedAccessState = &AccessState;
2652 Status = SeCreateAccessState(&AccessState,
2653 &AuxData,
2654 DesiredAccess,
2655 &Header->Type->TypeInfo.GenericMapping);
2656 if (!NT_SUCCESS(Status))
2657 {
2658 /* Fail */
2659 ObDereferenceObject(Object);
2660 return Status;
2661 }
2662 }
2663
2664 /* Check if we have invalid object attributes */
2665 if (Header->Type->TypeInfo.InvalidAttributes & HandleAttributes)
2666 {
2667 /* Delete the access state */
2668 if (PassedAccessState == &AccessState)
2669 {
2670 SeDeleteAccessState(PassedAccessState);
2671 }
2672
2673 /* Dereference the object */
2674 ObDereferenceObject(Object);
2675 return STATUS_INVALID_PARAMETER;
2676 }
2677
2678 /* Create the handle */
2679 Status = ObpCreateHandle(ObOpenHandle,
2680 Object,
2681 ObjectType,
2682 PassedAccessState,
2683 0,
2684 HandleAttributes,
2685 NULL,
2686 AccessMode,
2687 NULL,
2688 Handle);
2689 if (!NT_SUCCESS(Status)) ObDereferenceObject(Object);
2690
2691 /* Delete the access state */
2692 if (PassedAccessState == &AccessState)
2693 {
2694 SeDeleteAccessState(PassedAccessState);
2695 }
2696
2697 /* Return */
2698 OBTRACE(OB_HANDLE_DEBUG,
2699 "%s - returning Object with PC S: %lx %lx\n",
2700 __FUNCTION__,
2701 OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
2702 Status);
2703 return Status;
2704 }
2705
2706 /*++
2707 * @name ObFindHandleForObject
2708 * @implemented NT4
2709 *
2710 * The ObFindHandleForObject routine <FILLMEIN>
2711 *
2712 * @param Process
2713 * <FILLMEIN>.
2714 *
2715 * @param Object
2716 * <FILLMEIN>.
2717 *
2718 * @param ObjectType
2719 * <FILLMEIN>.
2720 *
2721 * @param HandleInformation
2722 * <FILLMEIN>.
2723 *
2724 * @param HandleReturn
2725 * <FILLMEIN>.
2726 *
2727 * @return <FILLMEIN>.
2728 *
2729 * @remarks None.
2730 *
2731 *--*/
2732 BOOLEAN
2733 NTAPI
2734 ObFindHandleForObject(IN PEPROCESS Process,
2735 IN PVOID Object,
2736 IN POBJECT_TYPE ObjectType,
2737 IN POBJECT_HANDLE_INFORMATION HandleInformation,
2738 OUT PHANDLE Handle)
2739 {
2740 OBP_FIND_HANDLE_DATA FindData;
2741 BOOLEAN Result = FALSE;
2742 PVOID ObjectTable;
2743
2744 /* Make sure we have an object table */
2745 ObjectTable = ObReferenceProcessHandleTable(Process);
2746 if (ObjectTable)
2747 {
2748 /* Check if we have an object */
2749 if (Object)
2750 {
2751 /* Set its header */
2752 FindData.ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2753 }
2754 else
2755 {
2756 /* Otherwise, no object to match*/
2757 FindData.ObjectHeader = NULL;
2758 }
2759
2760 /* Set other information */
2761 FindData.ObjectType = ObjectType;
2762 FindData.HandleInformation = HandleInformation;
2763
2764 /* Enumerate the handle table */
2765 if (ExEnumHandleTable(Process->ObjectTable,
2766 ObpEnumFindHandleProcedure,
2767 &FindData,
2768 Handle))
2769 {
2770 /* Set success */
2771 Result = TRUE;
2772 }
2773
2774 /* Let go of the table */
2775 ObDereferenceProcessHandleTable(Process);
2776 }
2777
2778 /* Return the result */
2779 return Result;
2780 }
2781
2782 /*++
2783 * @name ObInsertObject
2784 * @implemented NT4
2785 *
2786 * The ObInsertObject routine <FILLMEIN>
2787 *
2788 * @param Object
2789 * <FILLMEIN>.
2790 *
2791 * @param PassedAccessState
2792 * <FILLMEIN>.
2793 *
2794 * @param DesiredAccess
2795 * <FILLMEIN>.
2796 *
2797 * @param AdditionalReferences
2798 * <FILLMEIN>.
2799 *
2800 * @param ReferencedObject
2801 * <FILLMEIN>.
2802 *
2803 * @param Handle
2804 * <FILLMEIN>.
2805 *
2806 * @return <FILLMEIN>.
2807 *
2808 * @remarks None.
2809 *
2810 *--*/
2811 NTSTATUS
2812 NTAPI
2813 ObInsertObject(IN PVOID Object,
2814 IN PACCESS_STATE AccessState OPTIONAL,
2815 IN ACCESS_MASK DesiredAccess,
2816 IN ULONG ObjectPointerBias,
2817 OUT PVOID *NewObject OPTIONAL,
2818 OUT PHANDLE Handle)
2819 {
2820 POBJECT_CREATE_INFORMATION ObjectCreateInfo;
2821 POBJECT_HEADER ObjectHeader;
2822 POBJECT_TYPE ObjectType;
2823 PUNICODE_STRING ObjectName;
2824 PVOID InsertObject;
2825 PSECURITY_DESCRIPTOR ParentDescriptor = NULL;
2826 BOOLEAN SdAllocated = FALSE;
2827 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
2828 OBP_LOOKUP_CONTEXT Context;
2829 ACCESS_STATE LocalAccessState;
2830 AUX_ACCESS_DATA AuxData;
2831 OB_OPEN_REASON OpenReason;
2832 KPROCESSOR_MODE PreviousMode;
2833 NTSTATUS Status = STATUS_SUCCESS, RealStatus;
2834 BOOLEAN IsNewObject;
2835 PAGED_CODE();
2836
2837 /* Get the Header */
2838 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2839
2840 /* Detect invalid insert */
2841 if (!(ObjectHeader->Flags & OB_FLAG_CREATE_INFO))
2842 {
2843 /* Display warning and break into debugger */
2844 DPRINT1("OB: Attempting to insert existing object %08x\n", Object);
2845 DbgBreakPoint();
2846
2847 /* Allow debugger to continue */
2848 ObDereferenceObject(Object);
2849 return STATUS_INVALID_PARAMETER;
2850 }
2851
2852 /* Get the create and name info, as well as the object type */
2853 ObjectCreateInfo = ObjectHeader->ObjectCreateInfo;
2854 ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
2855 ObjectType = ObjectHeader->Type;
2856 ObjectName = NULL;
2857
2858 /* Check if this is an named object */
2859 if ((ObjectNameInfo) && (ObjectNameInfo->Name.Buffer))
2860 {
2861 /* Get the object name */
2862 ObjectName = &ObjectNameInfo->Name;
2863 }
2864
2865 /* Sanity check */
2866 ASSERT((Handle) ||
2867 ((ObjectPointerBias == 0) &&
2868 (ObjectName == NULL) &&
2869 (ObjectType->TypeInfo.SecurityRequired) &&
2870 (NewObject == NULL)));
2871
2872 /* Check if the object is unnamed and also doesn't have security */
2873 PreviousMode = KeGetPreviousMode();
2874 if (!(ObjectType->TypeInfo.SecurityRequired) && !(ObjectName))
2875 {
2876 /* Assume failure */
2877 *Handle = NULL;
2878 ObjectHeader->ObjectCreateInfo = NULL;
2879
2880 /* Create the handle */
2881 Status = ObpCreateUnnamedHandle(Object,
2882 DesiredAccess,
2883 ObjectPointerBias + 1,
2884 ObjectCreateInfo->Attributes,
2885 PreviousMode,
2886 NewObject,
2887 Handle);
2888
2889 /* Free the create information */
2890 ObpFreeObjectCreateInformation(ObjectCreateInfo);
2891
2892 /* Release the object name information */
2893 ObpDereferenceNameInfo(ObjectNameInfo);
2894
2895 /* Remove the extra keep-alive reference */
2896 ObDereferenceObject(Object);
2897
2898 /* Return */
2899 OBTRACE(OB_HANDLE_DEBUG,
2900 "%s - returning Object with PC S: %lx %lx\n",
2901 __FUNCTION__,
2902 ObjectHeader->PointerCount,
2903 Status);
2904 return Status;
2905 }
2906
2907 /* Check if we didn't get an access state */
2908 if (!AccessState)
2909 {
2910 /* Use our built-in access state */
2911 AccessState = &LocalAccessState;
2912 Status = SeCreateAccessState(&LocalAccessState,
2913 &AuxData,
2914 DesiredAccess,
2915 &ObjectType->TypeInfo.GenericMapping);
2916 if (!NT_SUCCESS(Status))
2917 {
2918 /* Fail */
2919 ObpDereferenceNameInfo(ObjectNameInfo);
2920 ObDereferenceObject(Object);
2921 return Status;
2922 }
2923 }
2924
2925 /* Save the security descriptor */
2926 AccessState->SecurityDescriptor = ObjectCreateInfo->SecurityDescriptor;
2927
2928 /* Validate the access mask */
2929 Status = ObpValidateAccessMask(AccessState);
2930 if (!NT_SUCCESS(Status))
2931 {
2932 /* Fail */
2933 ObpDereferenceNameInfo(ObjectNameInfo);
2934 ObDereferenceObject(Object);
2935 return Status;
2936 }
2937
2938 /* Setup a lookup context */
2939 ObpInitializeLookupContext(&Context);
2940 InsertObject = Object;
2941 OpenReason = ObCreateHandle;
2942
2943 /* Check if the object is named */
2944 if (ObjectName)
2945 {
2946 /* Look it up */
2947 Status = ObpLookupObjectName(ObjectCreateInfo->RootDirectory,
2948 ObjectName,
2949 ObjectCreateInfo->Attributes,
2950 ObjectType,
2951 (ObjectHeader->Flags & OB_FLAG_KERNEL_MODE) ?
2952 KernelMode : UserMode,
2953 ObjectCreateInfo->ParseContext,
2954 ObjectCreateInfo->SecurityQos,
2955 Object,
2956 AccessState,
2957 &Context,
2958 &InsertObject);
2959
2960 /* Check if we found an object that doesn't match the one requested */
2961 if ((NT_SUCCESS(Status)) && (InsertObject) && (Object != InsertObject))
2962 {
2963 /* This means we're opening an object, not creating a new one */
2964 OpenReason = ObOpenHandle;
2965
2966 /* Make sure the caller said it's OK to do this */
2967 if (ObjectCreateInfo->Attributes & OBJ_OPENIF)
2968 {
2969 /* He did, but did he want this type? */
2970 if (ObjectType != OBJECT_TO_OBJECT_HEADER(InsertObject)->Type)
2971 {
2972 /* Wrong type, so fail */
2973 Status = STATUS_OBJECT_TYPE_MISMATCH;
2974 }
2975 else
2976 {
2977 /* Right type, so warn */
2978 Status = STATUS_OBJECT_NAME_EXISTS;
2979 }
2980 }
2981 else
2982 {
2983 /* Check if this was a symbolic link */
2984 if (OBJECT_TO_OBJECT_HEADER(InsertObject)->Type ==
2985 ObSymbolicLinkType)
2986 {
2987 /* Dereference it */
2988 ObDereferenceObject(InsertObject);
2989 }
2990
2991 /* Caller wanted to create a new object, fail */
2992 Status = STATUS_OBJECT_NAME_COLLISION;
2993 }
2994 }
2995
2996 /* Check if anything until now failed */
2997 if (!NT_SUCCESS(Status))
2998 {
2999 /* Cleanup after lookup */
3000 ObpReleaseLookupContext(&Context);
3001
3002 /* Remove query reference that we added */
3003 ObpDereferenceNameInfo(ObjectNameInfo);
3004
3005 /* Dereference the object and delete the access state */
3006 ObDereferenceObject(Object);
3007 if (AccessState == &LocalAccessState)
3008 {
3009 /* We used a local one; delete it */
3010 SeDeleteAccessState(AccessState);
3011 }
3012
3013 /* Return failure code */
3014 return Status;
3015 }
3016 else
3017 {
3018 /* Check if this is a symbolic link */
3019 if (ObjectType == ObSymbolicLinkType)
3020 {
3021 /* Create the internal name */
3022 ObpCreateSymbolicLinkName(Object);
3023 }
3024 }
3025 }
3026
3027 /* Now check if this object is being created */
3028 if (InsertObject == Object)
3029 {
3030 /* Check if it's named or forces security */
3031 if ((ObjectName) || (ObjectType->TypeInfo.SecurityRequired))
3032 {
3033 /* Make sure it's inserted into an object directory */
3034 if ((ObjectNameInfo) && (ObjectNameInfo->Directory))
3035 {
3036 /* Get the current descriptor */
3037 ObGetObjectSecurity(ObjectNameInfo->Directory,
3038 &ParentDescriptor,
3039 &SdAllocated);
3040 }
3041
3042 /* Now assign it */
3043 Status = ObAssignSecurity(AccessState,
3044 ParentDescriptor,
3045 Object,
3046 ObjectType);
3047
3048 /* Check if we captured one */
3049 if (ParentDescriptor)
3050 {
3051 /* We did, release it */
3052 ObReleaseObjectSecurity(ParentDescriptor, SdAllocated);
3053 }
3054 else if (NT_SUCCESS(Status))
3055 {
3056 /* Other we didn't, but we were able to use the current SD */
3057 SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor,
3058 ObjectCreateInfo->ProbeMode,
3059 TRUE);
3060
3061 /* Clear the current one */
3062 AccessState->SecurityDescriptor =
3063 ObjectCreateInfo->SecurityDescriptor = NULL;
3064 }
3065 }
3066
3067 /* Check if anything until now failed */
3068 if (!NT_SUCCESS(Status))
3069 {
3070 /* Check if the directory was added */
3071 if (Context.DirectoryLocked)
3072 {
3073 /* Weird case where we need to do a manual delete */
3074 DPRINT1("Unhandled path\n");
3075 ASSERT(FALSE);
3076 }
3077
3078 /* Cleanup the lookup */
3079 ObpReleaseLookupContext(&Context);
3080
3081 /* Remove query reference that we added */
3082 ObpDereferenceNameInfo(ObjectNameInfo);
3083
3084 /* Dereference the object and delete the access state */
3085 ObDereferenceObject(Object);
3086 if (AccessState == &LocalAccessState)
3087 {
3088 /* We used a local one; delete it */
3089 SeDeleteAccessState(AccessState);
3090 }
3091
3092 /* Return failure code */
3093 ASSERT(FALSE);
3094 return Status;
3095 }
3096 }
3097
3098 /* Save the actual status until here */
3099 RealStatus = Status;
3100
3101 /* Check if caller wants us to create a handle */
3102 ObjectHeader->ObjectCreateInfo = NULL;
3103 if (Handle)
3104 {
3105 /* Create the handle */
3106 Status = ObpCreateHandle(OpenReason,
3107 InsertObject,
3108 NULL,
3109 AccessState,
3110 ObjectPointerBias + 1,
3111 ObjectCreateInfo->Attributes,
3112 &Context,
3113 PreviousMode,
3114 NewObject,
3115 Handle);
3116 if (!NT_SUCCESS(Status))
3117 {
3118 /* If the object had a name, backout everything */
3119 if (ObjectName) ObpDeleteNameCheck(Object);
3120
3121 /* Return the status of the failure */
3122 *Handle = NULL;
3123 RealStatus = Status;
3124 }
3125
3126 /* Remove a query reference */
3127 ObpDereferenceNameInfo(ObjectNameInfo);
3128
3129 /* Remove the extra keep-alive reference */
3130 ObDereferenceObject(Object);
3131 }
3132 else
3133 {
3134 /* Otherwise, lock the object */
3135 ObpAcquireObjectLock(ObjectHeader);
3136
3137 /* And charge quota for the process to make it appear as used */
3138 RealStatus = ObpChargeQuotaForObject(ObjectHeader,
3139 ObjectType,
3140 &IsNewObject);
3141
3142 /* Release the lock */
3143 ObpReleaseObjectLock(ObjectHeader);
3144
3145 /* Check if we failed and dereference the object if so */
3146 if (!NT_SUCCESS(RealStatus)) ObDereferenceObject(Object);
3147 }
3148
3149 /* We can delete the Create Info now */
3150 ObpFreeObjectCreateInformation(ObjectCreateInfo);
3151
3152 /* Check if we created our own access state and delete it if so */
3153 if (AccessState == &LocalAccessState) SeDeleteAccessState(AccessState);
3154
3155 /* Return status code */
3156 OBTRACE(OB_HANDLE_DEBUG,
3157 "%s - returning Object with PC RS/S: %lx %lx %lx\n",
3158 __FUNCTION__,
3159 OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
3160 RealStatus, Status);
3161 return RealStatus;
3162 }
3163
3164 /*++
3165 * @name ObCloseHandle
3166 * @implemented NT5.1
3167 *
3168 * The ObCloseHandle routine <FILLMEIN>
3169 *
3170 * @param Handle
3171 * <FILLMEIN>.
3172 *
3173 * @param AccessMode
3174 * <FILLMEIN>.
3175 *
3176 * @return <FILLMEIN>.
3177 *
3178 * @remarks None.
3179 *
3180 *--*/
3181 NTSTATUS
3182 NTAPI
3183 ObCloseHandle(IN HANDLE Handle,
3184 IN KPROCESSOR_MODE AccessMode)
3185 {
3186 /* Call the internal API */
3187 return ObpCloseHandle(Handle, AccessMode);
3188 }
3189
3190 /*++
3191 * @name NtClose
3192 * @implemented NT4
3193 *
3194 * The NtClose routine <FILLMEIN>
3195 *
3196 * @param Handle
3197 * <FILLMEIN>.
3198 *
3199 * @return <FILLMEIN>.
3200 *
3201 * @remarks None.
3202 *
3203 *--*/
3204 NTSTATUS
3205 NTAPI
3206 NtClose(IN HANDLE Handle)
3207 {
3208 /* Call the internal API */
3209 return ObpCloseHandle(Handle, ExGetPreviousMode());
3210 }
3211
3212 NTSTATUS
3213 NTAPI
3214 NtDuplicateObject(IN HANDLE SourceProcessHandle,
3215 IN HANDLE SourceHandle,
3216 IN HANDLE TargetProcessHandle OPTIONAL,
3217 OUT PHANDLE TargetHandle OPTIONAL,
3218 IN ACCESS_MASK DesiredAccess,
3219 IN ULONG HandleAttributes,
3220 IN ULONG Options)
3221 {
3222 PEPROCESS SourceProcess, TargetProcess, Target;
3223 HANDLE hTarget;
3224 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
3225 NTSTATUS Status;
3226 OBTRACE(OB_HANDLE_DEBUG,
3227 "%s - Duplicating handle: %lx for %lx into %lx.\n",
3228 __FUNCTION__,
3229 SourceHandle,
3230 SourceProcessHandle,
3231 TargetProcessHandle);
3232
3233 /* Check if we have a target handle */
3234 if ((TargetHandle) && (PreviousMode != KernelMode))
3235 {
3236 /* Enter SEH */
3237 _SEH2_TRY
3238 {
3239 /* Probe the handle and assume failure */
3240 ProbeForWriteHandle(TargetHandle);
3241 *TargetHandle = NULL;
3242 }
3243 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3244 {
3245 /* Return the exception code */
3246 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3247 }
3248 _SEH2_END;
3249 }
3250
3251 /* Now reference the input handle */
3252 Status = ObReferenceObjectByHandle(SourceProcessHandle,
3253 PROCESS_DUP_HANDLE,
3254 PsProcessType,
3255 PreviousMode,
3256 (PVOID*)&SourceProcess,
3257 NULL);
3258 if (!NT_SUCCESS(Status)) return(Status);
3259
3260 /* Check if got a target handle */
3261 if (TargetProcessHandle)
3262 {
3263 /* Now reference the output handle */
3264 Status = ObReferenceObjectByHandle(TargetProcessHandle,
3265 PROCESS_DUP_HANDLE,
3266 PsProcessType,
3267 PreviousMode,
3268 (PVOID*)&TargetProcess,
3269 NULL);
3270 if (NT_SUCCESS(Status))
3271 {
3272 /* Use this target process */
3273 Target = TargetProcess;
3274 }
3275 else
3276 {
3277 /* No target process */
3278 Target = NULL;
3279 }
3280 }
3281 else
3282 {
3283 /* No target process */
3284 Status = STATUS_SUCCESS;
3285 Target = NULL;
3286 }
3287
3288 /* Call the internal routine */
3289 Status = ObDuplicateObject(SourceProcess,
3290 SourceHandle,
3291 Target,
3292 &hTarget,
3293 DesiredAccess,
3294 HandleAttributes,
3295 Options,
3296 PreviousMode);
3297
3298 /* Check if the caller wanted the return handle */
3299 if (TargetHandle)
3300 {
3301 /* Protect the write to user mode */
3302 _SEH2_TRY
3303 {
3304 /* Write the new handle */
3305 *TargetHandle = hTarget;
3306 }
3307 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3308 {
3309 /* Otherwise, get the exception code */
3310 Status = _SEH2_GetExceptionCode();
3311 }
3312 _SEH2_END;
3313 }
3314
3315 /* Dereference the processes */
3316 OBTRACE(OB_HANDLE_DEBUG,
3317 "%s - Duplicated handle: %lx into %lx S %lx\n",
3318 __FUNCTION__,
3319 hTarget,
3320 TargetProcessHandle,
3321 Status);
3322 if (Target) ObDereferenceObject(Target);
3323 ObDereferenceObject(SourceProcess);
3324 return Status;
3325 }
3326
3327 #undef ObIsKernelHandle
3328 BOOLEAN
3329 NTAPI
3330 ObIsKernelHandle(IN HANDLE Handle)
3331 {
3332 /* We know we're kernel mode, so just check for the kernel handle flag */
3333 return (BOOLEAN)(((ULONG_PTR)Handle & KERNEL_HANDLE_FLAG) != 0);
3334 }
3335
3336 /* EOF */