a2b2f9cebb81951a80be43923722d2a03b116e60
[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: %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 PAGED_CODE();
811
812 /* Get the object header and type */
813 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
814 ObjectType = ObjectHeader->Type;
815 OBTRACE(OB_HANDLE_DEBUG,
816 "%s - Incrementing count for: %p. Reason: %lx. HC PC %lx %lx\n",
817 __FUNCTION__,
818 Object,
819 OpenReason,
820 ObjectHeader->HandleCount,
821 ObjectHeader->PointerCount);
822
823 /* Check if caller is forcing user mode */
824 if (HandleAttributes & OBJ_FORCE_ACCESS_CHECK)
825 {
826 /* Force it */
827 ProbeMode = UserMode;
828 }
829 else
830 {
831 /* Keep original setting */
832 ProbeMode = AccessMode;
833 }
834
835 /* Lock the object */
836 ObpAcquireObjectLock(ObjectHeader);
837
838 /* Charge quota and remove the creator info flag */
839 Status = ObpChargeQuotaForObject(ObjectHeader, ObjectType, &NewObject);
840 if (!NT_SUCCESS(Status)) return Status;
841
842 /* Check if the open is exclusive */
843 if (HandleAttributes & OBJ_EXCLUSIVE)
844 {
845 /* Check if the object allows this, or if the inherit flag was given */
846 if ((HandleAttributes & OBJ_INHERIT) ||
847 !(ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
848 {
849 /* Incorrect attempt */
850 Status = STATUS_INVALID_PARAMETER;
851 goto Quickie;
852 }
853
854 /* Check if we have access to it */
855 ExclusiveProcess = OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader);
856 if ((!(ExclusiveProcess) && (ObjectHeader->HandleCount)) ||
857 ((ExclusiveProcess) && (ExclusiveProcess != PsGetCurrentProcess())))
858 {
859 /* This isn't the right process */
860 Status = STATUS_ACCESS_DENIED;
861 goto Quickie;
862 }
863
864 /* Now you got exclusive access */
865 Exclusive = TRUE;
866 }
867 else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) &&
868 (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader)))
869 {
870 /* Caller didn't want exclusive access, but the object is exclusive */
871 Status = STATUS_ACCESS_DENIED;
872 goto Quickie;
873 }
874
875 /*
876 * Check if this is an object that went from 0 handles back to existence,
877 * but doesn't have an open procedure, only a close procedure. This means
878 * that it will never realize that the object is back alive, so we must
879 * fail the request.
880 */
881 if (!(ObjectHeader->HandleCount) &&
882 !(NewObject) &&
883 (ObjectType->TypeInfo.MaintainHandleCount) &&
884 !(ObjectType->TypeInfo.OpenProcedure) &&
885 (ObjectType->TypeInfo.CloseProcedure))
886 {
887 /* Fail */
888 Status = STATUS_UNSUCCESSFUL;
889 goto Quickie;
890 }
891
892 /* Check if we're opening an existing handle */
893 if ((OpenReason == ObOpenHandle) ||
894 ((OpenReason == ObDuplicateHandle) && (AccessState)))
895 {
896 /* Validate the caller's access to this object */
897 if (!ObCheckObjectAccess(Object,
898 AccessState,
899 TRUE,
900 ProbeMode,
901 &Status))
902 {
903 /* Access was denied, so fail */
904 goto Quickie;
905 }
906 }
907 else if (OpenReason == ObCreateHandle)
908 {
909 /* Convert MAXIMUM_ALLOWED to GENERIC_ALL */
910 if (AccessState->RemainingDesiredAccess & MAXIMUM_ALLOWED)
911 {
912 /* Mask out MAXIMUM_ALLOWED and stick GENERIC_ALL instead */
913 AccessState->RemainingDesiredAccess &= ~MAXIMUM_ALLOWED;
914 AccessState->RemainingDesiredAccess |= GENERIC_ALL;
915 }
916
917 /* Check if we have to map the GENERIC mask */
918 if (AccessState->RemainingDesiredAccess & GENERIC_ACCESS)
919 {
920 /* Map it to the correct access masks */
921 RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
922 &ObjectType->TypeInfo.GenericMapping);
923 }
924
925 /* Check if the caller is trying to access system security */
926 if (AccessState->RemainingDesiredAccess & ACCESS_SYSTEM_SECURITY)
927 {
928 /* FIXME: TODO */
929 DPRINT1("ACCESS_SYSTEM_SECURITY not validated!\n");
930 }
931 }
932
933 /* Check if this is an exclusive handle */
934 if (Exclusive)
935 {
936 /* Save the owner process */
937 OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
938 }
939
940 /* Increase the handle count */
941 InterlockedIncrement(&ObjectHeader->HandleCount);
942 ProcessHandleCount = 0;
943
944 /* Check if we have a handle database */
945 if (ObjectType->TypeInfo.MaintainHandleCount)
946 {
947 /* Increment the handle database */
948 Status = ObpIncrementHandleDataBase(ObjectHeader,
949 Process,
950 &ProcessHandleCount);
951 if (!NT_SUCCESS(Status))
952 {
953 /* FIXME: This should never happen for now */
954 DPRINT1("Unhandled case\n");
955 ASSERT(FALSE);
956 goto Quickie;
957 }
958 }
959
960 /* Release the lock */
961 ObpReleaseObjectLock(ObjectHeader);
962
963 /* Check if we have an open procedure */
964 Status = STATUS_SUCCESS;
965 if (ObjectType->TypeInfo.OpenProcedure)
966 {
967 /* Call it */
968 ObpCalloutStart(&CalloutIrql);
969 Status = ObjectType->TypeInfo.OpenProcedure(OpenReason,
970 Process,
971 Object,
972 AccessState ?
973 AccessState->
974 PreviouslyGrantedAccess :
975 0,
976 ProcessHandleCount);
977 ObpCalloutEnd(CalloutIrql, "Open", ObjectType, Object);
978
979 /* Check if the open procedure failed */
980 if (!NT_SUCCESS(Status))
981 {
982 /* FIXME: This should never happen for now */
983 DPRINT1("Unhandled case\n");
984 ASSERT(FALSE);
985 return Status;
986 }
987 }
988
989 /* Check if this is a create operation */
990 if (OpenReason == ObCreateHandle)
991 {
992 /* Check if we have creator info */
993 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(ObjectHeader);
994 if (CreatorInfo)
995 {
996 /* We do, acquire the lock */
997 ObpEnterObjectTypeMutex(ObjectType);
998
999 /* Insert us on the list */
1000 InsertTailList(&ObjectType->TypeList, &CreatorInfo->TypeList);
1001
1002 /* Release the lock */
1003 ObpLeaveObjectTypeMutex(ObjectType);
1004 }
1005 }
1006
1007 /* Increase total number of handles */
1008 Total = InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfHandles);
1009 if (Total > ObjectType->HighWaterNumberOfHandles)
1010 {
1011 /* Fixup count */
1012 ObjectType->HighWaterNumberOfHandles = Total;
1013 }
1014
1015 /* Trace call and return */
1016 OBTRACE(OB_HANDLE_DEBUG,
1017 "%s - Incremented count for: %p. Reason: %lx HC PC %lx %lx\n",
1018 __FUNCTION__,
1019 Object,
1020 OpenReason,
1021 ObjectHeader->HandleCount,
1022 ObjectHeader->PointerCount);
1023 return Status;
1024
1025 Quickie:
1026 /* Release lock and return */
1027 ObpReleaseObjectLock(ObjectHeader);
1028 return Status;
1029 }
1030
1031 /*++
1032 * @name ObpIncrementUnnamedHandleCount
1033 *
1034 * The ObpIncrementUnnamedHandleCount routine <FILLMEIN>
1035 *
1036 * @param Object
1037 * <FILLMEIN>.
1038 *
1039 * @param AccessState
1040 * <FILLMEIN>.
1041 *
1042 * @param AccessMode
1043 * <FILLMEIN>.
1044 *
1045 * @param HandleAttributes
1046 * <FILLMEIN>.
1047 *
1048 * @param Process
1049 * <FILLMEIN>.
1050 *
1051 * @param OpenReason
1052 * <FILLMEIN>.
1053 *
1054 * @return <FILLMEIN>.
1055 *
1056 * @remarks None.
1057 *
1058 *--*/
1059 NTSTATUS
1060 NTAPI
1061 ObpIncrementUnnamedHandleCount(IN PVOID Object,
1062 IN PACCESS_MASK DesiredAccess,
1063 IN KPROCESSOR_MODE AccessMode,
1064 IN ULONG HandleAttributes,
1065 IN PEPROCESS Process)
1066 {
1067 POBJECT_HEADER ObjectHeader;
1068 POBJECT_TYPE ObjectType;
1069 ULONG ProcessHandleCount;
1070 NTSTATUS Status;
1071 PEPROCESS ExclusiveProcess;
1072 BOOLEAN Exclusive = FALSE, NewObject;
1073 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
1074 KIRQL CalloutIrql;
1075 ULONG Total;
1076
1077 /* Get the object header and type */
1078 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1079 ObjectType = ObjectHeader->Type;
1080 OBTRACE(OB_HANDLE_DEBUG,
1081 "%s - Incrementing count for: %p. UNNAMED. HC PC %lx %lx\n",
1082 __FUNCTION__,
1083 Object,
1084 ObjectHeader->HandleCount,
1085 ObjectHeader->PointerCount);
1086
1087 /* Lock the object */
1088 ObpAcquireObjectLock(ObjectHeader);
1089
1090 /* Charge quota and remove the creator info flag */
1091 Status = ObpChargeQuotaForObject(ObjectHeader, ObjectType, &NewObject);
1092 if (!NT_SUCCESS(Status)) return Status;
1093
1094 /* Check if the open is exclusive */
1095 if (HandleAttributes & OBJ_EXCLUSIVE)
1096 {
1097 /* Check if the object allows this, or if the inherit flag was given */
1098 if ((HandleAttributes & OBJ_INHERIT) ||
1099 !(ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
1100 {
1101 /* Incorrect attempt */
1102 Status = STATUS_INVALID_PARAMETER;
1103 goto Quickie;
1104 }
1105
1106 /* Check if we have access to it */
1107 ExclusiveProcess = OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader);
1108 if ((!(ExclusiveProcess) && (ObjectHeader->HandleCount)) ||
1109 ((ExclusiveProcess) && (ExclusiveProcess != PsGetCurrentProcess())))
1110 {
1111 /* This isn't the right process */
1112 Status = STATUS_ACCESS_DENIED;
1113 goto Quickie;
1114 }
1115
1116 /* Now you got exclusive access */
1117 Exclusive = TRUE;
1118 }
1119 else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) &&
1120 (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader)))
1121 {
1122 /* Caller didn't want exclusive access, but the object is exclusive */
1123 Status = STATUS_ACCESS_DENIED;
1124 goto Quickie;
1125 }
1126
1127 /*
1128 * Check if this is an object that went from 0 handles back to existence,
1129 * but doesn't have an open procedure, only a close procedure. This means
1130 * that it will never realize that the object is back alive, so we must
1131 * fail the request.
1132 */
1133 if (!(ObjectHeader->HandleCount) &&
1134 !(NewObject) &&
1135 (ObjectType->TypeInfo.MaintainHandleCount) &&
1136 !(ObjectType->TypeInfo.OpenProcedure) &&
1137 (ObjectType->TypeInfo.CloseProcedure))
1138 {
1139 /* Fail */
1140 Status = STATUS_UNSUCCESSFUL;
1141 goto Quickie;
1142 }
1143
1144 /* Convert MAXIMUM_ALLOWED to GENERIC_ALL */
1145 if (*DesiredAccess & MAXIMUM_ALLOWED)
1146 {
1147 /* Mask out MAXIMUM_ALLOWED and stick GENERIC_ALL instead */
1148 *DesiredAccess &= ~MAXIMUM_ALLOWED;
1149 *DesiredAccess |= GENERIC_ALL;
1150 }
1151
1152 /* Check if we have to map the GENERIC mask */
1153 if (*DesiredAccess & GENERIC_ACCESS)
1154 {
1155 /* Map it to the correct access masks */
1156 RtlMapGenericMask(DesiredAccess,
1157 &ObjectType->TypeInfo.GenericMapping);
1158 }
1159
1160 /* Check if this is an exclusive handle */
1161 if (Exclusive)
1162 {
1163 /* Save the owner process */
1164 OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
1165 }
1166
1167 /* Increase the handle count */
1168 InterlockedIncrement(&ObjectHeader->HandleCount);
1169 ProcessHandleCount = 0;
1170
1171 /* Check if we have a handle database */
1172 if (ObjectType->TypeInfo.MaintainHandleCount)
1173 {
1174 /* Increment the handle database */
1175 Status = ObpIncrementHandleDataBase(ObjectHeader,
1176 Process,
1177 &ProcessHandleCount);
1178 if (!NT_SUCCESS(Status))
1179 {
1180 /* FIXME: This should never happen for now */
1181 DPRINT1("Unhandled case\n");
1182 ASSERT(FALSE);
1183 goto Quickie;
1184 }
1185 }
1186
1187 /* Release the lock */
1188 ObpReleaseObjectLock(ObjectHeader);
1189
1190 /* Check if we have an open procedure */
1191 Status = STATUS_SUCCESS;
1192 if (ObjectType->TypeInfo.OpenProcedure)
1193 {
1194 /* Call it */
1195 ObpCalloutStart(&CalloutIrql);
1196 Status = ObjectType->TypeInfo.OpenProcedure(ObCreateHandle,
1197 Process,
1198 Object,
1199 *DesiredAccess,
1200 ProcessHandleCount);
1201 ObpCalloutEnd(CalloutIrql, "Open", ObjectType, Object);
1202
1203 /* Check if the open procedure failed */
1204 if (!NT_SUCCESS(Status))
1205 {
1206 /* FIXME: This should never happen for now */
1207 DPRINT1("Unhandled case\n");
1208 ASSERT(FALSE);
1209 return Status;
1210 }
1211 }
1212
1213 /* Check if we have creator info */
1214 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(ObjectHeader);
1215 if (CreatorInfo)
1216 {
1217 /* We do, acquire the lock */
1218 ObpEnterObjectTypeMutex(ObjectType);
1219
1220 /* Insert us on the list */
1221 InsertTailList(&ObjectType->TypeList, &CreatorInfo->TypeList);
1222
1223 /* Release the lock */
1224 ObpLeaveObjectTypeMutex(ObjectType);
1225 }
1226
1227 /* Increase total number of handles */
1228 Total = InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfHandles);
1229 if (Total > ObjectType->HighWaterNumberOfHandles)
1230 {
1231 /* Fixup count */
1232 ObjectType->HighWaterNumberOfHandles = Total;
1233 }
1234
1235 /* Trace call and return */
1236 OBTRACE(OB_HANDLE_DEBUG,
1237 "%s - Incremented count for: %p. UNNAMED HC PC %lx %lx\n",
1238 __FUNCTION__,
1239 Object,
1240 ObjectHeader->HandleCount,
1241 ObjectHeader->PointerCount);
1242 return Status;
1243
1244 Quickie:
1245 /* Release lock and return */
1246 ObpReleaseObjectLock(ObjectHeader);
1247 return Status;
1248 }
1249
1250 /*++
1251 * @name ObpCreateUnnamedHandle
1252 *
1253 * The ObpCreateUnnamedHandle routine <FILLMEIN>
1254 *
1255 * @param Object
1256 * <FILLMEIN>.
1257 *
1258 * @param DesiredAccess
1259 * <FILLMEIN>.
1260 *
1261 * @param AdditionalReferences
1262 * <FILLMEIN>.
1263 *
1264 * @param HandleAttributes
1265 * <FILLMEIN>.
1266 *
1267 * @param AccessMode
1268 * <FILLMEIN>.
1269 *
1270 * @param ReturnedObject
1271 * <FILLMEIN>.
1272 *
1273 * @param ReturnedHandle
1274 * <FILLMEIN>.
1275 *
1276 * @return <FILLMEIN>.
1277 *
1278 * @remarks None.
1279 *
1280 *--*/
1281 NTSTATUS
1282 NTAPI
1283 ObpCreateUnnamedHandle(IN PVOID Object,
1284 IN ACCESS_MASK DesiredAccess,
1285 IN ULONG AdditionalReferences,
1286 IN ULONG HandleAttributes,
1287 IN KPROCESSOR_MODE AccessMode,
1288 OUT PVOID *ReturnedObject,
1289 OUT PHANDLE ReturnedHandle)
1290 {
1291 HANDLE_TABLE_ENTRY NewEntry;
1292 POBJECT_HEADER ObjectHeader;
1293 HANDLE Handle;
1294 KAPC_STATE ApcState;
1295 BOOLEAN AttachedToProcess = FALSE, KernelHandle = FALSE;
1296 PVOID HandleTable;
1297 NTSTATUS Status;
1298 ACCESS_MASK GrantedAccess;
1299 POBJECT_TYPE ObjectType;
1300 PAGED_CODE();
1301
1302 /* Get the object header and type */
1303 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1304 ObjectType = ObjectHeader->Type;
1305 OBTRACE(OB_HANDLE_DEBUG,
1306 "%s - Creating handle for: %p. UNNAMED. HC PC %lx %lx\n",
1307 __FUNCTION__,
1308 Object,
1309 ObjectHeader->HandleCount,
1310 ObjectHeader->PointerCount);
1311
1312 /* Save the object header */
1313 NewEntry.Object = ObjectHeader;
1314
1315 /* Mask out the internal attributes */
1316 NewEntry.ObAttributes |= HandleAttributes & OBJ_HANDLE_ATTRIBUTES;
1317
1318 /* Check if this is a kernel handle */
1319 if (HandleAttributes & OBJ_KERNEL_HANDLE)
1320 {
1321 /* Set the handle table */
1322 HandleTable = ObpKernelHandleTable;
1323 KernelHandle = TRUE;
1324
1325 /* Check if we're not in the system process */
1326 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1327 {
1328 /* Attach to the system process */
1329 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1330 AttachedToProcess = TRUE;
1331 }
1332 }
1333 else
1334 {
1335 /* Get the current handle table */
1336 HandleTable = PsGetCurrentProcess()->ObjectTable;
1337 }
1338
1339 /* Increment the handle count */
1340 Status = ObpIncrementUnnamedHandleCount(Object,
1341 &DesiredAccess,
1342 AccessMode,
1343 HandleAttributes,
1344 PsGetCurrentProcess());
1345 if (!NT_SUCCESS(Status))
1346 {
1347 /*
1348 * We failed (meaning security failure, according to NT Internals)
1349 * detach and return
1350 */
1351 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1352 return Status;
1353 }
1354
1355 /* Remove what's not in the valid access mask */
1356 GrantedAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
1357 ACCESS_SYSTEM_SECURITY);
1358
1359 /* Handle extra references */
1360 if (AdditionalReferences)
1361 {
1362 /* Add them to the header */
1363 InterlockedExchangeAdd(&ObjectHeader->PointerCount,
1364 AdditionalReferences);
1365 }
1366
1367 /* Save the access mask */
1368 NewEntry.GrantedAccess = GrantedAccess;
1369
1370 /*
1371 * Create the actual handle. We'll need to do this *after* calling
1372 * ObpIncrementHandleCount to make sure that Object Security is valid
1373 * (specified in Gl00my documentation on Ob)
1374 */
1375 OBTRACE(OB_HANDLE_DEBUG,
1376 "%s - Handle Properties: [%p-%lx-%lx]\n",
1377 __FUNCTION__,
1378 NewEntry.Object, NewEntry.ObAttributes & 3, NewEntry.GrantedAccess);
1379 Handle = ExCreateHandle(HandleTable, &NewEntry);
1380
1381 /* Make sure we got a handle */
1382 if (Handle)
1383 {
1384 /* Check if this was a kernel handle */
1385 if (KernelHandle) Handle = ObMarkHandleAsKernelHandle(Handle);
1386
1387 /* Return handle and object */
1388 *ReturnedHandle = Handle;
1389
1390 /* Return the new object only if caller wanted it biased */
1391 if ((AdditionalReferences) && (ReturnedObject))
1392 {
1393 /* Return it */
1394 *ReturnedObject = Object;
1395 }
1396
1397 /* Detach if needed */
1398 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1399
1400 /* Trace and return */
1401 OBTRACE(OB_HANDLE_DEBUG,
1402 "%s - Returning Handle: %p HC PC %lx %lx\n",
1403 __FUNCTION__,
1404 Handle,
1405 ObjectHeader->HandleCount,
1406 ObjectHeader->PointerCount);
1407 return STATUS_SUCCESS;
1408 }
1409
1410 /* Handle extra references */
1411 if (AdditionalReferences)
1412 {
1413 /* Dereference it as many times as required */
1414 InterlockedExchangeAdd(&ObjectHeader->PointerCount,
1415 -(LONG)AdditionalReferences);
1416 }
1417
1418 /* Decrement the handle count and detach */
1419 ObpDecrementHandleCount(&ObjectHeader->Body,
1420 PsGetCurrentProcess(),
1421 GrantedAccess,
1422 ObjectType);
1423
1424 /* Detach and fail */
1425 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1426 return STATUS_INSUFFICIENT_RESOURCES;
1427 }
1428
1429 /*++
1430 * @name ObpCreateHandle
1431 *
1432 * The ObpCreateHandle routine <FILLMEIN>
1433 *
1434 * @param OpenReason
1435 * <FILLMEIN>.
1436 *
1437 * @param Object
1438 * <FILLMEIN>.
1439 *
1440 * @param Type
1441 * <FILLMEIN>.
1442 *
1443 * @param AccessState
1444 * <FILLMEIN>.
1445 *
1446 * @param AdditionalReferences
1447 * <FILLMEIN>.
1448 *
1449 * @param HandleAttributes
1450 * <FILLMEIN>.
1451 *
1452 * @param AccessMode
1453 * <FILLMEIN>.
1454 *
1455 * @param ReturnedObject
1456 * <FILLMEIN>.
1457 *
1458 * @param ReturnedHandle
1459 * <FILLMEIN>.
1460 *
1461 * @return <FILLMEIN>.
1462 *
1463 * @remarks Cleans up the Lookup Context on return.
1464 *
1465 *--*/
1466 NTSTATUS
1467 NTAPI
1468 ObpCreateHandle(IN OB_OPEN_REASON OpenReason,
1469 IN PVOID Object,
1470 IN POBJECT_TYPE Type OPTIONAL,
1471 IN PACCESS_STATE AccessState,
1472 IN ULONG AdditionalReferences,
1473 IN ULONG HandleAttributes,
1474 IN POBP_LOOKUP_CONTEXT Context,
1475 IN KPROCESSOR_MODE AccessMode,
1476 OUT PVOID *ReturnedObject,
1477 OUT PHANDLE ReturnedHandle)
1478 {
1479 HANDLE_TABLE_ENTRY NewEntry;
1480 POBJECT_HEADER ObjectHeader;
1481 HANDLE Handle;
1482 KAPC_STATE ApcState;
1483 BOOLEAN AttachedToProcess = FALSE, KernelHandle = FALSE;
1484 POBJECT_TYPE ObjectType;
1485 PVOID HandleTable;
1486 NTSTATUS Status;
1487 ACCESS_MASK DesiredAccess, GrantedAccess;
1488 PAUX_ACCESS_DATA AuxData;
1489 PAGED_CODE();
1490
1491 /* Get the object header and type */
1492 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1493 ObjectType = ObjectHeader->Type;
1494 OBTRACE(OB_HANDLE_DEBUG,
1495 "%s - Creating handle for: %p. Reason: %lx. HC PC %lx %lx\n",
1496 __FUNCTION__,
1497 Object,
1498 OpenReason,
1499 ObjectHeader->HandleCount,
1500 ObjectHeader->PointerCount);
1501
1502 /* Check if the types match */
1503 if ((Type) && (ObjectType != Type))
1504 {
1505 /* They don't, cleanup */
1506 if (Context) ObpReleaseLookupContext(Context);
1507 return STATUS_OBJECT_TYPE_MISMATCH;
1508 }
1509
1510 /* Save the object header */
1511 NewEntry.Object = ObjectHeader;
1512
1513 /* Check if this is a kernel handle */
1514 if (HandleAttributes & OBJ_KERNEL_HANDLE)
1515 {
1516 /* Set the handle table */
1517 HandleTable = ObpKernelHandleTable;
1518 KernelHandle = TRUE;
1519
1520 /* Check if we're not in the system process */
1521 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1522 {
1523 /* Attach to the system process */
1524 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1525 AttachedToProcess = TRUE;
1526 }
1527 }
1528 else
1529 {
1530 /* Get the current handle table */
1531 HandleTable = PsGetCurrentProcess()->ObjectTable;
1532 }
1533
1534 /* Increment the handle count */
1535 Status = ObpIncrementHandleCount(Object,
1536 AccessState,
1537 AccessMode,
1538 HandleAttributes,
1539 PsGetCurrentProcess(),
1540 OpenReason);
1541 if (!NT_SUCCESS(Status))
1542 {
1543 /*
1544 * We failed (meaning security failure, according to NT Internals)
1545 * detach and return
1546 */
1547 if (Context) ObpReleaseLookupContext(Context);
1548 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1549 return Status;
1550 }
1551
1552 /* Check if we are doing audits on close */
1553 if (AccessState->GenerateOnClose)
1554 {
1555 /* Force the attribute on */
1556 HandleAttributes |= OBJ_AUDIT_OBJECT_CLOSE;
1557 }
1558
1559 /* Mask out the internal attributes */
1560 NewEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
1561
1562 /* Get the original desired access */
1563 DesiredAccess = AccessState->RemainingDesiredAccess |
1564 AccessState->PreviouslyGrantedAccess;
1565
1566 /* Remove what's not in the valid access mask */
1567 GrantedAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
1568 ACCESS_SYSTEM_SECURITY);
1569
1570 /* Update the value in the access state */
1571 AccessState->PreviouslyGrantedAccess = GrantedAccess;
1572
1573 /* Get the auxiliary data */
1574 AuxData = AccessState->AuxData;
1575
1576 /* Handle extra references */
1577 if (AdditionalReferences)
1578 {
1579 /* Add them to the header */
1580 InterlockedExchangeAdd(&ObjectHeader->PointerCount, AdditionalReferences);
1581 }
1582
1583 /* Now we can release the object */
1584 if (Context) ObpReleaseLookupContext(Context);
1585
1586 /* Save the access mask */
1587 NewEntry.GrantedAccess = GrantedAccess;
1588
1589 /*
1590 * Create the actual handle. We'll need to do this *after* calling
1591 * ObpIncrementHandleCount to make sure that Object Security is valid
1592 * (specified in Gl00my documentation on Ob)
1593 */
1594 OBTRACE(OB_HANDLE_DEBUG,
1595 "%s - Handle Properties: [%p-%lx-%lx]\n",
1596 __FUNCTION__,
1597 NewEntry.Object, NewEntry.ObAttributes & 3, NewEntry.GrantedAccess);
1598 Handle = ExCreateHandle(HandleTable, &NewEntry);
1599
1600 /* Make sure we got a handle */
1601 if (Handle)
1602 {
1603 /* Check if this was a kernel handle */
1604 if (KernelHandle) Handle = ObMarkHandleAsKernelHandle(Handle);
1605
1606 /* Return it */
1607 *ReturnedHandle = Handle;
1608
1609 /* Check if we need to generate on audit */
1610 if (AccessState->GenerateAudit)
1611 {
1612 /* Audit the handle creation */
1613 //SeAuditHandleCreation(AccessState, Handle);
1614 }
1615
1616 /* Check if this was a create */
1617 if (OpenReason == ObCreateHandle)
1618 {
1619 /* Check if we need to audit the privileges */
1620 if ((AuxData->PrivilegeSet) &&
1621 (AuxData->PrivilegeSet->PrivilegeCount))
1622 {
1623 /* Do the audit */
1624 #if 0
1625 SePrivilegeObjectAuditAlarm(Handle,
1626 &AccessState->
1627 SubjectSecurityContext,
1628 GrantedAccess,
1629 AuxData->PrivilegeSet,
1630 TRUE,
1631 ExGetPreviousMode());
1632 #endif
1633 }
1634 }
1635
1636 /* Return the new object only if caller wanted it biased */
1637 if ((AdditionalReferences) && (ReturnedObject))
1638 {
1639 /* Return it */
1640 *ReturnedObject = Object;
1641 }
1642
1643 /* Detach if needed */
1644 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1645
1646 /* Trace and return */
1647 OBTRACE(OB_HANDLE_DEBUG,
1648 "%s - Returning Handle: %p HC PC %lx %lx\n",
1649 __FUNCTION__,
1650 Handle,
1651 ObjectHeader->HandleCount,
1652 ObjectHeader->PointerCount);
1653 return STATUS_SUCCESS;
1654 }
1655
1656 /* Decrement the handle count and detach */
1657 ObpDecrementHandleCount(&ObjectHeader->Body,
1658 PsGetCurrentProcess(),
1659 GrantedAccess,
1660 ObjectType);
1661
1662 /* Handle extra references */
1663 if (AdditionalReferences)
1664 {
1665 /* Check how many extra references were added */
1666 if (AdditionalReferences > 1)
1667 {
1668 /* Dereference it many times */
1669 InterlockedExchangeAdd(&ObjectHeader->PointerCount,
1670 -(LONG)(AdditionalReferences - 1));
1671 }
1672
1673 /* Dereference the object one last time */
1674 ObDereferenceObject(Object);
1675 }
1676
1677 /* Detach if necessary and fail */
1678 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
1679 return STATUS_INSUFFICIENT_RESOURCES;
1680 }
1681
1682 /*++
1683 * @name ObpCloseHandle
1684 *
1685 * The ObpCloseHandle routine <FILLMEIN>
1686 *
1687 * @param Handle
1688 * <FILLMEIN>.
1689 *
1690 * @param AccessMode
1691 * <FILLMEIN>.
1692 *
1693 * @return <FILLMEIN>.
1694 *
1695 * @remarks None.
1696 *
1697 *--*/
1698 NTSTATUS
1699 NTAPI
1700 ObpCloseHandle(IN HANDLE Handle,
1701 IN KPROCESSOR_MODE AccessMode)
1702 {
1703 PVOID HandleTable;
1704 BOOLEAN AttachedToProcess = FALSE;
1705 KAPC_STATE ApcState;
1706 PHANDLE_TABLE_ENTRY HandleTableEntry;
1707 NTSTATUS Status;
1708 PEPROCESS Process = PsGetCurrentProcess();
1709 PAGED_CODE();
1710 OBTRACE(OB_HANDLE_DEBUG,
1711 "%s - Closing handle: %p\n", __FUNCTION__, Handle);
1712
1713 if (AccessMode == KernelMode && Handle == (HANDLE)-1)
1714 return STATUS_INVALID_HANDLE;
1715
1716 /* Check if we're dealing with a kernel handle */
1717 if (ObpIsKernelHandle(Handle, AccessMode))
1718 {
1719 /* Use the kernel table and convert the handle */
1720 HandleTable = ObpKernelHandleTable;
1721 Handle = ObKernelHandleToHandle(Handle);
1722
1723 /* Check if we're not in the system process */
1724 if (Process != PsInitialSystemProcess)
1725 {
1726 /* Attach to the system process */
1727 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1728 AttachedToProcess = TRUE;
1729 }
1730 }
1731 else
1732 {
1733 /* Use the process's handle table */
1734 HandleTable = Process->ObjectTable;
1735 }
1736
1737 /* Enter a critical region to protect handle access */
1738 KeEnterCriticalRegion();
1739
1740 /* Get the handle entry */
1741 HandleTableEntry = ExMapHandleToPointer(HandleTable, Handle);
1742 if (HandleTableEntry)
1743 {
1744 /* Now close the entry */
1745 Status = ObpCloseHandleTableEntry(HandleTable,
1746 HandleTableEntry,
1747 Handle,
1748 AccessMode,
1749 FALSE);
1750
1751 /* We can quit the critical region now */
1752 KeLeaveCriticalRegion();
1753
1754 /* Detach and return success */
1755 if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
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: %p 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: %p 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: %p 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, Status2;
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 AccessMode,
2461 TRUE,
2462 &TempBuffer->ObjectCreateInfo,
2463 &ObjectName);
2464 if (!NT_SUCCESS(Status))
2465 {
2466 /* Fail */
2467 ExFreePoolWithTag(TempBuffer, TAG_OB_TEMP_STORAGE);
2468 return Status;
2469 }
2470
2471 /* Check if we didn't get an access state */
2472 if (!PassedAccessState)
2473 {
2474 /* Try to get the generic mapping if we can */
2475 if (ObjectType) GenericMapping = &ObjectType->TypeInfo.GenericMapping;
2476
2477 /* Use our built-in access state */
2478 PassedAccessState = &TempBuffer->LocalAccessState;
2479 Status = SeCreateAccessState(&TempBuffer->LocalAccessState,
2480 &TempBuffer->AuxData,
2481 DesiredAccess,
2482 GenericMapping);
2483 if (!NT_SUCCESS(Status)) goto Quickie;
2484 }
2485
2486 /* Get the security descriptor */
2487 if (TempBuffer->ObjectCreateInfo.SecurityDescriptor)
2488 {
2489 /* Save it in the access state */
2490 PassedAccessState->SecurityDescriptor =
2491 TempBuffer->ObjectCreateInfo.SecurityDescriptor;
2492 }
2493
2494 /* Validate the access mask */
2495 Status = ObpValidateAccessMask(PassedAccessState);
2496 if (!NT_SUCCESS(Status))
2497 {
2498 /* Cleanup after lookup */
2499 ObpReleaseLookupContext(&TempBuffer->LookupContext);
2500 goto Cleanup;
2501 }
2502
2503 /* Now do the lookup */
2504 Status = ObpLookupObjectName(TempBuffer->ObjectCreateInfo.RootDirectory,
2505 &ObjectName,
2506 TempBuffer->ObjectCreateInfo.Attributes,
2507 ObjectType,
2508 AccessMode,
2509 ParseContext,
2510 TempBuffer->ObjectCreateInfo.SecurityQos,
2511 NULL,
2512 PassedAccessState,
2513 &TempBuffer->LookupContext,
2514 &Object);
2515 if (!NT_SUCCESS(Status))
2516 {
2517 /* Cleanup after lookup */
2518 ObpReleaseLookupContext(&TempBuffer->LookupContext);
2519 goto Cleanup;
2520 }
2521
2522 /* Check if this object has create information */
2523 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2524 if (ObjectHeader->Flags & OB_FLAG_CREATE_INFO)
2525 {
2526 /* Then we are creating a new handle */
2527 OpenReason = ObCreateHandle;
2528
2529 /* Check if we still have create info */
2530 if (ObjectHeader->ObjectCreateInfo)
2531 {
2532 /* Free it */
2533 ObpFreeObjectCreateInformation(ObjectHeader->
2534 ObjectCreateInfo);
2535 ObjectHeader->ObjectCreateInfo = NULL;
2536 }
2537 }
2538 else
2539 {
2540 /* Otherwise, we are merely opening it */
2541 OpenReason = ObOpenHandle;
2542 }
2543
2544 /* Check if we have invalid object attributes */
2545 if (ObjectHeader->Type->TypeInfo.InvalidAttributes &
2546 TempBuffer->ObjectCreateInfo.Attributes)
2547 {
2548 /* Set failure code */
2549 Status = STATUS_INVALID_PARAMETER;
2550
2551 /* Cleanup after lookup */
2552 ObpReleaseLookupContext(&TempBuffer->LookupContext);
2553
2554 /* Dereference the object */
2555 ObDereferenceObject(Object);
2556 }
2557 else
2558 {
2559 /* Create the actual handle now */
2560 Status2 = ObpCreateHandle(OpenReason,
2561 Object,
2562 ObjectType,
2563 PassedAccessState,
2564 0,
2565 TempBuffer->ObjectCreateInfo.Attributes,
2566 &TempBuffer->LookupContext,
2567 AccessMode,
2568 NULL,
2569 Handle);
2570 if (!NT_SUCCESS(Status))
2571 {
2572 ObDereferenceObject(Object);
2573 Status = Status2;
2574 }
2575 }
2576
2577 Cleanup:
2578 /* Delete the access state */
2579 if (PassedAccessState == &TempBuffer->LocalAccessState)
2580 {
2581 SeDeleteAccessState(PassedAccessState);
2582 }
2583
2584 Quickie:
2585 /* Release the object attributes and temporary buffer */
2586 ObpReleaseObjectCreateInformation(&TempBuffer->ObjectCreateInfo);
2587 if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
2588 ExFreePoolWithTag(TempBuffer, TAG_OB_TEMP_STORAGE);
2589
2590 /* Return status */
2591 OBTRACE(OB_HANDLE_DEBUG,
2592 "%s - returning Object %p with PC S: %lx %lx\n",
2593 __FUNCTION__,
2594 Object,
2595 Object ? OBJECT_TO_OBJECT_HEADER(Object)->PointerCount : -1,
2596 Status);
2597 return Status;
2598 }
2599
2600 /*++
2601 * @name ObOpenObjectByPointer
2602 * @implemented NT4
2603 *
2604 * The ObOpenObjectByPointer routine <FILLMEIN>
2605 *
2606 * @param Object
2607 * <FILLMEIN>.
2608 *
2609 * @param HandleAttributes
2610 * <FILLMEIN>.
2611 *
2612 * @param PassedAccessState
2613 * <FILLMEIN>.
2614 *
2615 * @param DesiredAccess
2616 * <FILLMEIN>.
2617 *
2618 * @param ObjectType
2619 * <FILLMEIN>.
2620 *
2621 * @param AccessMode
2622 * <FILLMEIN>.
2623 *
2624 * @param Handle
2625 * <FILLMEIN>.
2626 *
2627 * @return <FILLMEIN>.
2628 *
2629 * @remarks None.
2630 *
2631 *--*/
2632 NTSTATUS
2633 NTAPI
2634 ObOpenObjectByPointer(IN PVOID Object,
2635 IN ULONG HandleAttributes,
2636 IN PACCESS_STATE PassedAccessState,
2637 IN ACCESS_MASK DesiredAccess,
2638 IN POBJECT_TYPE ObjectType,
2639 IN KPROCESSOR_MODE AccessMode,
2640 OUT PHANDLE Handle)
2641 {
2642 POBJECT_HEADER Header;
2643 NTSTATUS Status;
2644 ACCESS_STATE AccessState;
2645 AUX_ACCESS_DATA AuxData;
2646 PAGED_CODE();
2647
2648 /* Assume failure */
2649 *Handle = NULL;
2650
2651 /* Reference the object */
2652 Status = ObReferenceObjectByPointer(Object,
2653 0,
2654 ObjectType,
2655 AccessMode);
2656 if (!NT_SUCCESS(Status)) return Status;
2657
2658 /* Get the Header Info */
2659 Header = OBJECT_TO_OBJECT_HEADER(Object);
2660
2661 /* Check if we didn't get an access state */
2662 if (!PassedAccessState)
2663 {
2664 /* Use our built-in access state */
2665 PassedAccessState = &AccessState;
2666 Status = SeCreateAccessState(&AccessState,
2667 &AuxData,
2668 DesiredAccess,
2669 &Header->Type->TypeInfo.GenericMapping);
2670 if (!NT_SUCCESS(Status))
2671 {
2672 /* Fail */
2673 ObDereferenceObject(Object);
2674 return Status;
2675 }
2676 }
2677
2678 /* Check if we have invalid object attributes */
2679 if (Header->Type->TypeInfo.InvalidAttributes & HandleAttributes)
2680 {
2681 /* Delete the access state */
2682 if (PassedAccessState == &AccessState)
2683 {
2684 SeDeleteAccessState(PassedAccessState);
2685 }
2686
2687 /* Dereference the object */
2688 ObDereferenceObject(Object);
2689 return STATUS_INVALID_PARAMETER;
2690 }
2691
2692 /* Create the handle */
2693 Status = ObpCreateHandle(ObOpenHandle,
2694 Object,
2695 ObjectType,
2696 PassedAccessState,
2697 0,
2698 HandleAttributes,
2699 NULL,
2700 AccessMode,
2701 NULL,
2702 Handle);
2703 if (!NT_SUCCESS(Status)) ObDereferenceObject(Object);
2704
2705 /* Delete the access state */
2706 if (PassedAccessState == &AccessState)
2707 {
2708 SeDeleteAccessState(PassedAccessState);
2709 }
2710
2711 /* Return */
2712 OBTRACE(OB_HANDLE_DEBUG,
2713 "%s - returning Object with PC S: %lx %lx\n",
2714 __FUNCTION__,
2715 OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
2716 Status);
2717 return Status;
2718 }
2719
2720 /*++
2721 * @name ObFindHandleForObject
2722 * @implemented NT4
2723 *
2724 * The ObFindHandleForObject routine <FILLMEIN>
2725 *
2726 * @param Process
2727 * <FILLMEIN>.
2728 *
2729 * @param Object
2730 * <FILLMEIN>.
2731 *
2732 * @param ObjectType
2733 * <FILLMEIN>.
2734 *
2735 * @param HandleInformation
2736 * <FILLMEIN>.
2737 *
2738 * @param HandleReturn
2739 * <FILLMEIN>.
2740 *
2741 * @return <FILLMEIN>.
2742 *
2743 * @remarks None.
2744 *
2745 *--*/
2746 BOOLEAN
2747 NTAPI
2748 ObFindHandleForObject(IN PEPROCESS Process,
2749 IN PVOID Object,
2750 IN POBJECT_TYPE ObjectType,
2751 IN POBJECT_HANDLE_INFORMATION HandleInformation,
2752 OUT PHANDLE Handle)
2753 {
2754 OBP_FIND_HANDLE_DATA FindData;
2755 BOOLEAN Result = FALSE;
2756 PVOID ObjectTable;
2757
2758 /* Make sure we have an object table */
2759 ObjectTable = ObReferenceProcessHandleTable(Process);
2760 if (ObjectTable)
2761 {
2762 /* Check if we have an object */
2763 if (Object)
2764 {
2765 /* Set its header */
2766 FindData.ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2767 }
2768 else
2769 {
2770 /* Otherwise, no object to match*/
2771 FindData.ObjectHeader = NULL;
2772 }
2773
2774 /* Set other information */
2775 FindData.ObjectType = ObjectType;
2776 FindData.HandleInformation = HandleInformation;
2777
2778 /* Enumerate the handle table */
2779 if (ExEnumHandleTable(Process->ObjectTable,
2780 ObpEnumFindHandleProcedure,
2781 &FindData,
2782 Handle))
2783 {
2784 /* Set success */
2785 Result = TRUE;
2786 }
2787
2788 /* Let go of the table */
2789 ObDereferenceProcessHandleTable(Process);
2790 }
2791
2792 /* Return the result */
2793 return Result;
2794 }
2795
2796 /*++
2797 * @name ObInsertObject
2798 * @implemented NT4
2799 *
2800 * The ObInsertObject routine <FILLMEIN>
2801 *
2802 * @param Object
2803 * <FILLMEIN>.
2804 *
2805 * @param PassedAccessState
2806 * <FILLMEIN>.
2807 *
2808 * @param DesiredAccess
2809 * <FILLMEIN>.
2810 *
2811 * @param AdditionalReferences
2812 * <FILLMEIN>.
2813 *
2814 * @param ReferencedObject
2815 * <FILLMEIN>.
2816 *
2817 * @param Handle
2818 * <FILLMEIN>.
2819 *
2820 * @return <FILLMEIN>.
2821 *
2822 * @remarks None.
2823 *
2824 *--*/
2825 NTSTATUS
2826 NTAPI
2827 ObInsertObject(IN PVOID Object,
2828 IN PACCESS_STATE AccessState OPTIONAL,
2829 IN ACCESS_MASK DesiredAccess,
2830 IN ULONG ObjectPointerBias,
2831 OUT PVOID *NewObject OPTIONAL,
2832 OUT PHANDLE Handle)
2833 {
2834 POBJECT_CREATE_INFORMATION ObjectCreateInfo;
2835 POBJECT_HEADER ObjectHeader;
2836 POBJECT_TYPE ObjectType;
2837 PUNICODE_STRING ObjectName;
2838 PVOID InsertObject;
2839 PSECURITY_DESCRIPTOR ParentDescriptor = NULL;
2840 BOOLEAN SdAllocated = FALSE;
2841 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
2842 OBP_LOOKUP_CONTEXT Context;
2843 ACCESS_STATE LocalAccessState;
2844 AUX_ACCESS_DATA AuxData;
2845 OB_OPEN_REASON OpenReason;
2846 KPROCESSOR_MODE PreviousMode;
2847 NTSTATUS Status = STATUS_SUCCESS, RealStatus;
2848 BOOLEAN IsNewObject;
2849 PAGED_CODE();
2850
2851 /* Get the Header */
2852 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2853
2854 /* Detect invalid insert */
2855 if (!(ObjectHeader->Flags & OB_FLAG_CREATE_INFO))
2856 {
2857 /* Display warning and break into debugger */
2858 DPRINT1("OB: Attempting to insert existing object %p\n", Object);
2859 DbgBreakPoint();
2860
2861 /* Allow debugger to continue */
2862 ObDereferenceObject(Object);
2863 return STATUS_INVALID_PARAMETER;
2864 }
2865
2866 /* Get the create and name info, as well as the object type */
2867 ObjectCreateInfo = ObjectHeader->ObjectCreateInfo;
2868 ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
2869 ObjectType = ObjectHeader->Type;
2870 ObjectName = NULL;
2871
2872 /* Check if this is an named object */
2873 if ((ObjectNameInfo) && (ObjectNameInfo->Name.Buffer))
2874 {
2875 /* Get the object name */
2876 ObjectName = &ObjectNameInfo->Name;
2877 }
2878
2879 /* Sanity check */
2880 ASSERT((Handle) ||
2881 ((ObjectPointerBias == 0) &&
2882 (ObjectName == NULL) &&
2883 (ObjectType->TypeInfo.SecurityRequired) &&
2884 (NewObject == NULL)));
2885
2886 /* Check if the object is unnamed and also doesn't have security */
2887 PreviousMode = KeGetPreviousMode();
2888 if (!(ObjectType->TypeInfo.SecurityRequired) && !(ObjectName))
2889 {
2890 /* Assume failure */
2891 *Handle = NULL;
2892 ObjectHeader->ObjectCreateInfo = NULL;
2893
2894 /* Create the handle */
2895 Status = ObpCreateUnnamedHandle(Object,
2896 DesiredAccess,
2897 ObjectPointerBias + 1,
2898 ObjectCreateInfo->Attributes,
2899 PreviousMode,
2900 NewObject,
2901 Handle);
2902
2903 /* Free the create information */
2904 ObpFreeObjectCreateInformation(ObjectCreateInfo);
2905
2906 /* Release the object name information */
2907 ObpDereferenceNameInfo(ObjectNameInfo);
2908
2909 /* Remove the extra keep-alive reference */
2910 ObDereferenceObject(Object);
2911
2912 /* Return */
2913 OBTRACE(OB_HANDLE_DEBUG,
2914 "%s - returning Object with PC S: %lx %lx\n",
2915 __FUNCTION__,
2916 ObjectHeader->PointerCount,
2917 Status);
2918 return Status;
2919 }
2920
2921 /* Check if we didn't get an access state */
2922 if (!AccessState)
2923 {
2924 /* Use our built-in access state */
2925 AccessState = &LocalAccessState;
2926 Status = SeCreateAccessState(&LocalAccessState,
2927 &AuxData,
2928 DesiredAccess,
2929 &ObjectType->TypeInfo.GenericMapping);
2930 if (!NT_SUCCESS(Status))
2931 {
2932 /* Fail */
2933 ObpDereferenceNameInfo(ObjectNameInfo);
2934 ObDereferenceObject(Object);
2935 return Status;
2936 }
2937 }
2938
2939 /* Save the security descriptor */
2940 AccessState->SecurityDescriptor = ObjectCreateInfo->SecurityDescriptor;
2941
2942 /* Validate the access mask */
2943 Status = ObpValidateAccessMask(AccessState);
2944 if (!NT_SUCCESS(Status))
2945 {
2946 /* Fail */
2947 ObpDereferenceNameInfo(ObjectNameInfo);
2948 ObDereferenceObject(Object);
2949 return Status;
2950 }
2951
2952 /* Setup a lookup context */
2953 ObpInitializeLookupContext(&Context);
2954 InsertObject = Object;
2955 OpenReason = ObCreateHandle;
2956
2957 /* Check if the object is named */
2958 if (ObjectName)
2959 {
2960 /* Look it up */
2961 Status = ObpLookupObjectName(ObjectCreateInfo->RootDirectory,
2962 ObjectName,
2963 ObjectCreateInfo->Attributes,
2964 ObjectType,
2965 (ObjectHeader->Flags & OB_FLAG_KERNEL_MODE) ?
2966 KernelMode : UserMode,
2967 ObjectCreateInfo->ParseContext,
2968 ObjectCreateInfo->SecurityQos,
2969 Object,
2970 AccessState,
2971 &Context,
2972 &InsertObject);
2973
2974 /* Check if we found an object that doesn't match the one requested */
2975 if ((NT_SUCCESS(Status)) && (InsertObject) && (Object != InsertObject))
2976 {
2977 /* This means we're opening an object, not creating a new one */
2978 OpenReason = ObOpenHandle;
2979
2980 /* Make sure the caller said it's OK to do this */
2981 if (ObjectCreateInfo->Attributes & OBJ_OPENIF)
2982 {
2983 /* He did, but did he want this type? */
2984 if (ObjectType != OBJECT_TO_OBJECT_HEADER(InsertObject)->Type)
2985 {
2986 /* Wrong type, so fail */
2987 Status = STATUS_OBJECT_TYPE_MISMATCH;
2988 }
2989 else
2990 {
2991 /* Right type, so warn */
2992 Status = STATUS_OBJECT_NAME_EXISTS;
2993 }
2994 }
2995 else
2996 {
2997 /* Check if this was a symbolic link */
2998 if (OBJECT_TO_OBJECT_HEADER(InsertObject)->Type ==
2999 ObSymbolicLinkType)
3000 {
3001 /* Dereference it */
3002 ObDereferenceObject(InsertObject);
3003 }
3004
3005 /* Caller wanted to create a new object, fail */
3006 Status = STATUS_OBJECT_NAME_COLLISION;
3007 }
3008 }
3009
3010 /* Check if anything until now failed */
3011 if (!NT_SUCCESS(Status))
3012 {
3013 /* Cleanup after lookup */
3014 ObpReleaseLookupContext(&Context);
3015
3016 /* Remove query reference that we added */
3017 ObpDereferenceNameInfo(ObjectNameInfo);
3018
3019 /* Dereference the object and delete the access state */
3020 ObDereferenceObject(Object);
3021 if (AccessState == &LocalAccessState)
3022 {
3023 /* We used a local one; delete it */
3024 SeDeleteAccessState(AccessState);
3025 }
3026
3027 /* Return failure code */
3028 return Status;
3029 }
3030 else
3031 {
3032 /* Check if this is a symbolic link */
3033 if (ObjectType == ObSymbolicLinkType)
3034 {
3035 /* Create the internal name */
3036 ObpCreateSymbolicLinkName(Object);
3037 }
3038 }
3039 }
3040
3041 /* Now check if this object is being created */
3042 if (InsertObject == Object)
3043 {
3044 /* Check if it's named or forces security */
3045 if ((ObjectName) || (ObjectType->TypeInfo.SecurityRequired))
3046 {
3047 /* Make sure it's inserted into an object directory */
3048 if ((ObjectNameInfo) && (ObjectNameInfo->Directory))
3049 {
3050 /* Get the current descriptor */
3051 ObGetObjectSecurity(ObjectNameInfo->Directory,
3052 &ParentDescriptor,
3053 &SdAllocated);
3054 }
3055
3056 /* Now assign it */
3057 Status = ObAssignSecurity(AccessState,
3058 ParentDescriptor,
3059 Object,
3060 ObjectType);
3061
3062 /* Check if we captured one */
3063 if (ParentDescriptor)
3064 {
3065 /* We did, release it */
3066 ObReleaseObjectSecurity(ParentDescriptor, SdAllocated);
3067 }
3068 else if (NT_SUCCESS(Status))
3069 {
3070 /* Other we didn't, but we were able to use the current SD */
3071 SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor,
3072 ObjectCreateInfo->ProbeMode,
3073 TRUE);
3074
3075 /* Clear the current one */
3076 AccessState->SecurityDescriptor =
3077 ObjectCreateInfo->SecurityDescriptor = NULL;
3078 }
3079 }
3080
3081 /* Check if anything until now failed */
3082 if (!NT_SUCCESS(Status))
3083 {
3084 /* Check if the directory was added */
3085 if (Context.DirectoryLocked)
3086 {
3087 /* Weird case where we need to do a manual delete */
3088 DPRINT1("Unhandled path\n");
3089 ASSERT(FALSE);
3090 }
3091
3092 /* Cleanup the lookup */
3093 ObpReleaseLookupContext(&Context);
3094
3095 /* Remove query reference that we added */
3096 ObpDereferenceNameInfo(ObjectNameInfo);
3097
3098 /* Dereference the object and delete the access state */
3099 ObDereferenceObject(Object);
3100 if (AccessState == &LocalAccessState)
3101 {
3102 /* We used a local one; delete it */
3103 SeDeleteAccessState(AccessState);
3104 }
3105
3106 /* Return failure code */
3107 ASSERT(FALSE);
3108 return Status;
3109 }
3110 }
3111
3112 /* Save the actual status until here */
3113 RealStatus = Status;
3114
3115 /* Check if caller wants us to create a handle */
3116 ObjectHeader->ObjectCreateInfo = NULL;
3117 if (Handle)
3118 {
3119 /* Create the handle */
3120 Status = ObpCreateHandle(OpenReason,
3121 InsertObject,
3122 NULL,
3123 AccessState,
3124 ObjectPointerBias + 1,
3125 ObjectCreateInfo->Attributes,
3126 &Context,
3127 PreviousMode,
3128 NewObject,
3129 Handle);
3130 if (!NT_SUCCESS(Status))
3131 {
3132 /* If the object had a name, backout everything */
3133 if (ObjectName) ObpDeleteNameCheck(Object);
3134
3135 /* Return the status of the failure */
3136 *Handle = NULL;
3137 RealStatus = Status;
3138 }
3139
3140 /* Remove a query reference */
3141 ObpDereferenceNameInfo(ObjectNameInfo);
3142
3143 /* Remove the extra keep-alive reference */
3144 ObDereferenceObject(Object);
3145 }
3146 else
3147 {
3148 /* Otherwise, lock the object */
3149 ObpAcquireObjectLock(ObjectHeader);
3150
3151 /* And charge quota for the process to make it appear as used */
3152 RealStatus = ObpChargeQuotaForObject(ObjectHeader,
3153 ObjectType,
3154 &IsNewObject);
3155
3156 /* Release the lock */
3157 ObpReleaseObjectLock(ObjectHeader);
3158
3159 /* Check if we failed and dereference the object if so */
3160 if (!NT_SUCCESS(RealStatus)) ObDereferenceObject(Object);
3161 }
3162
3163 /* We can delete the Create Info now */
3164 ObpFreeObjectCreateInformation(ObjectCreateInfo);
3165
3166 /* Check if we created our own access state and delete it if so */
3167 if (AccessState == &LocalAccessState) SeDeleteAccessState(AccessState);
3168
3169 /* Return status code */
3170 OBTRACE(OB_HANDLE_DEBUG,
3171 "%s - returning Object with PC RS/S: %lx %lx %lx\n",
3172 __FUNCTION__,
3173 OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
3174 RealStatus, Status);
3175 return RealStatus;
3176 }
3177
3178 /*++
3179 * @name ObSetHandleAttributes
3180 * @implemented NT5.1
3181 *
3182 * The ObSetHandleAttributes routine <FILLMEIN>
3183 *
3184 * @param Handle
3185 * <FILLMEIN>.
3186 *
3187 * @param HandleFlags
3188 * <FILLMEIN>.
3189 *
3190 * @param PreviousMode
3191 * <FILLMEIN>.
3192 *
3193 * @return <FILLMEIN>.
3194 *
3195 * @remarks None.
3196 *
3197 *--*/
3198 NTSTATUS
3199 NTAPI
3200 ObSetHandleAttributes(IN HANDLE Handle,
3201 IN POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags,
3202 IN KPROCESSOR_MODE PreviousMode)
3203 {
3204 OBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleAttributesContext;
3205 BOOLEAN Result, AttachedToSystemProcess = FALSE;
3206 PHANDLE_TABLE HandleTable;
3207 KAPC_STATE ApcState;
3208 PAGED_CODE();
3209
3210 /* Check if this is a kernel handle */
3211 if (ObpIsKernelHandle(Handle, PreviousMode))
3212 {
3213 /* Use the kernel table and convert the handle */
3214 HandleTable = ObpKernelHandleTable;
3215 Handle = ObKernelHandleToHandle(Handle);
3216
3217 /* Check if we're not in the system process */
3218 if (PsGetCurrentProcess() != PsInitialSystemProcess)
3219 {
3220 /* Attach to the system process */
3221 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
3222 AttachedToSystemProcess = TRUE;
3223 }
3224 }
3225 else
3226 {
3227 /* Get the current process' handle table */
3228 HandleTable = PsGetCurrentProcess()->ObjectTable;
3229 }
3230
3231 /* Initialize the handle attribute context */
3232 SetHandleAttributesContext.PreviousMode = PreviousMode;
3233 SetHandleAttributesContext.Information = *HandleFlags;
3234
3235 /* Invoke the ObpSetHandleAttributes callback */
3236 Result = ExChangeHandle(HandleTable,
3237 Handle,
3238 ObpSetHandleAttributes,
3239 (ULONG_PTR)&SetHandleAttributesContext);
3240
3241 /* Did we attach to the system process? */
3242 if (AttachedToSystemProcess)
3243 {
3244 /* Detach from it */
3245 KeUnstackDetachProcess(&ApcState);
3246 }
3247
3248 /* Return the result as an NTSTATUS value */
3249 return Result ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
3250 }
3251
3252 /*++
3253 * @name ObCloseHandle
3254 * @implemented NT5.1
3255 *
3256 * The ObCloseHandle routine <FILLMEIN>
3257 *
3258 * @param Handle
3259 * <FILLMEIN>.
3260 *
3261 * @param AccessMode
3262 * <FILLMEIN>.
3263 *
3264 * @return <FILLMEIN>.
3265 *
3266 * @remarks None.
3267 *
3268 *--*/
3269 NTSTATUS
3270 NTAPI
3271 ObCloseHandle(IN HANDLE Handle,
3272 IN KPROCESSOR_MODE AccessMode)
3273 {
3274 /* Call the internal API */
3275 return ObpCloseHandle(Handle, AccessMode);
3276 }
3277
3278 /*++
3279 * @name NtClose
3280 * @implemented NT4
3281 *
3282 * The NtClose routine <FILLMEIN>
3283 *
3284 * @param Handle
3285 * <FILLMEIN>.
3286 *
3287 * @return <FILLMEIN>.
3288 *
3289 * @remarks None.
3290 *
3291 *--*/
3292 NTSTATUS
3293 NTAPI
3294 NtClose(IN HANDLE Handle)
3295 {
3296 /* Call the internal API */
3297 return ObpCloseHandle(Handle, ExGetPreviousMode());
3298 }
3299
3300 NTSTATUS
3301 NTAPI
3302 NtDuplicateObject(IN HANDLE SourceProcessHandle,
3303 IN HANDLE SourceHandle,
3304 IN HANDLE TargetProcessHandle OPTIONAL,
3305 OUT PHANDLE TargetHandle OPTIONAL,
3306 IN ACCESS_MASK DesiredAccess,
3307 IN ULONG HandleAttributes,
3308 IN ULONG Options)
3309 {
3310 PEPROCESS SourceProcess, TargetProcess, Target;
3311 HANDLE hTarget;
3312 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
3313 NTSTATUS Status;
3314 OBTRACE(OB_HANDLE_DEBUG,
3315 "%s - Duplicating handle: %p for %p into %p.\n",
3316 __FUNCTION__,
3317 SourceHandle,
3318 SourceProcessHandle,
3319 TargetProcessHandle);
3320
3321 /* Check if we have a target handle */
3322 if ((TargetHandle) && (PreviousMode != KernelMode))
3323 {
3324 /* Enter SEH */
3325 _SEH2_TRY
3326 {
3327 /* Probe the handle and assume failure */
3328 ProbeForWriteHandle(TargetHandle);
3329 *TargetHandle = NULL;
3330 }
3331 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3332 {
3333 /* Return the exception code */
3334 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3335 }
3336 _SEH2_END;
3337 }
3338
3339 /* Now reference the input handle */
3340 Status = ObReferenceObjectByHandle(SourceProcessHandle,
3341 PROCESS_DUP_HANDLE,
3342 PsProcessType,
3343 PreviousMode,
3344 (PVOID*)&SourceProcess,
3345 NULL);
3346 if (!NT_SUCCESS(Status)) return Status;
3347
3348 /* Check if got a target handle */
3349 if (TargetProcessHandle)
3350 {
3351 /* Now reference the output handle */
3352 Status = ObReferenceObjectByHandle(TargetProcessHandle,
3353 PROCESS_DUP_HANDLE,
3354 PsProcessType,
3355 PreviousMode,
3356 (PVOID*)&TargetProcess,
3357 NULL);
3358 if (NT_SUCCESS(Status))
3359 {
3360 /* Use this target process */
3361 Target = TargetProcess;
3362 }
3363 else
3364 {
3365 /* No target process */
3366 Target = NULL;
3367 }
3368 }
3369 else
3370 {
3371 /* No target process */
3372 Status = STATUS_SUCCESS;
3373 Target = NULL;
3374 }
3375
3376 /* Call the internal routine */
3377 Status = ObDuplicateObject(SourceProcess,
3378 SourceHandle,
3379 Target,
3380 &hTarget,
3381 DesiredAccess,
3382 HandleAttributes,
3383 Options,
3384 PreviousMode);
3385
3386 /* Check if the caller wanted the return handle */
3387 if (TargetHandle)
3388 {
3389 /* Protect the write to user mode */
3390 _SEH2_TRY
3391 {
3392 /* Write the new handle */
3393 *TargetHandle = hTarget;
3394 }
3395 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3396 {
3397 /* Otherwise, get the exception code */
3398 Status = _SEH2_GetExceptionCode();
3399 }
3400 _SEH2_END;
3401 }
3402
3403 /* Dereference the processes */
3404 OBTRACE(OB_HANDLE_DEBUG,
3405 "%s - Duplicated handle: %p into %p S %lx\n",
3406 __FUNCTION__,
3407 hTarget,
3408 TargetProcessHandle,
3409 Status);
3410 if (Target) ObDereferenceObject(Target);
3411 ObDereferenceObject(SourceProcess);
3412 return Status;
3413 }
3414
3415 BOOLEAN
3416 NTAPI
3417 ObIsKernelHandle(IN HANDLE Handle)
3418 {
3419 /* Use the inlined version. We know we are in kernel mode. */
3420 return ObpIsKernelHandle(Handle, KernelMode);
3421 }
3422
3423 /* EOF */