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