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