* Sync up to trunk r55544.
[reactos.git] / ntoskrnl / ob / obhandle.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/obhandle.c
5 * PURPOSE: Manages all functions related to the Object Manager handle
6 * implementation, including creating and destroying handles
7 * and/or handle tables, duplicating objects, and setting the
8 * permanent or temporary flags.
9 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
10 * Eric Kohl
11 * Thomas Weidenmueller (w3seek@reactos.org)
12 */
13
14 /* INCLUDES ******************************************************************/
15
16 #include <ntoskrnl.h>
17 #define NDEBUG
18 #include <debug.h>
19
20 PHANDLE_TABLE ObpKernelHandleTable = NULL;
21 ULONG ObpAccessProtectCloseBit = MAXIMUM_ALLOWED;
22
23 #define TAG_OB_HANDLE 'dHbO'
24
25 /* PRIVATE FUNCTIONS *********************************************************/
26
27 PHANDLE_TABLE
28 NTAPI
29 ObReferenceProcessHandleTable(IN PEPROCESS Process)
30 {
31 PHANDLE_TABLE HandleTable = NULL;
32
33 /* Lock the process */
34 if (ExAcquireRundownProtection(&Process->RundownProtect))
35 {
36 /* Get the handle table */
37 HandleTable = Process->ObjectTable;
38 if (!HandleTable)
39 {
40 /* No table, release the lock */
41 ExReleaseRundownProtection(&Process->RundownProtect);
42 }
43 }
44
45 /* Return the handle table */
46 return HandleTable;
47 }
48
49 VOID
50 NTAPI
51 ObDereferenceProcessHandleTable(IN PEPROCESS Process)
52 {
53 /* Release the process lock */
54 ExReleaseRundownProtection(&Process->RundownProtect);
55 }
56
57 ULONG
58 NTAPI
59 ObGetProcessHandleCount(IN PEPROCESS Process)
60 {
61 ULONG HandleCount;
62 PHANDLE_TABLE HandleTable;
63
64 ASSERT(Process);
65
66 /* Ensure the handle table doesn't go away while we use it */
67 HandleTable = ObReferenceProcessHandleTable(Process);
68
69 if (HandleTable != NULL)
70 {
71 /* Count the number of handles the process has */
72 HandleCount = HandleTable->HandleCount;
73
74 /* Let the handle table go */
75 ObDereferenceProcessHandleTable(Process);
76 }
77 else
78 {
79 /* No handle table, no handles */
80 HandleCount = 0;
81 }
82
83 return HandleCount;
84 }
85
86 NTSTATUS
87 NTAPI
88 ObpReferenceProcessObjectByHandle(IN HANDLE Handle,
89 IN PEPROCESS Process,
90 IN PHANDLE_TABLE HandleTable,
91 IN KPROCESSOR_MODE AccessMode,
92 OUT PVOID *Object,
93 OUT POBJECT_HANDLE_INFORMATION HandleInformation,
94 OUT PACCESS_MASK AuditMask)
95 {
96 PHANDLE_TABLE_ENTRY HandleEntry;
97 POBJECT_HEADER ObjectHeader;
98 ACCESS_MASK GrantedAccess;
99 ULONG Attributes;
100 PETHREAD Thread = PsGetCurrentThread();
101 NTSTATUS Status;
102
103 /* Assume failure */
104 *Object = NULL;
105
106 /* Check if this is a special handle */
107 if (HandleToLong(Handle) < 0)
108 {
109 /* Check if the caller wants the current process */
110 if (Handle == NtCurrentProcess())
111 {
112 /* Return handle info */
113 HandleInformation->HandleAttributes = 0;
114 HandleInformation->GrantedAccess = Process->GrantedAccess;
115
116 /* No audit mask */
117 *AuditMask = 0;
118
119 /* Reference ourselves */
120 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Process);
121 InterlockedIncrement(&ObjectHeader->PointerCount);
122
123 /* Return the pointer */
124 *Object = Process;
125 ASSERT(*Object != NULL);
126 return STATUS_SUCCESS;
127 }
128
129 /* Check if the caller wants the current thread */
130 if (Handle == NtCurrentThread())
131 {
132 /* Return handle information */
133 HandleInformation->HandleAttributes = 0;
134 HandleInformation->GrantedAccess = Thread->GrantedAccess;
135
136 /* Reference ourselves */
137 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Thread);
138 InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
139
140 /* No audit mask */
141 *AuditMask = 0;
142
143 /* Return the pointer */
144 *Object = Thread;
145 ASSERT(*Object != NULL);
146 return STATUS_SUCCESS;
147 }
148
149 /* This is a kernel handle... do we have access? */
150 if (AccessMode == KernelMode)
151 {
152 /* Use the kernel handle table and get the actual handle value */
153 Handle = ObKernelHandleToHandle(Handle);
154 HandleTable = ObpKernelHandleTable;
155 }
156 else
157 {
158 /* This is an illegal attempt to access a kernel handle */
159 return STATUS_INVALID_HANDLE;
160 }
161 }
162
163 /* Enter a critical region while we touch the handle table */
164 ASSERT(HandleTable != NULL);
165 KeEnterCriticalRegion();
166
167 /* Get the handle entry */
168 HandleEntry = ExMapHandleToPointer(HandleTable, Handle);
169 if (HandleEntry)
170 {
171 /* Get the object header and validate the type*/
172 ObjectHeader = ObpGetHandleObject(HandleEntry);
173
174 /* Get the granted access and validate it */
175 GrantedAccess = HandleEntry->GrantedAccess;
176
177 /* Mask out the internal attributes */
178 Attributes = HandleEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
179
180 /* Fill out the information */
181 HandleInformation->HandleAttributes = Attributes;
182 HandleInformation->GrantedAccess = GrantedAccess;
183
184 /* No audit mask (FIXME!) */
185 *AuditMask = 0;
186
187 /* Return the pointer */
188 *Object = &ObjectHeader->Body;
189
190 /* Add a reference */
191 InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
192
193 /* Unlock the handle */
194 ExUnlockHandleTableEntry(HandleTable, HandleEntry);
195 KeLeaveCriticalRegion();
196
197 /* Return success */
198 ASSERT(*Object != NULL);
199 return STATUS_SUCCESS;
200 }
201 else
202 {
203 /* Invalid handle */
204 Status = STATUS_INVALID_HANDLE;
205 }
206
207 /* Return failure status */
208 KeLeaveCriticalRegion();
209 return Status;
210 }
211
212 BOOLEAN
213 NTAPI
214 ObpEnumFindHandleProcedure(IN PHANDLE_TABLE_ENTRY HandleEntry,
215 IN HANDLE Handle,
216 IN PVOID Context)
217 {
218 POBJECT_HEADER ObjectHeader;
219 ACCESS_MASK GrantedAccess;
220 ULONG HandleAttributes;
221 POBP_FIND_HANDLE_DATA FindData = Context;
222
223 /* Get the object header */
224 ObjectHeader = ObpGetHandleObject(HandleEntry);
225
226 /* Make sure it's valid and matching */
227 if ((FindData->ObjectHeader) && (FindData->ObjectHeader != ObjectHeader))
228 {
229 /* No match, fail */
230 return FALSE;
231 }
232
233 /* Now attempt to match the object type */
234 if ((FindData->ObjectType) && (FindData->ObjectType != ObjectHeader->Type))
235 {
236 /* No match, fail */
237 return FALSE;
238 }
239
240 /* Check if we have extra information */
241 if (FindData->HandleInformation)
242 {
243 /* Get the granted access and attributes */
244 GrantedAccess = HandleEntry->GrantedAccess;
245 HandleAttributes = HandleEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
246
247 /* Attempt to match them */
248 if ((FindData->HandleInformation->HandleAttributes != HandleAttributes) ||
249 (FindData->HandleInformation->GrantedAccess != GrantedAccess))
250 {
251 /* No match, fail */
252 return FALSE;
253 }
254 }
255
256 /* We have a match */
257 return TRUE;
258 }
259
260 POBJECT_HANDLE_COUNT_ENTRY
261 NTAPI
262 ObpInsertHandleCount(IN POBJECT_HEADER ObjectHeader)
263 {
264 POBJECT_HEADER_HANDLE_INFO HandleInfo;
265 POBJECT_HANDLE_COUNT_ENTRY FreeEntry;
266 POBJECT_HANDLE_COUNT_DATABASE HandleDatabase, OldHandleDatabase;
267 ULONG i;
268 ULONG Size, OldSize;
269 OBJECT_HANDLE_COUNT_DATABASE SingleDatabase;
270 PAGED_CODE();
271
272 /* Get the handle info */
273 HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
274 if (!HandleInfo) return NULL;
275
276 /* Check if we only have one entry */
277 if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
278 {
279 /* Fill out the single entry */
280 SingleDatabase.CountEntries = 1;
281 SingleDatabase.HandleCountEntries[0] = HandleInfo->SingleEntry;
282
283 /* Use this as the old size */
284 OldHandleDatabase = &SingleDatabase;
285 OldSize = sizeof(SingleDatabase);
286
287 /* Now we'll have two entries, and an entire DB */
288 i = 2;
289 Size = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
290 ((i - 1) * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
291 }
292 else
293 {
294 /* We already have a DB, get the information from it */
295 OldHandleDatabase = HandleInfo->HandleCountDatabase;
296 i = OldHandleDatabase->CountEntries;
297 OldSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
298 ((i - 1) * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
299
300 /* Add 4 more entries */
301 i += 4;
302 Size = OldSize + (4 * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
303 }
304
305 /* Allocate the DB */
306 HandleDatabase = ExAllocatePoolWithTag(PagedPool, Size, TAG_OB_HANDLE);
307 if (!HandleDatabase) return NULL;
308
309 /* Copy the old database */
310 RtlCopyMemory(HandleDatabase, OldHandleDatabase, OldSize);
311
312 /* Check if we he had a single entry before */
313 if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
314 {
315 /* Now we have more */
316 ObjectHeader->Flags &= ~OB_FLAG_SINGLE_PROCESS;
317 }
318 else
319 {
320 /* Otherwise we had a DB, free it */
321 ExFreePoolWithTag(OldHandleDatabase, TAG_OB_HANDLE);
322 }
323
324 /* Find the end of the copy and zero out the new data */
325 FreeEntry = (PVOID)((ULONG_PTR)HandleDatabase + OldSize);
326 RtlZeroMemory(FreeEntry, Size - OldSize);
327
328 /* Set the new information and return the free entry */
329 HandleDatabase->CountEntries = i;
330 HandleInfo->HandleCountDatabase = HandleDatabase;
331 return FreeEntry;
332 }
333
334 NTSTATUS
335 NTAPI
336 ObpIncrementHandleDataBase(IN POBJECT_HEADER ObjectHeader,
337 IN PEPROCESS Process,
338 IN OUT PULONG NewProcessHandleCount)
339 {
340 POBJECT_HEADER_HANDLE_INFO HandleInfo;
341 POBJECT_HANDLE_COUNT_ENTRY HandleEntry, FreeEntry = NULL;
342 POBJECT_HANDLE_COUNT_DATABASE HandleDatabase;
343 ULONG i;
344 PAGED_CODE();
345
346 /* Get the handle info and check if we only have one entry */
347 HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
348 if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
349 {
350 /* Check if the entry is free */
351 if (!HandleInfo->SingleEntry.HandleCount)
352 {
353 /* Add ours */
354 HandleInfo->SingleEntry.HandleCount = 1;
355 HandleInfo->SingleEntry.Process = Process;
356
357 /* Return success and 1 handle */
358 *NewProcessHandleCount = 1;
359 return STATUS_SUCCESS;
360 }
361 else if (HandleInfo->SingleEntry.Process == Process)
362 {
363 /* Busy entry, but same process */
364 *NewProcessHandleCount = ++HandleInfo->SingleEntry.HandleCount;
365 return STATUS_SUCCESS;
366 }
367 else
368 {
369 /* Insert a new entry */
370 FreeEntry = ObpInsertHandleCount(ObjectHeader);
371 if (!FreeEntry) return STATUS_INSUFFICIENT_RESOURCES;
372 ASSERT(!FreeEntry->Process);
373 ASSERT(!FreeEntry->HandleCount);
374
375 /* Fill it out */
376 FreeEntry->Process = Process;
377 FreeEntry->HandleCount = 1;
378
379 /* Return success and 1 handle */
380 *NewProcessHandleCount = 1;
381 return STATUS_SUCCESS;
382 }
383 }
384
385 /* We have a database instead */
386 HandleDatabase = HandleInfo->HandleCountDatabase;
387 if (HandleDatabase)
388 {
389 /* Get the entries and loop them */
390 i = HandleDatabase->CountEntries;
391 HandleEntry = &HandleDatabase->HandleCountEntries[0];
392 while (i)
393 {
394 /* Check if this is a match */
395 if (HandleEntry->Process == Process)
396 {
397 /* Found it, get the process handle count */
398 *NewProcessHandleCount = ++HandleEntry->HandleCount;
399 return STATUS_SUCCESS;
400 }
401 else if (!HandleEntry->HandleCount)
402 {
403 /* Found a free entry */
404 FreeEntry = HandleEntry;
405 }
406
407 /* Keep looping */
408 HandleEntry++;
409 i--;
410 }
411
412 /* Check if we couldn't find a free entry */
413 if (!FreeEntry)
414 {
415 /* Allocate one */
416 FreeEntry = ObpInsertHandleCount(ObjectHeader);
417 if (!FreeEntry) return STATUS_INSUFFICIENT_RESOURCES;
418 ASSERT(!FreeEntry->Process);
419 ASSERT(!FreeEntry->HandleCount);
420 }
421
422 /* Fill out the entry */
423 FreeEntry->Process = Process;
424 FreeEntry->HandleCount = 1;
425 *NewProcessHandleCount = 1;
426 }
427
428 /* Return success if we got here */
429 return STATUS_SUCCESS;
430 }
431
432 NTSTATUS
433 NTAPI
434 ObpChargeQuotaForObject(IN POBJECT_HEADER ObjectHeader,
435 IN POBJECT_TYPE ObjectType,
436 OUT PBOOLEAN NewObject)
437 {
438 POBJECT_HEADER_QUOTA_INFO ObjectQuota;
439 ULONG PagedPoolCharge, NonPagedPoolCharge;
440
441 /* Get quota information */
442 ObjectQuota = OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader);
443 *NewObject = FALSE;
444
445 /* Check if this is a new object */
446 if (ObjectHeader->Flags & OB_FLAG_CREATE_INFO)
447 {
448 /* Remove the flag */
449 ObjectHeader->Flags &= ~ OB_FLAG_CREATE_INFO;
450 if (ObjectQuota)
451 {
452 /* We have a quota, get the charges */
453 PagedPoolCharge = ObjectQuota->PagedPoolCharge;
454 NonPagedPoolCharge = ObjectQuota->NonPagedPoolCharge;
455 }
456 else
457 {
458 /* Get it from the object type */
459 PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
460 NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
461 }
462
463 /* Charge the quota */
464 ObjectHeader->QuotaBlockCharged = (PVOID)1;
465 DPRINT("FIXME: Should charge: %lx %lx\n", PagedPoolCharge, NonPagedPoolCharge);
466 #if 0
467 PsChargeSharedPoolQuota(PsGetCurrentProcess(),
468 PagedPoolCharge,
469 NonPagedPoolCharge);
470 #endif
471
472 /* Check if we don't have a quota block */
473 if (!ObjectHeader->QuotaBlockCharged) return STATUS_QUOTA_EXCEEDED;
474
475 /* Now set the flag */
476 *NewObject = TRUE;
477 }
478
479 /* Return success */
480 return STATUS_SUCCESS;
481 }
482
483 NTSTATUS
484 NTAPI
485 ObpValidateAccessMask(IN PACCESS_STATE AccessState)
486 {
487 /* TODO */
488 return STATUS_SUCCESS;
489 }
490
491 /*++
492 * @name ObpDecrementHandleCount
493 *
494 * The ObpDecrementHandleCount routine <FILLMEIN>
495 *
496 * @param ObjectBody
497 * <FILLMEIN>.
498 *
499 * @param Process
500 * <FILLMEIN>.
501 *
502 * @param GrantedAccess
503 * <FILLMEIN>.
504 *
505 * @return None.
506 *
507 * @remarks None.
508 *
509 *--*/
510 VOID
511 NTAPI
512 ObpDecrementHandleCount(IN PVOID ObjectBody,
513 IN PEPROCESS Process,
514 IN ACCESS_MASK GrantedAccess,
515 IN POBJECT_TYPE ObjectType)
516 {
517 POBJECT_HEADER ObjectHeader;
518 LONG SystemHandleCount, ProcessHandleCount;
519 LONG NewCount;
520 KIRQL CalloutIrql;
521 POBJECT_HEADER_HANDLE_INFO HandleInfo;
522 POBJECT_HANDLE_COUNT_ENTRY HandleEntry;
523 POBJECT_HANDLE_COUNT_DATABASE HandleDatabase;
524 ULONG i;
525 PAGED_CODE();
526
527 /* Get the object type and header */
528 ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
529 OBTRACE(OB_HANDLE_DEBUG,
530 "%s - Decrementing count for: %p. HC PC %lx %lx\n",
531 __FUNCTION__,
532 ObjectBody,
533 ObjectHeader->HandleCount,
534 ObjectHeader->PointerCount);
535
536 /* Lock the object */
537 ObpAcquireObjectLock(ObjectHeader);
538
539 /* Set default counts */
540 SystemHandleCount = ObjectHeader->HandleCount;
541 ProcessHandleCount = 0;
542
543 /* Decrement the handle count */
544 NewCount = InterlockedDecrement(&ObjectHeader->HandleCount);
545
546 /* Check if we're out of handles and this was an exclusive object */
547 if (!(NewCount) && (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
548 {
549 /* Clear the exclusive flag */
550 OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = NULL;
551 }
552
553 /* Is the object type keeping track of handles? */
554 if (ObjectType->TypeInfo.MaintainHandleCount)
555 {
556 /* Get handle information */
557 HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
558
559 /* Check if there's only a single entry */
560 if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
561 {
562 /* It should be us */
563 ASSERT(HandleInfo->SingleEntry.Process == Process);
564 ASSERT(HandleInfo->SingleEntry.HandleCount > 0);
565
566 /* Get the handle counts */
567 ProcessHandleCount = HandleInfo->SingleEntry.HandleCount--;
568 HandleEntry = &HandleInfo->SingleEntry;
569 }
570 else
571 {
572 /* Otherwise, get the database */
573 HandleDatabase = HandleInfo->HandleCountDatabase;
574 if (HandleDatabase)
575 {
576 /* Get the entries and loop them */
577 i = HandleDatabase->CountEntries;
578 HandleEntry = &HandleDatabase->HandleCountEntries[0];
579 while (i)
580 {
581 /* Check if this is a match */
582 if ((HandleEntry->HandleCount) &&
583 (HandleEntry->Process == Process))
584 {
585 /* Found it, get the process handle count */
586 ProcessHandleCount = HandleEntry->HandleCount--;
587 break;
588 }
589
590 /* Keep looping */
591 HandleEntry++;
592 i--;
593 }
594 }
595 else
596 {
597 /* No database, so no entry */
598 HandleEntry = NULL;
599 }
600 }
601
602 /* Check if this is the last handle */
603 if (ProcessHandleCount == 1)
604 {
605 /* Then clear the entry */
606 HandleEntry->Process = NULL;
607 HandleEntry->HandleCount = 0;
608 }
609 }
610
611 /* Release the lock */
612 ObpReleaseObjectLock(ObjectHeader);
613
614 /* Check if we have a close procedure */
615 if (ObjectType->TypeInfo.CloseProcedure)
616 {
617 /* Call it */
618 ObpCalloutStart(&CalloutIrql);
619 ObjectType->TypeInfo.CloseProcedure(Process,
620 ObjectBody,
621 GrantedAccess,
622 ProcessHandleCount,
623 SystemHandleCount);
624 ObpCalloutEnd(CalloutIrql, "Close", ObjectType, ObjectBody);
625 }
626
627 /* Check if we should delete the object */
628 ObpDeleteNameCheck(ObjectBody);
629
630 /* Decrease the total number of handles for this type */
631 InterlockedDecrement((PLONG)&ObjectType->TotalNumberOfHandles);
632 OBTRACE(OB_HANDLE_DEBUG,
633 "%s - Decremented count for: %p. HC PC %lx %lx\n",
634 __FUNCTION__,
635 ObjectBody,
636 ObjectHeader->HandleCount,
637 ObjectHeader->PointerCount);
638 }
639
640 /*++
641 * @name ObpCloseHandleTableEntry
642 *
643 * The ObpCloseHandleTableEntry routine <FILLMEIN>
644 *
645 * @param HandleTable
646 * <FILLMEIN>.
647 *
648 * @param HandleEntry
649 * <FILLMEIN>.
650 *
651 * @param Handle
652 * <FILLMEIN>.
653 *
654 * @param AccessMode
655 * <FILLMEIN>.
656 *
657 * @param IgnoreHandleProtection
658 * <FILLMEIN>.
659 *
660 * @return <FILLMEIN>.
661 *
662 * @remarks None.
663 *
664 *--*/
665 NTSTATUS
666 NTAPI
667 ObpCloseHandleTableEntry(IN PHANDLE_TABLE HandleTable,
668 IN PHANDLE_TABLE_ENTRY HandleEntry,
669 IN HANDLE Handle,
670 IN KPROCESSOR_MODE AccessMode,
671 IN BOOLEAN IgnoreHandleProtection)
672 {
673 PVOID Body;
674 POBJECT_TYPE ObjectType;
675 POBJECT_HEADER ObjectHeader;
676 ACCESS_MASK GrantedAccess;
677 KIRQL CalloutIrql;
678 PAGED_CODE();
679
680 /* Get the object data */
681 ObjectHeader = ObpGetHandleObject(HandleEntry);
682 ObjectType = ObjectHeader->Type;
683 Body = &ObjectHeader->Body;
684 GrantedAccess = HandleEntry->GrantedAccess;
685 OBTRACE(OB_HANDLE_DEBUG,
686 "%s - Closing handle: %lx for %p. HC PC %lx %lx\n",
687 __FUNCTION__,
688 Handle,
689 Body,
690 ObjectHeader->HandleCount,
691 ObjectHeader->PointerCount);
692
693 /* Check if the object has an Okay To Close procedure */
694 if (ObjectType->TypeInfo.OkayToCloseProcedure)
695 {
696 /* Call it and check if it's not letting us close it */
697 ObpCalloutStart(&CalloutIrql);
698 if (!ObjectType->TypeInfo.OkayToCloseProcedure(PsGetCurrentProcess(),
699 Body,
700 Handle,
701 AccessMode))
702 {
703 /* Fail */
704 ObpCalloutEnd(CalloutIrql, "NtClose", ObjectType, Body);
705 ExUnlockHandleTableEntry(HandleTable, HandleEntry);
706 return STATUS_HANDLE_NOT_CLOSABLE;
707 }
708
709 /* Success, validate callout retrn */
710 ObpCalloutEnd(CalloutIrql, "NtClose", ObjectType, Body);
711 }
712
713 /* The callback allowed us to close it, but does the handle itself? */
714 if ((HandleEntry->ObAttributes & OBJ_PROTECT_CLOSE) &&
715 !(IgnoreHandleProtection))
716 {
717 /* It doesn't, are we from user mode? */
718 if (AccessMode != KernelMode)
719 {
720 /* We are! Unlock the entry */
721 ExUnlockHandleTableEntry(HandleTable, HandleEntry);
722
723 /* Make sure we have a debug port */
724 if (PsGetCurrentProcess()->DebugPort)
725 {
726 /* Raise an exception */
727 return KeRaiseUserException(STATUS_HANDLE_NOT_CLOSABLE);
728 }
729 else
730 {
731 /* Return the error instead */
732 return STATUS_HANDLE_NOT_CLOSABLE;
733 }
734 }
735 else
736 {
737 /* Otherwise, bugcheck the OS */
738 KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 0, 0, 0);
739 }
740 }
741
742 /* Destroy and unlock the handle entry */
743 ExDestroyHandle(HandleTable, Handle, HandleEntry);
744
745 /* Now decrement the handle count */
746 ObpDecrementHandleCount(Body,
747 PsGetCurrentProcess(),
748 GrantedAccess,
749 ObjectType);
750
751 /* Dereference the object as well */
752 ObDereferenceObject(Body);
753
754 /* Return to caller */
755 OBTRACE(OB_HANDLE_DEBUG,
756 "%s - Closed handle: %lx for %p.\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: %lx 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: %lx 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: %lx\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 (ObIsKernelHandle(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: %lx S: %lx\n",
1807 __FUNCTION__, Handle, Status);
1808 return Status;
1809 }
1810
1811 /*++
1812 * @name ObpSetHandleAttributes
1813 *
1814 * The ObpSetHandleAttributes routine <FILLMEIN>
1815 *
1816 * @param HandleTableEntry
1817 * <FILLMEIN>.
1818 *
1819 * @param Context
1820 * <FILLMEIN>.
1821 *
1822 * @return <FILLMEIN>.
1823 *
1824 * @remarks None.
1825 *
1826 *--*/
1827 BOOLEAN
1828 NTAPI
1829 ObpSetHandleAttributes(IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
1830 IN ULONG_PTR Context)
1831 {
1832 POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo = (PVOID)Context;
1833 POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1834
1835 /* Check if making the handle inheritable */
1836 if (SetHandleInfo->Information.Inherit)
1837 {
1838 /* Check if inheriting is not supported for this object */
1839 if (ObjectHeader->Type->TypeInfo.InvalidAttributes & OBJ_INHERIT)
1840 {
1841 /* Fail without changing anything */
1842 return FALSE;
1843 }
1844
1845 /* Set the flag */
1846 HandleTableEntry->ObAttributes |= OBJ_INHERIT;
1847 }
1848 else
1849 {
1850 /* Otherwise this implies we're removing the flag */
1851 HandleTableEntry->ObAttributes &= ~OBJ_INHERIT;
1852 }
1853
1854 /* Check if making the handle protected */
1855 if (SetHandleInfo->Information.ProtectFromClose)
1856 {
1857 /* Set the flag */
1858 HandleTableEntry->GrantedAccess |= ObpAccessProtectCloseBit;
1859 }
1860 else
1861 {
1862 /* Otherwise, remove it */
1863 HandleTableEntry->GrantedAccess &= ~ObpAccessProtectCloseBit;
1864 }
1865
1866 /* Return success */
1867 return TRUE;
1868 }
1869
1870 /*++
1871 * @name ObpCloseHandleCallback
1872 *
1873 * The ObpCloseHandleCallback routine <FILLMEIN>
1874 *
1875 * @param HandleTable
1876 * <FILLMEIN>.
1877 *
1878 * @param Object
1879 * <FILLMEIN>.
1880 *
1881 * @param GrantedAccess
1882 * <FILLMEIN>.
1883 *
1884 * @param Context
1885 * <FILLMEIN>.
1886 *
1887 * @return <FILLMEIN>.
1888 *
1889 * @remarks None.
1890 *
1891 *--*/
1892 BOOLEAN
1893 NTAPI
1894 ObpCloseHandleCallback(IN PHANDLE_TABLE_ENTRY HandleTableEntry,
1895 IN HANDLE Handle,
1896 IN PVOID Context)
1897 {
1898 POBP_CLOSE_HANDLE_CONTEXT CloseContext = (POBP_CLOSE_HANDLE_CONTEXT)Context;
1899
1900 /* Simply decrement the handle count */
1901 ObpCloseHandleTableEntry(CloseContext->HandleTable,
1902 HandleTableEntry,
1903 Handle,
1904 CloseContext->AccessMode,
1905 TRUE);
1906 return TRUE;
1907 }
1908
1909 /*++
1910 * @name ObpDuplicateHandleCallback
1911 *
1912 * The ObpDuplicateHandleCallback routine <FILLMEIN>
1913 *
1914 * @param HandleTable
1915 * <FILLMEIN>.
1916 *
1917 * @param HandleTableEntry
1918 * <FILLMEIN>.
1919 *
1920 * @param Context
1921 * <FILLMEIN>.
1922 *
1923 * @return <FILLMEIN>.
1924 *
1925 * @remarks None.
1926 *
1927 *--*/
1928 BOOLEAN
1929 NTAPI
1930 ObpDuplicateHandleCallback(IN PEPROCESS Process,
1931 IN PHANDLE_TABLE HandleTable,
1932 IN PHANDLE_TABLE_ENTRY OldEntry,
1933 IN PHANDLE_TABLE_ENTRY HandleTableEntry)
1934 {
1935 POBJECT_HEADER ObjectHeader;
1936 BOOLEAN Ret = FALSE;
1937 ACCESS_STATE AccessState;
1938 NTSTATUS Status;
1939 PAGED_CODE();
1940
1941 /* Make sure that the handle is inheritable */
1942 Ret = (HandleTableEntry->ObAttributes & OBJ_INHERIT) != 0;
1943 if (Ret)
1944 {
1945 /* Get the object header */
1946 ObjectHeader = ObpGetHandleObject(HandleTableEntry);
1947
1948 /* Increment the pointer count */
1949 InterlockedIncrement(&ObjectHeader->PointerCount);
1950
1951 /* Release the handle lock */
1952 ExUnlockHandleTableEntry(HandleTable, OldEntry);
1953
1954 /* Setup the access state */
1955 AccessState.PreviouslyGrantedAccess = HandleTableEntry->GrantedAccess;
1956
1957 /* Call the shared routine for incrementing handles */
1958 Status = ObpIncrementHandleCount(&ObjectHeader->Body,
1959 &AccessState,
1960 KernelMode,
1961 HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES,
1962 Process,
1963 ObInheritHandle);
1964 if (!NT_SUCCESS(Status))
1965 {
1966 /* Return failure */
1967 ObDereferenceObject(&ObjectHeader->Body);
1968 Ret = FALSE;
1969 }
1970 }
1971 else
1972 {
1973 /* Release the handle lock */
1974 ExUnlockHandleTableEntry(HandleTable, OldEntry);
1975 }
1976
1977 /* Return duplication result */
1978 return Ret;
1979 }
1980
1981 VOID
1982 NTAPI
1983 ObClearProcessHandleTable(IN PEPROCESS Process)
1984 {
1985 /* FIXME */
1986 }
1987
1988 /*++
1989 * @name ObpCreateHandleTable
1990 *
1991 * The ObpCreateHandleTable routine <FILLMEIN>
1992 *
1993 * @param Parent
1994 * <FILLMEIN>.
1995 *
1996 * @param Process
1997 * <FILLMEIN>.
1998 *
1999 * @return <FILLMEIN>.
2000 *
2001 * @remarks None.
2002 *
2003 *--*/
2004 NTSTATUS
2005 NTAPI
2006 ObInitProcess(IN PEPROCESS Parent OPTIONAL,
2007 IN PEPROCESS Process)
2008 {
2009 PHANDLE_TABLE ParentTable, ObjectTable;
2010
2011 /* Check for a parent */
2012 if (Parent)
2013 {
2014 /* Reference the parent's table */
2015 ParentTable = ObReferenceProcessHandleTable(Parent);
2016 if (!ParentTable) return STATUS_PROCESS_IS_TERMINATING;
2017
2018 /* Duplicate it */
2019 ObjectTable = ExDupHandleTable(Process,
2020 ParentTable,
2021 ObpDuplicateHandleCallback,
2022 OBJ_INHERIT);
2023 }
2024 else
2025 {
2026 /* Otherwise just create a new table */
2027 ParentTable = NULL;
2028 ObjectTable = ExCreateHandleTable(Process);
2029 }
2030
2031 /* Make sure we have a table */
2032 if (ObjectTable)
2033 {
2034 /* Associate it */
2035 Process->ObjectTable = ObjectTable;
2036
2037 /* Check for auditing */
2038 if (SeDetailedAuditingWithToken(NULL))
2039 {
2040 /* FIXME: TODO */
2041 DPRINT1("Need auditing!\n");
2042 }
2043
2044 /* Get rid of the old table now */
2045 if (ParentTable) ObDereferenceProcessHandleTable(Parent);
2046
2047 /* We are done */
2048 return STATUS_SUCCESS;
2049 }
2050 else
2051 {
2052 /* Fail */
2053 Process->ObjectTable = NULL;
2054 if (ParentTable) ObDereferenceProcessHandleTable(Parent);
2055 return STATUS_INSUFFICIENT_RESOURCES;
2056 }
2057 }
2058
2059 /*++
2060 * @name ObKillProcess
2061 *
2062 * The ObKillProcess routine <FILLMEIN>
2063 *
2064 * @param Process
2065 * <FILLMEIN>.
2066 *
2067 * @return None.
2068 *
2069 * @remarks None.
2070 *
2071 *--*/
2072 VOID
2073 NTAPI
2074 ObKillProcess(IN PEPROCESS Process)
2075 {
2076 PHANDLE_TABLE HandleTable;
2077 OBP_CLOSE_HANDLE_CONTEXT Context;
2078 BOOLEAN HardErrors;
2079 PAGED_CODE();
2080
2081 /* Wait for process rundown and then complete it */
2082 ExWaitForRundownProtectionRelease(&Process->RundownProtect);
2083 ExRundownCompleted(&Process->RundownProtect);
2084
2085 /* Get the object table */
2086 HandleTable = Process->ObjectTable;
2087 if (!HandleTable) return;
2088
2089 /* Disable hard errors while we close handles */
2090 HardErrors = IoSetThreadHardErrorMode(FALSE);
2091
2092 /* Enter a critical region */
2093 KeEnterCriticalRegion();
2094
2095 /* Fill out the context */
2096 Context.AccessMode = KernelMode;
2097 Context.HandleTable = HandleTable;
2098
2099 /* Sweep the handle table to close all handles */
2100 ExSweepHandleTable(HandleTable,
2101 ObpCloseHandleCallback,
2102 &Context);
2103 ASSERT(HandleTable->HandleCount == 0);
2104
2105 /* Leave the critical region */
2106 KeLeaveCriticalRegion();
2107
2108 /* Re-enable hard errors */
2109 IoSetThreadHardErrorMode(HardErrors);
2110
2111 /* Destroy the object table */
2112 Process->ObjectTable = NULL;
2113 ExDestroyHandleTable(HandleTable, NULL);
2114 }
2115
2116 NTSTATUS
2117 NTAPI
2118 ObDuplicateObject(IN PEPROCESS SourceProcess,
2119 IN HANDLE SourceHandle,
2120 IN PEPROCESS TargetProcess OPTIONAL,
2121 IN PHANDLE TargetHandle OPTIONAL,
2122 IN ACCESS_MASK DesiredAccess,
2123 IN ULONG HandleAttributes,
2124 IN ULONG Options,
2125 IN KPROCESSOR_MODE PreviousMode)
2126 {
2127 HANDLE_TABLE_ENTRY NewHandleEntry;
2128 BOOLEAN AttachedToProcess = FALSE;
2129 PVOID SourceObject;
2130 POBJECT_HEADER ObjectHeader;
2131 POBJECT_TYPE ObjectType;
2132 HANDLE NewHandle;
2133 KAPC_STATE ApcState;
2134 NTSTATUS Status;
2135 ACCESS_MASK TargetAccess, SourceAccess;
2136 ACCESS_STATE AccessState;
2137 PACCESS_STATE PassedAccessState = NULL;
2138 AUX_ACCESS_DATA AuxData;
2139 PHANDLE_TABLE HandleTable;
2140 OBJECT_HANDLE_INFORMATION HandleInformation;
2141 ULONG AuditMask;
2142 PAGED_CODE();
2143 OBTRACE(OB_HANDLE_DEBUG,
2144 "%s - Duplicating handle: %lx for %p into %p\n",
2145 __FUNCTION__,
2146 SourceHandle,
2147 SourceProcess,
2148 TargetProcess);
2149
2150 /* Assume failure */
2151 if (TargetHandle) *TargetHandle = NULL;
2152
2153 /* Check if we're not duplicating the same access */
2154 if (!(Options & DUPLICATE_SAME_ACCESS))
2155 {
2156 /* Validate the desired access */
2157 Status = STATUS_SUCCESS; //ObpValidateDesiredAccess(DesiredAccess);
2158 if (!NT_SUCCESS(Status)) return Status;
2159 }
2160
2161 /* Reference the object table */
2162 HandleTable = ObReferenceProcessHandleTable(SourceProcess);
2163 if (!HandleTable) return STATUS_PROCESS_IS_TERMINATING;
2164
2165 /* Reference the process object */
2166 Status = ObpReferenceProcessObjectByHandle(SourceHandle,
2167 SourceProcess,
2168 HandleTable,
2169 PreviousMode,
2170 &SourceObject,
2171 &HandleInformation,
2172 &AuditMask);
2173 if (!NT_SUCCESS(Status))
2174 {
2175 /* Fail */
2176 ObDereferenceProcessHandleTable(SourceProcess);
2177 return Status;
2178 }
2179 else
2180 {
2181 /* Check if we have to don't have to audit object close */
2182 if (!(HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE))
2183 {
2184 /* Then there is no audit mask */
2185 AuditMask = 0;
2186 }
2187 }
2188
2189 /* Check if there's no target process */
2190 if (!TargetProcess)
2191 {
2192 /* Check if the caller wanted actual duplication */
2193 if (!(Options & DUPLICATE_CLOSE_SOURCE))
2194 {
2195 /* Invalid request */
2196 Status = STATUS_INVALID_PARAMETER;
2197 }
2198 else
2199 {
2200 /* Otherwise, do the attach */
2201 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2202
2203 /* Close the handle and detach */
2204 NtClose(SourceHandle);
2205 KeUnstackDetachProcess(&ApcState);
2206 }
2207
2208 /* Return */
2209 ObDereferenceProcessHandleTable(SourceProcess);
2210 ObDereferenceObject(SourceObject);
2211 return Status;
2212 }
2213
2214 /* Get the target handle table */
2215 HandleTable = ObReferenceProcessHandleTable(TargetProcess);
2216 if (!HandleTable)
2217 {
2218 /* Check if the caller wanted us to close the handle */
2219 if (Options & DUPLICATE_CLOSE_SOURCE)
2220 {
2221 /* Do the attach */
2222 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2223
2224 /* Close the handle and detach */
2225 NtClose(SourceHandle);
2226 KeUnstackDetachProcess(&ApcState);
2227 }
2228
2229 /* Return */
2230 ObDereferenceProcessHandleTable(SourceProcess);
2231 ObDereferenceObject(SourceObject);
2232 return STATUS_PROCESS_IS_TERMINATING;
2233 }
2234
2235 /* Get the source access */
2236 SourceAccess = HandleInformation.GrantedAccess;
2237
2238 /* Check if we're not in the target process */
2239 if (TargetProcess != PsGetCurrentProcess())
2240 {
2241 /* Attach to it */
2242 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
2243 AttachedToProcess = TRUE;
2244 }
2245
2246 /* Check if we're duplicating the attributes */
2247 if (Options & DUPLICATE_SAME_ATTRIBUTES)
2248 {
2249 /* Duplicate them */
2250 HandleAttributes = HandleInformation.HandleAttributes;
2251 }
2252 else
2253 {
2254 /* Don't allow caller to bypass auditing */
2255 HandleAttributes |= HandleInformation.HandleAttributes &
2256 OBJ_AUDIT_OBJECT_CLOSE;
2257 }
2258
2259 /* Check if we're duplicating the access */
2260 if (Options & DUPLICATE_SAME_ACCESS) DesiredAccess = SourceAccess;
2261
2262 /* Get object data */
2263 ObjectHeader = OBJECT_TO_OBJECT_HEADER(SourceObject);
2264 ObjectType = ObjectHeader->Type;
2265
2266 /* Fill out the entry */
2267 RtlZeroMemory(&NewHandleEntry, sizeof(HANDLE_TABLE_ENTRY));
2268 NewHandleEntry.Object = ObjectHeader;
2269 NewHandleEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
2270
2271 /* Check if we're using a generic mask */
2272 if (DesiredAccess & GENERIC_ACCESS)
2273 {
2274 /* Map it */
2275 RtlMapGenericMask(&DesiredAccess,
2276 &ObjectType->TypeInfo.GenericMapping);
2277 }
2278
2279 /* Set the target access, always propagate ACCESS_SYSTEM_SECURITY */
2280 TargetAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
2281 ACCESS_SYSTEM_SECURITY);
2282 NewHandleEntry.GrantedAccess = TargetAccess;
2283
2284 /* Check if we're asking for new access */
2285 if (TargetAccess & ~SourceAccess)
2286 {
2287 /* We are. We need the security procedure to validate this */
2288 if (ObjectType->TypeInfo.SecurityProcedure == SeDefaultObjectMethod)
2289 {
2290 /* Use our built-in access state */
2291 PassedAccessState = &AccessState;
2292 Status = SeCreateAccessState(&AccessState,
2293 &AuxData,
2294 TargetAccess,
2295 &ObjectType->TypeInfo.GenericMapping);
2296 }
2297 else
2298 {
2299 /* Otherwise we can't allow this privilege elevation */
2300 Status = STATUS_ACCESS_DENIED;
2301 }
2302 }
2303 else
2304 {
2305 /* We don't need an access state */
2306 Status = STATUS_SUCCESS;
2307 }
2308
2309 /* Make sure the access state was created OK */
2310 if (NT_SUCCESS(Status))
2311 {
2312 /* Add a new handle */
2313 Status = ObpIncrementHandleCount(SourceObject,
2314 PassedAccessState,
2315 PreviousMode,
2316 HandleAttributes,
2317 PsGetCurrentProcess(),
2318 ObDuplicateHandle);
2319 }
2320
2321 /* Check if we were attached */
2322 if (AttachedToProcess)
2323 {
2324 /* We can safely detach now */
2325 KeUnstackDetachProcess(&ApcState);
2326 AttachedToProcess = FALSE;
2327 }
2328
2329 /* Check if we have to close the source handle */
2330 if (Options & DUPLICATE_CLOSE_SOURCE)
2331 {
2332 /* Attach and close */
2333 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
2334 NtClose(SourceHandle);
2335 KeUnstackDetachProcess(&ApcState);
2336 }
2337
2338 /* Check if we had an access state */
2339 if (PassedAccessState) SeDeleteAccessState(PassedAccessState);
2340
2341 /* Now check if incrementing actually failed */
2342 if (!NT_SUCCESS(Status))
2343 {
2344 /* Dereference handle tables */
2345 ObDereferenceProcessHandleTable(SourceProcess);
2346 ObDereferenceProcessHandleTable(TargetProcess);
2347
2348 /* Dereference the source object */
2349 ObDereferenceObject(SourceObject);
2350 return Status;
2351 }
2352
2353 /* Now create the handle */
2354 NewHandle = ExCreateHandle(HandleTable, &NewHandleEntry);
2355 if (!NewHandle)
2356 {
2357 /* Undo the increment */
2358 ObpDecrementHandleCount(SourceObject,
2359 TargetProcess,
2360 TargetAccess,
2361 ObjectType);
2362
2363 /* Deference the object and set failure status */
2364 ObDereferenceObject(SourceObject);
2365 Status = STATUS_INSUFFICIENT_RESOURCES;
2366 }
2367
2368 /* Return the handle */
2369 if (TargetHandle) *TargetHandle = NewHandle;
2370
2371 /* Dereference handle tables */
2372 ObDereferenceProcessHandleTable(SourceProcess);
2373 ObDereferenceProcessHandleTable(TargetProcess);
2374
2375 /* Return status */
2376 OBTRACE(OB_HANDLE_DEBUG,
2377 "%s - Duplicated handle: %lx for %p into %p. Source: %p HC PC %lx %lx\n",
2378 __FUNCTION__,
2379 NewHandle,
2380 SourceProcess,
2381 TargetProcess,
2382 SourceObject,
2383 ObjectHeader->PointerCount,
2384 ObjectHeader->HandleCount);
2385 return Status;
2386 }
2387
2388 /* PUBLIC FUNCTIONS *********************************************************/
2389
2390 /*++
2391 * @name ObOpenObjectByName
2392 * @implemented NT4
2393 *
2394 * The ObOpenObjectByName routine <FILLMEIN>
2395 *
2396 * @param ObjectAttributes
2397 * <FILLMEIN>.
2398 *
2399 * @param ObjectType
2400 * <FILLMEIN>.
2401 *
2402 * @param AccessMode
2403 * <FILLMEIN>.
2404 *
2405 * @param PassedAccessState
2406 * <FILLMEIN>.
2407 *
2408 * @param DesiredAccess
2409 * <FILLMEIN>.
2410 *
2411 * @param ParseContext
2412 * <FILLMEIN>.
2413 *
2414 * @param Handle
2415 * <FILLMEIN>.
2416 *
2417 * @return <FILLMEIN>.
2418 *
2419 * @remarks None.
2420 *
2421 *--*/
2422 NTSTATUS
2423 NTAPI
2424 ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
2425 IN POBJECT_TYPE ObjectType,
2426 IN KPROCESSOR_MODE AccessMode,
2427 IN PACCESS_STATE PassedAccessState,
2428 IN ACCESS_MASK DesiredAccess,
2429 IN OUT PVOID ParseContext,
2430 OUT PHANDLE Handle)
2431 {
2432 PVOID Object = NULL;
2433 UNICODE_STRING ObjectName;
2434 NTSTATUS Status;
2435 POBJECT_HEADER ObjectHeader;
2436 PGENERIC_MAPPING GenericMapping = NULL;
2437 OB_OPEN_REASON OpenReason;
2438 POB_TEMP_BUFFER TempBuffer;
2439 PAGED_CODE();
2440
2441 /* Assume failure */
2442 *Handle = NULL;
2443
2444 /* Check if we didn't get any Object Attributes */
2445 if (!ObjectAttributes)
2446 {
2447 /* Fail with special status code */
2448 return STATUS_INVALID_PARAMETER;
2449 }
2450
2451 /* Allocate the temporary buffer */
2452 TempBuffer = ExAllocatePoolWithTag(NonPagedPool,
2453 sizeof(OB_TEMP_BUFFER),
2454 TAG_OB_TEMP_STORAGE);
2455 if (!TempBuffer) return STATUS_INSUFFICIENT_RESOURCES;
2456
2457 /* Capture all the info */
2458 Status = ObpCaptureObjectCreateInformation(ObjectAttributes,
2459 AccessMode,
2460 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 /* Now do the lookup */
2495 Status = ObpLookupObjectName(TempBuffer->ObjectCreateInfo.RootDirectory,
2496 &ObjectName,
2497 TempBuffer->ObjectCreateInfo.Attributes,
2498 ObjectType,
2499 AccessMode,
2500 ParseContext,
2501 TempBuffer->ObjectCreateInfo.SecurityQos,
2502 NULL,
2503 PassedAccessState,
2504 &TempBuffer->LookupContext,
2505 &Object);
2506 if (!NT_SUCCESS(Status))
2507 {
2508 /* Cleanup after lookup */
2509 ObpReleaseLookupContext(&TempBuffer->LookupContext);
2510 goto Cleanup;
2511 }
2512
2513 /* Check if this object has create information */
2514 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2515 if (ObjectHeader->Flags & OB_FLAG_CREATE_INFO)
2516 {
2517 /* Then we are creating a new handle */
2518 OpenReason = ObCreateHandle;
2519
2520 /* Check if we still have create info */
2521 if (ObjectHeader->ObjectCreateInfo)
2522 {
2523 /* Free it */
2524 ObpFreeObjectCreateInformation(ObjectHeader->
2525 ObjectCreateInfo);
2526 ObjectHeader->ObjectCreateInfo = NULL;
2527 }
2528 }
2529 else
2530 {
2531 /* Otherwise, we are merely opening it */
2532 OpenReason = ObOpenHandle;
2533 }
2534
2535 /* Check if we have invalid object attributes */
2536 if (ObjectHeader->Type->TypeInfo.InvalidAttributes &
2537 TempBuffer->ObjectCreateInfo.Attributes)
2538 {
2539 /* Set failure code */
2540 Status = STATUS_INVALID_PARAMETER;
2541
2542 /* Cleanup after lookup */
2543 ObpReleaseLookupContext(&TempBuffer->LookupContext);
2544
2545 /* Dereference the object */
2546 ObDereferenceObject(Object);
2547 }
2548 else
2549 {
2550 /* Create the actual handle now */
2551 Status = ObpCreateHandle(OpenReason,
2552 Object,
2553 ObjectType,
2554 PassedAccessState,
2555 0,
2556 TempBuffer->ObjectCreateInfo.Attributes,
2557 &TempBuffer->LookupContext,
2558 AccessMode,
2559 NULL,
2560 Handle);
2561 if (!NT_SUCCESS(Status)) ObDereferenceObject(Object);
2562 }
2563
2564 Cleanup:
2565 /* Delete the access state */
2566 if (PassedAccessState == &TempBuffer->LocalAccessState)
2567 {
2568 SeDeleteAccessState(PassedAccessState);
2569 }
2570
2571 Quickie:
2572 /* Release the object attributes and temporary buffer */
2573 ObpReleaseObjectCreateInformation(&TempBuffer->ObjectCreateInfo);
2574 if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
2575 ExFreePoolWithTag(TempBuffer, TAG_OB_TEMP_STORAGE);
2576
2577 /* Return status */
2578 OBTRACE(OB_HANDLE_DEBUG,
2579 "%s - returning Object %p with PC S: %lx %lx\n",
2580 __FUNCTION__,
2581 Object,
2582 Object ? OBJECT_TO_OBJECT_HEADER(Object)->PointerCount : -1,
2583 Status);
2584 return Status;
2585 }
2586
2587 /*++
2588 * @name ObOpenObjectByPointer
2589 * @implemented NT4
2590 *
2591 * The ObOpenObjectByPointer routine <FILLMEIN>
2592 *
2593 * @param Object
2594 * <FILLMEIN>.
2595 *
2596 * @param HandleAttributes
2597 * <FILLMEIN>.
2598 *
2599 * @param PassedAccessState
2600 * <FILLMEIN>.
2601 *
2602 * @param DesiredAccess
2603 * <FILLMEIN>.
2604 *
2605 * @param ObjectType
2606 * <FILLMEIN>.
2607 *
2608 * @param AccessMode
2609 * <FILLMEIN>.
2610 *
2611 * @param Handle
2612 * <FILLMEIN>.
2613 *
2614 * @return <FILLMEIN>.
2615 *
2616 * @remarks None.
2617 *
2618 *--*/
2619 NTSTATUS
2620 NTAPI
2621 ObOpenObjectByPointer(IN PVOID Object,
2622 IN ULONG HandleAttributes,
2623 IN PACCESS_STATE PassedAccessState,
2624 IN ACCESS_MASK DesiredAccess,
2625 IN POBJECT_TYPE ObjectType,
2626 IN KPROCESSOR_MODE AccessMode,
2627 OUT PHANDLE Handle)
2628 {
2629 POBJECT_HEADER Header;
2630 NTSTATUS Status;
2631 ACCESS_STATE AccessState;
2632 AUX_ACCESS_DATA AuxData;
2633 PAGED_CODE();
2634
2635 /* Assume failure */
2636 *Handle = NULL;
2637
2638 /* Reference the object */
2639 Status = ObReferenceObjectByPointer(Object,
2640 0,
2641 ObjectType,
2642 AccessMode);
2643 if (!NT_SUCCESS(Status)) return Status;
2644
2645 /* Get the Header Info */
2646 Header = OBJECT_TO_OBJECT_HEADER(Object);
2647
2648 /* Check if we didn't get an access state */
2649 if (!PassedAccessState)
2650 {
2651 /* Use our built-in access state */
2652 PassedAccessState = &AccessState;
2653 Status = SeCreateAccessState(&AccessState,
2654 &AuxData,
2655 DesiredAccess,
2656 &Header->Type->TypeInfo.GenericMapping);
2657 if (!NT_SUCCESS(Status))
2658 {
2659 /* Fail */
2660 ObDereferenceObject(Object);
2661 return Status;
2662 }
2663 }
2664
2665 /* Check if we have invalid object attributes */
2666 if (Header->Type->TypeInfo.InvalidAttributes & HandleAttributes)
2667 {
2668 /* Delete the access state */
2669 if (PassedAccessState == &AccessState)
2670 {
2671 SeDeleteAccessState(PassedAccessState);
2672 }
2673
2674 /* Dereference the object */
2675 ObDereferenceObject(Object);
2676 return STATUS_INVALID_PARAMETER;
2677 }
2678
2679 /* Create the handle */
2680 Status = ObpCreateHandle(ObOpenHandle,
2681 Object,
2682 ObjectType,
2683 PassedAccessState,
2684 0,
2685 HandleAttributes,
2686 NULL,
2687 AccessMode,
2688 NULL,
2689 Handle);
2690 if (!NT_SUCCESS(Status)) ObDereferenceObject(Object);
2691
2692 /* Delete the access state */
2693 if (PassedAccessState == &AccessState)
2694 {
2695 SeDeleteAccessState(PassedAccessState);
2696 }
2697
2698 /* Return */
2699 OBTRACE(OB_HANDLE_DEBUG,
2700 "%s - returning Object with PC S: %lx %lx\n",
2701 __FUNCTION__,
2702 OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
2703 Status);
2704 return Status;
2705 }
2706
2707 /*++
2708 * @name ObFindHandleForObject
2709 * @implemented NT4
2710 *
2711 * The ObFindHandleForObject routine <FILLMEIN>
2712 *
2713 * @param Process
2714 * <FILLMEIN>.
2715 *
2716 * @param Object
2717 * <FILLMEIN>.
2718 *
2719 * @param ObjectType
2720 * <FILLMEIN>.
2721 *
2722 * @param HandleInformation
2723 * <FILLMEIN>.
2724 *
2725 * @param HandleReturn
2726 * <FILLMEIN>.
2727 *
2728 * @return <FILLMEIN>.
2729 *
2730 * @remarks None.
2731 *
2732 *--*/
2733 BOOLEAN
2734 NTAPI
2735 ObFindHandleForObject(IN PEPROCESS Process,
2736 IN PVOID Object,
2737 IN POBJECT_TYPE ObjectType,
2738 IN POBJECT_HANDLE_INFORMATION HandleInformation,
2739 OUT PHANDLE Handle)
2740 {
2741 OBP_FIND_HANDLE_DATA FindData;
2742 BOOLEAN Result = FALSE;
2743 PVOID ObjectTable;
2744
2745 /* Make sure we have an object table */
2746 ObjectTable = ObReferenceProcessHandleTable(Process);
2747 if (ObjectTable)
2748 {
2749 /* Check if we have an object */
2750 if (Object)
2751 {
2752 /* Set its header */
2753 FindData.ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2754 }
2755 else
2756 {
2757 /* Otherwise, no object to match*/
2758 FindData.ObjectHeader = NULL;
2759 }
2760
2761 /* Set other information */
2762 FindData.ObjectType = ObjectType;
2763 FindData.HandleInformation = HandleInformation;
2764
2765 /* Enumerate the handle table */
2766 if (ExEnumHandleTable(Process->ObjectTable,
2767 ObpEnumFindHandleProcedure,
2768 &FindData,
2769 Handle))
2770 {
2771 /* Set success */
2772 Result = TRUE;
2773 }
2774
2775 /* Let go of the table */
2776 ObDereferenceProcessHandleTable(Process);
2777 }
2778
2779 /* Return the result */
2780 return Result;
2781 }
2782
2783 /*++
2784 * @name ObInsertObject
2785 * @implemented NT4
2786 *
2787 * The ObInsertObject routine <FILLMEIN>
2788 *
2789 * @param Object
2790 * <FILLMEIN>.
2791 *
2792 * @param PassedAccessState
2793 * <FILLMEIN>.
2794 *
2795 * @param DesiredAccess
2796 * <FILLMEIN>.
2797 *
2798 * @param AdditionalReferences
2799 * <FILLMEIN>.
2800 *
2801 * @param ReferencedObject
2802 * <FILLMEIN>.
2803 *
2804 * @param Handle
2805 * <FILLMEIN>.
2806 *
2807 * @return <FILLMEIN>.
2808 *
2809 * @remarks None.
2810 *
2811 *--*/
2812 NTSTATUS
2813 NTAPI
2814 ObInsertObject(IN PVOID Object,
2815 IN PACCESS_STATE AccessState OPTIONAL,
2816 IN ACCESS_MASK DesiredAccess,
2817 IN ULONG ObjectPointerBias,
2818 OUT PVOID *NewObject OPTIONAL,
2819 OUT PHANDLE Handle)
2820 {
2821 POBJECT_CREATE_INFORMATION ObjectCreateInfo;
2822 POBJECT_HEADER ObjectHeader;
2823 POBJECT_TYPE ObjectType;
2824 PUNICODE_STRING ObjectName;
2825 PVOID InsertObject;
2826 PSECURITY_DESCRIPTOR ParentDescriptor = NULL;
2827 BOOLEAN SdAllocated = FALSE;
2828 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
2829 OBP_LOOKUP_CONTEXT Context;
2830 ACCESS_STATE LocalAccessState;
2831 AUX_ACCESS_DATA AuxData;
2832 OB_OPEN_REASON OpenReason;
2833 KPROCESSOR_MODE PreviousMode;
2834 NTSTATUS Status = STATUS_SUCCESS, RealStatus;
2835 BOOLEAN IsNewObject;
2836 PAGED_CODE();
2837
2838 /* Get the Header */
2839 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
2840
2841 /* Detect invalid insert */
2842 if (!(ObjectHeader->Flags & OB_FLAG_CREATE_INFO))
2843 {
2844 /* Display warning and break into debugger */
2845 DPRINT1("OB: Attempting to insert existing object %08x\n", Object);
2846 DbgBreakPoint();
2847
2848 /* Allow debugger to continue */
2849 ObDereferenceObject(Object);
2850 return STATUS_INVALID_PARAMETER;
2851 }
2852
2853 /* Get the create and name info, as well as the object type */
2854 ObjectCreateInfo = ObjectHeader->ObjectCreateInfo;
2855 ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
2856 ObjectType = ObjectHeader->Type;
2857 ObjectName = NULL;
2858
2859 /* Check if this is an named object */
2860 if ((ObjectNameInfo) && (ObjectNameInfo->Name.Buffer))
2861 {
2862 /* Get the object name */
2863 ObjectName = &ObjectNameInfo->Name;
2864 }
2865
2866 /* Sanity check */
2867 ASSERT((Handle) ||
2868 ((ObjectPointerBias == 0) &&
2869 (ObjectName == NULL) &&
2870 (ObjectType->TypeInfo.SecurityRequired) &&
2871 (NewObject == NULL)));
2872
2873 /* Check if the object is unnamed and also doesn't have security */
2874 PreviousMode = KeGetPreviousMode();
2875 if (!(ObjectType->TypeInfo.SecurityRequired) && !(ObjectName))
2876 {
2877 /* Assume failure */
2878 *Handle = NULL;
2879 ObjectHeader->ObjectCreateInfo = NULL;
2880
2881 /* Create the handle */
2882 Status = ObpCreateUnnamedHandle(Object,
2883 DesiredAccess,
2884 ObjectPointerBias + 1,
2885 ObjectCreateInfo->Attributes,
2886 PreviousMode,
2887 NewObject,
2888 Handle);
2889
2890 /* Free the create information */
2891 ObpFreeObjectCreateInformation(ObjectCreateInfo);
2892
2893 /* Release the object name information */
2894 ObpDereferenceNameInfo(ObjectNameInfo);
2895
2896 /* Remove the extra keep-alive reference */
2897 ObDereferenceObject(Object);
2898
2899 /* Return */
2900 OBTRACE(OB_HANDLE_DEBUG,
2901 "%s - returning Object with PC S: %lx %lx\n",
2902 __FUNCTION__,
2903 ObjectHeader->PointerCount,
2904 Status);
2905 return Status;
2906 }
2907
2908 /* Check if we didn't get an access state */
2909 if (!AccessState)
2910 {
2911 /* Use our built-in access state */
2912 AccessState = &LocalAccessState;
2913 Status = SeCreateAccessState(&LocalAccessState,
2914 &AuxData,
2915 DesiredAccess,
2916 &ObjectType->TypeInfo.GenericMapping);
2917 if (!NT_SUCCESS(Status))
2918 {
2919 /* Fail */
2920 ObpDereferenceNameInfo(ObjectNameInfo);
2921 ObDereferenceObject(Object);
2922 return Status;
2923 }
2924 }
2925
2926 /* Save the security descriptor */
2927 AccessState->SecurityDescriptor = ObjectCreateInfo->SecurityDescriptor;
2928
2929 /* Validate the access mask */
2930 Status = ObpValidateAccessMask(AccessState);
2931 if (!NT_SUCCESS(Status))
2932 {
2933 /* Fail */
2934 ObpDereferenceNameInfo(ObjectNameInfo);
2935 ObDereferenceObject(Object);
2936 return Status;
2937 }
2938
2939 /* Setup a lookup context */
2940 ObpInitializeLookupContext(&Context);
2941 InsertObject = Object;
2942 OpenReason = ObCreateHandle;
2943
2944 /* Check if the object is named */
2945 if (ObjectName)
2946 {
2947 /* Look it up */
2948 Status = ObpLookupObjectName(ObjectCreateInfo->RootDirectory,
2949 ObjectName,
2950 ObjectCreateInfo->Attributes,
2951 ObjectType,
2952 (ObjectHeader->Flags & OB_FLAG_KERNEL_MODE) ?
2953 KernelMode : UserMode,
2954 ObjectCreateInfo->ParseContext,
2955 ObjectCreateInfo->SecurityQos,
2956 Object,
2957 AccessState,
2958 &Context,
2959 &InsertObject);
2960
2961 /* Check if we found an object that doesn't match the one requested */
2962 if ((NT_SUCCESS(Status)) && (InsertObject) && (Object != InsertObject))
2963 {
2964 /* This means we're opening an object, not creating a new one */
2965 OpenReason = ObOpenHandle;
2966
2967 /* Make sure the caller said it's OK to do this */
2968 if (ObjectCreateInfo->Attributes & OBJ_OPENIF)
2969 {
2970 /* He did, but did he want this type? */
2971 if (ObjectType != OBJECT_TO_OBJECT_HEADER(InsertObject)->Type)
2972 {
2973 /* Wrong type, so fail */
2974 Status = STATUS_OBJECT_TYPE_MISMATCH;
2975 }
2976 else
2977 {
2978 /* Right type, so warn */
2979 Status = STATUS_OBJECT_NAME_EXISTS;
2980 }
2981 }
2982 else
2983 {
2984 /* Check if this was a symbolic link */
2985 if (OBJECT_TO_OBJECT_HEADER(InsertObject)->Type ==
2986 ObSymbolicLinkType)
2987 {
2988 /* Dereference it */
2989 ObDereferenceObject(InsertObject);
2990 }
2991
2992 /* Caller wanted to create a new object, fail */
2993 Status = STATUS_OBJECT_NAME_COLLISION;
2994 }
2995 }
2996
2997 /* Check if anything until now failed */
2998 if (!NT_SUCCESS(Status))
2999 {
3000 /* Cleanup after lookup */
3001 ObpReleaseLookupContext(&Context);
3002
3003 /* Remove query reference that we added */
3004 ObpDereferenceNameInfo(ObjectNameInfo);
3005
3006 /* Dereference the object and delete the access state */
3007 ObDereferenceObject(Object);
3008 if (AccessState == &LocalAccessState)
3009 {
3010 /* We used a local one; delete it */
3011 SeDeleteAccessState(AccessState);
3012 }
3013
3014 /* Return failure code */
3015 return Status;
3016 }
3017 else
3018 {
3019 /* Check if this is a symbolic link */
3020 if (ObjectType == ObSymbolicLinkType)
3021 {
3022 /* Create the internal name */
3023 ObpCreateSymbolicLinkName(Object);
3024 }
3025 }
3026 }
3027
3028 /* Now check if this object is being created */
3029 if (InsertObject == Object)
3030 {
3031 /* Check if it's named or forces security */
3032 if ((ObjectName) || (ObjectType->TypeInfo.SecurityRequired))
3033 {
3034 /* Make sure it's inserted into an object directory */
3035 if ((ObjectNameInfo) && (ObjectNameInfo->Directory))
3036 {
3037 /* Get the current descriptor */
3038 ObGetObjectSecurity(ObjectNameInfo->Directory,
3039 &ParentDescriptor,
3040 &SdAllocated);
3041 }
3042
3043 /* Now assign it */
3044 Status = ObAssignSecurity(AccessState,
3045 ParentDescriptor,
3046 Object,
3047 ObjectType);
3048
3049 /* Check if we captured one */
3050 if (ParentDescriptor)
3051 {
3052 /* We did, release it */
3053 ObReleaseObjectSecurity(ParentDescriptor, SdAllocated);
3054 }
3055 else if (NT_SUCCESS(Status))
3056 {
3057 /* Other we didn't, but we were able to use the current SD */
3058 SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor,
3059 ObjectCreateInfo->ProbeMode,
3060 TRUE);
3061
3062 /* Clear the current one */
3063 AccessState->SecurityDescriptor =
3064 ObjectCreateInfo->SecurityDescriptor = NULL;
3065 }
3066 }
3067
3068 /* Check if anything until now failed */
3069 if (!NT_SUCCESS(Status))
3070 {
3071 /* Check if the directory was added */
3072 if (Context.DirectoryLocked)
3073 {
3074 /* Weird case where we need to do a manual delete */
3075 DPRINT1("Unhandled path\n");
3076 ASSERT(FALSE);
3077 }
3078
3079 /* Cleanup the lookup */
3080 ObpReleaseLookupContext(&Context);
3081
3082 /* Remove query reference that we added */
3083 ObpDereferenceNameInfo(ObjectNameInfo);
3084
3085 /* Dereference the object and delete the access state */
3086 ObDereferenceObject(Object);
3087 if (AccessState == &LocalAccessState)
3088 {
3089 /* We used a local one; delete it */
3090 SeDeleteAccessState(AccessState);
3091 }
3092
3093 /* Return failure code */
3094 ASSERT(FALSE);
3095 return Status;
3096 }
3097 }
3098
3099 /* Save the actual status until here */
3100 RealStatus = Status;
3101
3102 /* Check if caller wants us to create a handle */
3103 ObjectHeader->ObjectCreateInfo = NULL;
3104 if (Handle)
3105 {
3106 /* Create the handle */
3107 Status = ObpCreateHandle(OpenReason,
3108 InsertObject,
3109 NULL,
3110 AccessState,
3111 ObjectPointerBias + 1,
3112 ObjectCreateInfo->Attributes,
3113 &Context,
3114 PreviousMode,
3115 NewObject,
3116 Handle);
3117 if (!NT_SUCCESS(Status))
3118 {
3119 /* If the object had a name, backout everything */
3120 if (ObjectName) ObpDeleteNameCheck(Object);
3121
3122 /* Return the status of the failure */
3123 *Handle = NULL;
3124 RealStatus = Status;
3125 }
3126
3127 /* Remove a query reference */
3128 ObpDereferenceNameInfo(ObjectNameInfo);
3129
3130 /* Remove the extra keep-alive reference */
3131 ObDereferenceObject(Object);
3132 }
3133 else
3134 {
3135 /* Otherwise, lock the object */
3136 ObpAcquireObjectLock(ObjectHeader);
3137
3138 /* And charge quota for the process to make it appear as used */
3139 RealStatus = ObpChargeQuotaForObject(ObjectHeader,
3140 ObjectType,
3141 &IsNewObject);
3142
3143 /* Release the lock */
3144 ObpReleaseObjectLock(ObjectHeader);
3145
3146 /* Check if we failed and dereference the object if so */
3147 if (!NT_SUCCESS(RealStatus)) ObDereferenceObject(Object);
3148 }
3149
3150 /* We can delete the Create Info now */
3151 ObpFreeObjectCreateInformation(ObjectCreateInfo);
3152
3153 /* Check if we created our own access state and delete it if so */
3154 if (AccessState == &LocalAccessState) SeDeleteAccessState(AccessState);
3155
3156 /* Return status code */
3157 OBTRACE(OB_HANDLE_DEBUG,
3158 "%s - returning Object with PC RS/S: %lx %lx %lx\n",
3159 __FUNCTION__,
3160 OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
3161 RealStatus, Status);
3162 return RealStatus;
3163 }
3164
3165 /*++
3166 * @name ObCloseHandle
3167 * @implemented NT5.1
3168 *
3169 * The ObCloseHandle routine <FILLMEIN>
3170 *
3171 * @param Handle
3172 * <FILLMEIN>.
3173 *
3174 * @param AccessMode
3175 * <FILLMEIN>.
3176 *
3177 * @return <FILLMEIN>.
3178 *
3179 * @remarks None.
3180 *
3181 *--*/
3182 NTSTATUS
3183 NTAPI
3184 ObCloseHandle(IN HANDLE Handle,
3185 IN KPROCESSOR_MODE AccessMode)
3186 {
3187 /* Call the internal API */
3188 return ObpCloseHandle(Handle, AccessMode);
3189 }
3190
3191 /*++
3192 * @name NtClose
3193 * @implemented NT4
3194 *
3195 * The NtClose routine <FILLMEIN>
3196 *
3197 * @param Handle
3198 * <FILLMEIN>.
3199 *
3200 * @return <FILLMEIN>.
3201 *
3202 * @remarks None.
3203 *
3204 *--*/
3205 NTSTATUS
3206 NTAPI
3207 NtClose(IN HANDLE Handle)
3208 {
3209 /* Call the internal API */
3210 return ObpCloseHandle(Handle, ExGetPreviousMode());
3211 }
3212
3213 NTSTATUS
3214 NTAPI
3215 NtDuplicateObject(IN HANDLE SourceProcessHandle,
3216 IN HANDLE SourceHandle,
3217 IN HANDLE TargetProcessHandle OPTIONAL,
3218 OUT PHANDLE TargetHandle OPTIONAL,
3219 IN ACCESS_MASK DesiredAccess,
3220 IN ULONG HandleAttributes,
3221 IN ULONG Options)
3222 {
3223 PEPROCESS SourceProcess, TargetProcess, Target;
3224 HANDLE hTarget;
3225 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
3226 NTSTATUS Status;
3227 OBTRACE(OB_HANDLE_DEBUG,
3228 "%s - Duplicating handle: %lx for %lx into %lx.\n",
3229 __FUNCTION__,
3230 SourceHandle,
3231 SourceProcessHandle,
3232 TargetProcessHandle);
3233
3234 /* Check if we have a target handle */
3235 if ((TargetHandle) && (PreviousMode != KernelMode))
3236 {
3237 /* Enter SEH */
3238 _SEH2_TRY
3239 {
3240 /* Probe the handle and assume failure */
3241 ProbeForWriteHandle(TargetHandle);
3242 *TargetHandle = NULL;
3243 }
3244 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3245 {
3246 /* Return the exception code */
3247 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3248 }
3249 _SEH2_END;
3250 }
3251
3252 /* Now reference the input handle */
3253 Status = ObReferenceObjectByHandle(SourceProcessHandle,
3254 PROCESS_DUP_HANDLE,
3255 PsProcessType,
3256 PreviousMode,
3257 (PVOID*)&SourceProcess,
3258 NULL);
3259 if (!NT_SUCCESS(Status)) return(Status);
3260
3261 /* Check if got a target handle */
3262 if (TargetProcessHandle)
3263 {
3264 /* Now reference the output handle */
3265 Status = ObReferenceObjectByHandle(TargetProcessHandle,
3266 PROCESS_DUP_HANDLE,
3267 PsProcessType,
3268 PreviousMode,
3269 (PVOID*)&TargetProcess,
3270 NULL);
3271 if (NT_SUCCESS(Status))
3272 {
3273 /* Use this target process */
3274 Target = TargetProcess;
3275 }
3276 else
3277 {
3278 /* No target process */
3279 Target = NULL;
3280 }
3281 }
3282 else
3283 {
3284 /* No target process */
3285 Status = STATUS_SUCCESS;
3286 Target = NULL;
3287 }
3288
3289 /* Call the internal routine */
3290 Status = ObDuplicateObject(SourceProcess,
3291 SourceHandle,
3292 Target,
3293 &hTarget,
3294 DesiredAccess,
3295 HandleAttributes,
3296 Options,
3297 PreviousMode);
3298
3299 /* Check if the caller wanted the return handle */
3300 if (TargetHandle)
3301 {
3302 /* Protect the write to user mode */
3303 _SEH2_TRY
3304 {
3305 /* Write the new handle */
3306 *TargetHandle = hTarget;
3307 }
3308 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3309 {
3310 /* Otherwise, get the exception code */
3311 Status = _SEH2_GetExceptionCode();
3312 }
3313 _SEH2_END;
3314 }
3315
3316 /* Dereference the processes */
3317 OBTRACE(OB_HANDLE_DEBUG,
3318 "%s - Duplicated handle: %lx into %lx S %lx\n",
3319 __FUNCTION__,
3320 hTarget,
3321 TargetProcessHandle,
3322 Status);
3323 if (Target) ObDereferenceObject(Target);
3324 ObDereferenceObject(SourceProcess);
3325 return Status;
3326 }
3327
3328 #undef ObIsKernelHandle
3329 BOOLEAN
3330 NTAPI
3331 ObIsKernelHandle(IN HANDLE Handle)
3332 {
3333 /* We know we're kernel mode, so just check for the kernel handle flag */
3334 return (BOOLEAN)(((ULONG_PTR)Handle & KERNEL_HANDLE_FLAG) != 0);
3335 }
3336
3337 /* EOF */