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