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