- use inlined probing macros for basic types
[reactos.git] / reactos / ntoskrnl / ob / handle.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: ntoskrnl/ob/handle.c
24 * PURPOSE: Managing handles
25 * PROGRAMMER: David Welch (welch@cwcom.net)
26 * REVISION HISTORY:
27 * 17/06/98: Created
28 */
29
30 /* INCLUDES ****************************************************************/
31
32 #include <ntoskrnl.h>
33 #define NDEBUG
34 #include <internal/debug.h>
35
36 #define GENERIC_ANY (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
37
38 /* GLOBALS *****************************************************************/
39
40 PHANDLE_TABLE ObpKernelHandleTable = NULL;
41
42 /* TEMPORARY HACK. DO NOT REMOVE -- Alex */
43 NTSTATUS
44 STDCALL
45 ExpDesktopCreate(PVOID ObjectBody,
46 PVOID Parent,
47 PWSTR RemainingPath,
48 POBJECT_CREATE_INFORMATION ObjectCreateInformation);
49
50 /* FUNCTIONS ***************************************************************/
51
52 static VOID
53 ObpDecrementHandleCount(PVOID ObjectBody)
54 {
55 POBJECT_HEADER ObjectHeader = BODY_TO_HEADER(ObjectBody);
56 LONG NewHandleCount = InterlockedDecrement(&ObjectHeader->HandleCount);
57 DPRINT("Header: %x\n", ObjectHeader);
58 DPRINT("NewHandleCount: %x\n", NewHandleCount);
59 DPRINT("HEADER_TO_OBJECT_NAME: %x\n", HEADER_TO_OBJECT_NAME(ObjectHeader));
60
61 if ((ObjectHeader->Type != NULL) &&
62 (ObjectHeader->Type->TypeInfo.CloseProcedure != NULL))
63 {
64 /* the handle count should be decremented but we pass the previous value
65 to the callback */
66 ObjectHeader->Type->TypeInfo.CloseProcedure(ObjectBody, NewHandleCount + 1);
67 }
68
69 if(NewHandleCount == 0)
70 {
71 if(HEADER_TO_OBJECT_NAME(ObjectHeader) &&
72 HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory != NULL &&
73 !(ObjectHeader->Flags & OB_FLAG_PERMANENT))
74 {
75 /* delete the object from the namespace when the last handle got closed.
76 Only do this if it's actually been inserted into the namespace and
77 if it's not a permanent object. */
78 ObpRemoveEntryDirectory(ObjectHeader);
79 }
80
81 /* remove the keep-alive reference */
82 ObDereferenceObject(ObjectBody);
83 }
84 }
85
86
87 NTSTATUS
88 ObpQueryHandleAttributes(HANDLE Handle,
89 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo)
90 {
91 PHANDLE_TABLE HandleTable;
92 PHANDLE_TABLE_ENTRY HandleTableEntry;
93
94 PAGED_CODE();
95
96 DPRINT("ObpQueryHandleAttributes(Handle %x)\n", Handle);
97
98 if(ObIsKernelHandle(Handle, ExGetPreviousMode()))
99 {
100 HandleTable = ObpKernelHandleTable;
101 Handle = ObKernelHandleToHandle(Handle);
102 }
103 else
104 {
105 HandleTable = PsGetCurrentProcess()->ObjectTable;
106 }
107
108 KeEnterCriticalRegion();
109
110 HandleTableEntry = ExMapHandleToPointer(HandleTable,
111 Handle);
112 if (HandleTableEntry == NULL)
113 {
114 KeLeaveCriticalRegion();
115 return STATUS_INVALID_HANDLE;
116 }
117
118 HandleInfo->Inherit = (HandleTableEntry->u1.ObAttributes & EX_HANDLE_ENTRY_INHERITABLE) != 0;
119 HandleInfo->ProtectFromClose = (HandleTableEntry->u1.ObAttributes & EX_HANDLE_ENTRY_PROTECTFROMCLOSE) != 0;
120
121 ExUnlockHandleTableEntry(HandleTable,
122 HandleTableEntry);
123
124 KeLeaveCriticalRegion();
125
126 return STATUS_SUCCESS;
127 }
128
129
130 NTSTATUS
131 ObpSetHandleAttributes(HANDLE Handle,
132 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo)
133 {
134 PHANDLE_TABLE HandleTable;
135 PHANDLE_TABLE_ENTRY HandleTableEntry;
136
137 PAGED_CODE();
138
139 DPRINT("ObpSetHandleAttributes(Handle %x)\n", Handle);
140
141 if(ObIsKernelHandle(Handle, ExGetPreviousMode()))
142 {
143 HandleTable = ObpKernelHandleTable;
144 Handle = ObKernelHandleToHandle(Handle);
145 }
146 else
147 {
148 HandleTable = PsGetCurrentProcess()->ObjectTable;
149 }
150
151 KeEnterCriticalRegion();
152
153 HandleTableEntry = ExMapHandleToPointer(HandleTable,
154 Handle);
155 if (HandleTableEntry == NULL)
156 {
157 KeLeaveCriticalRegion();
158 return STATUS_INVALID_HANDLE;
159 }
160
161 if (HandleInfo->Inherit)
162 HandleTableEntry->u1.ObAttributes |= EX_HANDLE_ENTRY_INHERITABLE;
163 else
164 HandleTableEntry->u1.ObAttributes &= ~EX_HANDLE_ENTRY_INHERITABLE;
165
166 if (HandleInfo->ProtectFromClose)
167 HandleTableEntry->u1.ObAttributes |= EX_HANDLE_ENTRY_PROTECTFROMCLOSE;
168 else
169 HandleTableEntry->u1.ObAttributes &= ~EX_HANDLE_ENTRY_PROTECTFROMCLOSE;
170
171 /* FIXME: Do we need to set anything in the object header??? */
172
173 ExUnlockHandleTableEntry(HandleTable,
174 HandleTableEntry);
175
176 KeLeaveCriticalRegion();
177
178 return STATUS_SUCCESS;
179 }
180
181
182 static NTSTATUS
183 ObpDeleteHandle(PHANDLE_TABLE HandleTable,
184 HANDLE Handle)
185 {
186 PHANDLE_TABLE_ENTRY HandleEntry;
187 PVOID Body;
188 POBJECT_HEADER ObjectHeader;
189
190 PAGED_CODE();
191
192 DPRINT("ObpDeleteHandle(Handle %x)\n",Handle);
193
194 KeEnterCriticalRegion();
195
196 HandleEntry = ExMapHandleToPointer(HandleTable,
197 Handle);
198 if(HandleEntry != NULL)
199 {
200 if(HandleEntry->u1.ObAttributes & EX_HANDLE_ENTRY_PROTECTFROMCLOSE)
201 {
202 ExUnlockHandleTableEntry(HandleTable,
203 HandleEntry);
204
205 KeLeaveCriticalRegion();
206
207 return STATUS_HANDLE_NOT_CLOSABLE;
208 }
209
210 ObjectHeader = EX_HTE_TO_HDR(HandleEntry);
211 Body = &ObjectHeader->Body;
212
213 ObpDecrementHandleCount(Body);
214
215 /* destroy and unlock the handle entry */
216 ExDestroyHandleByEntry(HandleTable,
217 HandleEntry,
218 Handle);
219
220 KeLeaveCriticalRegion();
221
222 return STATUS_SUCCESS;
223 }
224 KeLeaveCriticalRegion();
225 return STATUS_INVALID_HANDLE;
226 }
227
228
229 NTSTATUS
230 ObDuplicateObject(PEPROCESS SourceProcess,
231 PEPROCESS TargetProcess,
232 HANDLE SourceHandle,
233 PHANDLE TargetHandle,
234 ACCESS_MASK DesiredAccess,
235 BOOLEAN InheritHandle,
236 ULONG Options)
237 {
238 PHANDLE_TABLE SourceHandleTable;
239 PHANDLE_TABLE_ENTRY SourceHandleEntry;
240 HANDLE_TABLE_ENTRY NewHandleEntry;
241 PVOID ObjectBody;
242 POBJECT_HEADER ObjectHeader;
243 ULONG NewHandleCount;
244 HANDLE NewTargetHandle;
245
246 PAGED_CODE();
247
248 if(ObIsKernelHandle(SourceHandle, ExGetPreviousMode()))
249 {
250 SourceHandleTable = ObpKernelHandleTable;
251 SourceHandle = ObKernelHandleToHandle(SourceHandle);
252 }
253 else
254 {
255 SourceHandleTable = SourceProcess->ObjectTable;
256 }
257
258 KeEnterCriticalRegion();
259
260 SourceHandleEntry = ExMapHandleToPointer(SourceHandleTable,
261 SourceHandle);
262 if (SourceHandleEntry == NULL)
263 {
264 KeLeaveCriticalRegion();
265 return STATUS_INVALID_HANDLE;
266 }
267
268 ObjectHeader = EX_HTE_TO_HDR(SourceHandleEntry);
269 ObjectBody = &ObjectHeader->Body;
270
271 NewHandleEntry.u1.Object = SourceHandleEntry->u1.Object;
272 if(InheritHandle)
273 NewHandleEntry.u1.ObAttributes |= EX_HANDLE_ENTRY_INHERITABLE;
274 else
275 NewHandleEntry.u1.ObAttributes &= ~EX_HANDLE_ENTRY_INHERITABLE;
276 NewHandleEntry.u2.GrantedAccess = ((Options & DUPLICATE_SAME_ACCESS) ?
277 SourceHandleEntry->u2.GrantedAccess :
278 DesiredAccess);
279 if (Options & DUPLICATE_SAME_ACCESS)
280 {
281 NewHandleEntry.u2.GrantedAccess = SourceHandleEntry->u2.GrantedAccess;
282 }
283 else
284 {
285 if (DesiredAccess & GENERIC_ANY)
286 {
287 RtlMapGenericMask(&DesiredAccess,
288 &ObjectHeader->Type->TypeInfo.GenericMapping);
289 }
290 NewHandleEntry.u2.GrantedAccess = DesiredAccess;
291 }
292
293 /* reference the object so it doesn't get deleted after releasing the lock
294 and before creating a new handle for it */
295 ObReferenceObject(ObjectBody);
296
297 /* increment the handle count of the object, it should always be >= 2 because
298 we're holding a handle lock to this object! if the new handle count was
299 1 here, we're in big trouble... it would've been safe to increment and
300 check the handle count without using interlocked functions because the
301 entry is locked, which means the handle count can't change. */
302 NewHandleCount = InterlockedIncrement(&ObjectHeader->HandleCount);
303 ASSERT(NewHandleCount >= 2);
304
305 ExUnlockHandleTableEntry(SourceHandleTable,
306 SourceHandleEntry);
307
308 KeLeaveCriticalRegion();
309
310 /* attempt to create the new handle */
311 NewTargetHandle = ExCreateHandle(TargetProcess->ObjectTable,
312 &NewHandleEntry);
313 if (NewTargetHandle != NULL)
314 {
315 if (Options & DUPLICATE_CLOSE_SOURCE)
316 {
317 ObpDeleteHandle(SourceHandleTable,
318 SourceHandle);
319 }
320
321 ObDereferenceObject(ObjectBody);
322
323 *TargetHandle = NewTargetHandle;
324
325 return STATUS_SUCCESS;
326 }
327 else
328 {
329 /* decrement the handle count we previously incremented, but don't call the
330 closing procedure because we're not closing a handle! */
331 if(InterlockedDecrement(&ObjectHeader->HandleCount) == 0)
332 {
333 ObDereferenceObject(ObjectBody);
334 }
335
336 ObDereferenceObject(ObjectBody);
337 return STATUS_UNSUCCESSFUL;
338 }
339 }
340
341 /*
342 * @implemented
343 */
344 NTSTATUS STDCALL
345 NtDuplicateObject (IN HANDLE SourceProcessHandle,
346 IN HANDLE SourceHandle,
347 IN HANDLE TargetProcessHandle,
348 OUT PHANDLE TargetHandle OPTIONAL,
349 IN ACCESS_MASK DesiredAccess,
350 IN ULONG InheritHandle,
351 IN ULONG Options)
352 /*
353 * FUNCTION: Copies a handle from one process space to another
354 * ARGUMENTS:
355 * SourceProcessHandle = The source process owning the handle. The
356 * source process should have opened
357 * the SourceHandle with PROCESS_DUP_HANDLE
358 * access.
359 * SourceHandle = The handle to the object.
360 * TargetProcessHandle = The destination process owning the handle
361 * TargetHandle (OUT) = Caller should supply storage for the
362 * duplicated handle.
363 * DesiredAccess = The desired access to the handle.
364 * InheritHandle = Indicates wheter the new handle will be inheritable
365 * or not.
366 * Options = Specifies special actions upon duplicating the handle.
367 * Can be one of the values DUPLICATE_CLOSE_SOURCE |
368 * DUPLICATE_SAME_ACCESS. DUPLICATE_CLOSE_SOURCE specifies
369 * that the source handle should be closed after duplicating.
370 * DUPLICATE_SAME_ACCESS specifies to ignore the
371 * DesiredAccess paramter and just grant the same access to
372 * the new handle.
373 * RETURNS: Status
374 * REMARKS: This function maps to the win32 DuplicateHandle.
375 */
376 {
377 PEPROCESS SourceProcess;
378 PEPROCESS TargetProcess;
379 HANDLE hTarget;
380 KPROCESSOR_MODE PreviousMode;
381 NTSTATUS Status = STATUS_SUCCESS;
382
383 PAGED_CODE();
384
385 PreviousMode = ExGetPreviousMode();
386
387 if(TargetHandle != NULL && PreviousMode != KernelMode)
388 {
389 _SEH_TRY
390 {
391 ProbeForWriteHandle(TargetHandle);
392 }
393 _SEH_HANDLE
394 {
395 Status = _SEH_GetExceptionCode();
396 }
397 _SEH_END;
398
399 if(!NT_SUCCESS(Status))
400 {
401 return Status;
402 }
403 }
404
405 Status = ObReferenceObjectByHandle(SourceProcessHandle,
406 PROCESS_DUP_HANDLE,
407 NULL,
408 PreviousMode,
409 (PVOID*)&SourceProcess,
410 NULL);
411 if (!NT_SUCCESS(Status))
412 {
413 return(Status);
414 }
415
416 Status = ObReferenceObjectByHandle(TargetProcessHandle,
417 PROCESS_DUP_HANDLE,
418 NULL,
419 PreviousMode,
420 (PVOID*)&TargetProcess,
421 NULL);
422 if (!NT_SUCCESS(Status))
423 {
424 ObDereferenceObject(SourceProcess);
425 return(Status);
426 }
427
428 /* Check for magic handle first */
429 if (SourceHandle == NtCurrentThread() ||
430 SourceHandle == NtCurrentProcess())
431 {
432 PVOID ObjectBody;
433 POBJECT_TYPE ObjectType;
434
435 ObjectType = (SourceHandle == NtCurrentThread()) ? PsThreadType : PsProcessType;
436
437 Status = ObReferenceObjectByHandle(SourceHandle,
438 0,
439 ObjectType,
440 PreviousMode,
441 &ObjectBody,
442 NULL);
443 if(NT_SUCCESS(Status))
444 {
445 if (Options & DUPLICATE_SAME_ACCESS)
446 {
447 /* grant all access rights */
448 DesiredAccess = ((ObjectType == PsThreadType) ? THREAD_ALL_ACCESS : PROCESS_ALL_ACCESS);
449 }
450 else
451 {
452 if (DesiredAccess & GENERIC_ANY)
453 {
454 RtlMapGenericMask(&DesiredAccess,
455 &ObjectType->TypeInfo.GenericMapping);
456 }
457 }
458 Status = ObpCreateHandle(TargetProcess,
459 ObjectBody,
460 DesiredAccess,
461 InheritHandle,
462 &hTarget);
463
464 ObDereferenceObject(ObjectBody);
465
466 if (Options & DUPLICATE_CLOSE_SOURCE)
467 {
468 ObpDeleteHandle(SourceProcess->ObjectTable,
469 SourceHandle);
470 }
471 }
472 }
473 else
474 {
475 Status = ObDuplicateObject(SourceProcess,
476 TargetProcess,
477 SourceHandle,
478 &hTarget,
479 DesiredAccess,
480 InheritHandle,
481 Options);
482 }
483
484 ObDereferenceObject(TargetProcess);
485 ObDereferenceObject(SourceProcess);
486
487 if(NT_SUCCESS(Status) && TargetHandle != NULL)
488 {
489 _SEH_TRY
490 {
491 *TargetHandle = hTarget;
492 }
493 _SEH_HANDLE
494 {
495 Status = _SEH_GetExceptionCode();
496 }
497 _SEH_END;
498 }
499
500 return Status;
501 }
502
503 static VOID STDCALL
504 DeleteHandleCallback(PHANDLE_TABLE HandleTable,
505 PVOID Object,
506 ULONG GrantedAccess,
507 PVOID Context)
508 {
509 POBJECT_HEADER ObjectHeader;
510 PVOID ObjectBody;
511
512 PAGED_CODE();
513
514 ObjectHeader = EX_OBJ_TO_HDR(Object);
515 ObjectBody = &ObjectHeader->Body;
516
517 ObpDecrementHandleCount(ObjectBody);
518 }
519
520 static BOOLEAN STDCALL
521 DuplicateHandleCallback(PHANDLE_TABLE HandleTable,
522 PHANDLE_TABLE_ENTRY HandleTableEntry,
523 PVOID Context)
524 {
525 POBJECT_HEADER ObjectHeader;
526 BOOLEAN Ret = FALSE;
527
528 PAGED_CODE();
529
530 Ret = (HandleTableEntry->u1.ObAttributes & EX_HANDLE_ENTRY_INHERITABLE) != 0;
531 if(Ret)
532 {
533 ObjectHeader = EX_HTE_TO_HDR(HandleTableEntry);
534 if(InterlockedIncrement(&ObjectHeader->HandleCount) == 1)
535 {
536 ObReferenceObject(&ObjectHeader->Body);
537 }
538 }
539
540 return Ret;
541 }
542
543 VOID ObCreateHandleTable(PEPROCESS Parent,
544 BOOLEAN Inherit,
545 PEPROCESS Process)
546 /*
547 * FUNCTION: Creates a handle table for a process
548 * ARGUMENTS:
549 * Parent = Parent process (or NULL if this is the first process)
550 * Inherit = True if the process should inherit its parent's handles
551 * Process = Process whose handle table is to be created
552 */
553 {
554 PAGED_CODE();
555
556 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
557 Parent,Inherit,Process);
558 if(Parent != NULL)
559 {
560 Process->ObjectTable = ExDupHandleTable(Process,
561 DuplicateHandleCallback,
562 NULL,
563 Parent->ObjectTable);
564 }
565 else
566 {
567 Process->ObjectTable = ExCreateHandleTable(Process);
568 }
569 }
570
571
572 VOID
573 STDCALL
574 ObKillProcess(PEPROCESS Process)
575 {
576 PAGED_CODE();
577
578 ExDestroyHandleTable(Process->ObjectTable,
579 DeleteHandleCallback,
580 Process);
581 }
582
583
584 NTSTATUS
585 ObpCreateHandle(PEPROCESS Process,
586 PVOID ObjectBody,
587 ACCESS_MASK GrantedAccess,
588 BOOLEAN Inherit,
589 PHANDLE HandleReturn)
590 /*
591 * FUNCTION: Add a handle referencing an object
592 * ARGUMENTS:
593 * obj = Object body that the handle should refer to
594 * RETURNS: The created handle
595 * NOTE: The handle is valid only in the context of the current process
596 */
597 {
598 HANDLE_TABLE_ENTRY NewEntry;
599 POBJECT_HEADER ObjectHeader;
600 HANDLE Handle;
601
602 PAGED_CODE();
603
604 DPRINT("ObpCreateHandle(Process %x, obj %x)\n",Process,ObjectBody);
605
606 ASSERT(Process);
607 ASSERT(ObjectBody);
608
609 ObjectHeader = BODY_TO_HEADER(ObjectBody);
610
611 ASSERT((ULONG_PTR)ObjectHeader & EX_HANDLE_ENTRY_LOCKED);
612
613 if (GrantedAccess & MAXIMUM_ALLOWED)
614 {
615 GrantedAccess &= ~MAXIMUM_ALLOWED;
616 GrantedAccess |= GENERIC_ALL;
617 }
618
619 if (GrantedAccess & GENERIC_ANY)
620 {
621 RtlMapGenericMask(&GrantedAccess,
622 &ObjectHeader->Type->TypeInfo.GenericMapping);
623 }
624
625 NewEntry.u1.Object = ObjectHeader;
626 if(Inherit)
627 NewEntry.u1.ObAttributes |= EX_HANDLE_ENTRY_INHERITABLE;
628 else
629 NewEntry.u1.ObAttributes &= ~EX_HANDLE_ENTRY_INHERITABLE;
630 NewEntry.u2.GrantedAccess = GrantedAccess;
631
632 Handle = ExCreateHandle(Process->ObjectTable,
633 &NewEntry);
634 DPRINT("ObCreateHandle(0x%x)==0x%x [HT:0x%x]\n", ObjectHeader, Handle, Process->ObjectTable);
635 if(Handle != NULL)
636 {
637 if(InterlockedIncrement(&ObjectHeader->HandleCount) == 1)
638 {
639 ObReferenceObjectByPointer(ObjectBody,
640 0,
641 NULL,
642 UserMode);
643 }
644
645 *HandleReturn = Handle;
646
647 return STATUS_SUCCESS;
648 }
649
650 return STATUS_UNSUCCESSFUL;
651 }
652
653
654 /*
655 * @implemented
656 */
657 NTSTATUS STDCALL
658 ObQueryObjectAuditingByHandle(IN HANDLE Handle,
659 OUT PBOOLEAN GenerateOnClose)
660 {
661 PHANDLE_TABLE_ENTRY HandleEntry;
662 PEPROCESS Process;
663
664 PAGED_CODE();
665
666 DPRINT("ObQueryObjectAuditingByHandle(Handle %x)\n", Handle);
667
668 Process = PsGetCurrentProcess();
669
670 KeEnterCriticalRegion();
671
672 HandleEntry = ExMapHandleToPointer(Process->ObjectTable,
673 Handle);
674 if(HandleEntry != NULL)
675 {
676 *GenerateOnClose = (HandleEntry->u1.ObAttributes & EX_HANDLE_ENTRY_AUDITONCLOSE) != 0;
677
678 ExUnlockHandleTableEntry(Process->ObjectTable,
679 HandleEntry);
680
681 KeLeaveCriticalRegion();
682
683 return STATUS_SUCCESS;
684 }
685
686 KeLeaveCriticalRegion();
687
688 return STATUS_INVALID_HANDLE;
689 }
690
691
692 /*
693 * FUNCTION: Increments the reference count for an object and returns a
694 * pointer to its body
695 * ARGUMENTS:
696 * Handle = Handle for the object
697 * DesiredAccess = Desired access to the object
698 * ObjectType
699 * AccessMode
700 * Object (OUT) = Points to the object body on return
701 * HandleInformation (OUT) = Contains information about the handle
702 * on return
703 * RETURNS: Status
704 *
705 * @implemented
706 */
707 NTSTATUS STDCALL
708 ObReferenceObjectByHandle(HANDLE Handle,
709 ACCESS_MASK DesiredAccess,
710 POBJECT_TYPE ObjectType,
711 KPROCESSOR_MODE AccessMode,
712 PVOID* Object,
713 POBJECT_HANDLE_INFORMATION HandleInformation)
714 {
715 PHANDLE_TABLE_ENTRY HandleEntry;
716 POBJECT_HEADER ObjectHeader;
717 PHANDLE_TABLE HandleTable;
718 PVOID ObjectBody;
719 ACCESS_MASK GrantedAccess;
720 ULONG Attributes;
721
722 PAGED_CODE();
723
724 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
725 "ObjectType %x, AccessMode %d, Object %x)\n",Handle,DesiredAccess,
726 ObjectType,AccessMode,Object);
727
728 if (Handle == NULL)
729 {
730 return STATUS_INVALID_HANDLE;
731 }
732 /*
733 * Handle special handle names
734 */
735 if (Handle == NtCurrentProcess() &&
736 (ObjectType == PsProcessType || ObjectType == NULL))
737 {
738 PEPROCESS CurrentProcess = PsGetCurrentProcess();
739
740 ObReferenceObject(CurrentProcess);
741
742 if (HandleInformation != NULL)
743 {
744 HandleInformation->HandleAttributes = 0;
745 HandleInformation->GrantedAccess = PROCESS_ALL_ACCESS;
746 }
747
748 *Object = CurrentProcess;
749 DPRINT("Referencing current process %x\n", CurrentProcess);
750 return STATUS_SUCCESS;
751 }
752 else if (Handle == NtCurrentProcess())
753 {
754 CHECKPOINT;
755 return(STATUS_OBJECT_TYPE_MISMATCH);
756 }
757
758 if (Handle == NtCurrentThread() &&
759 (ObjectType == PsThreadType || ObjectType == NULL))
760 {
761 PETHREAD CurrentThread = PsGetCurrentThread();
762
763 ObReferenceObject(CurrentThread);
764
765 if (HandleInformation != NULL)
766 {
767 HandleInformation->HandleAttributes = 0;
768 HandleInformation->GrantedAccess = THREAD_ALL_ACCESS;
769 }
770
771 *Object = CurrentThread;
772 CHECKPOINT;
773 return STATUS_SUCCESS;
774 }
775 else if (Handle == NtCurrentThread())
776 {
777 CHECKPOINT;
778 return(STATUS_OBJECT_TYPE_MISMATCH);
779 }
780
781 /* desire as much access rights as possible */
782 if (DesiredAccess & MAXIMUM_ALLOWED)
783 {
784 DesiredAccess &= ~MAXIMUM_ALLOWED;
785 DesiredAccess |= GENERIC_ALL;
786 }
787
788 if(ObIsKernelHandle(Handle, AccessMode))
789 {
790 HandleTable = ObpKernelHandleTable;
791 Handle = ObKernelHandleToHandle(Handle);
792 }
793 else
794 {
795 HandleTable = PsGetCurrentProcess()->ObjectTable;
796 }
797
798 KeEnterCriticalRegion();
799
800 HandleEntry = ExMapHandleToPointer(HandleTable,
801 Handle);
802 if (HandleEntry == NULL)
803 {
804 KeLeaveCriticalRegion();
805 DPRINT("ExMapHandleToPointer() failed for handle 0x%x\n", Handle);
806 return(STATUS_INVALID_HANDLE);
807 }
808
809 ObjectHeader = EX_HTE_TO_HDR(HandleEntry);
810 ObjectBody = &ObjectHeader->Body;
811
812 DPRINT("locked1: ObjectHeader: 0x%x [HT:0x%x]\n", ObjectHeader, HandleTable);
813
814 if (ObjectType != NULL && ObjectType != ObjectHeader->Type)
815 {
816 DPRINT("ObjectType mismatch: %wZ vs %wZ (handle 0x%x)\n", &ObjectType->Name, ObjectHeader->Type ? &ObjectHeader->Type->Name : NULL, Handle);
817
818 ExUnlockHandleTableEntry(HandleTable,
819 HandleEntry);
820
821 KeLeaveCriticalRegion();
822
823 return(STATUS_OBJECT_TYPE_MISMATCH);
824 }
825
826 /* map the generic access masks if the caller asks for generic access */
827 if (DesiredAccess & GENERIC_ANY)
828 {
829 RtlMapGenericMask(&DesiredAccess,
830 &BODY_TO_HEADER(ObjectBody)->Type->TypeInfo.GenericMapping);
831 }
832
833 GrantedAccess = HandleEntry->u2.GrantedAccess;
834
835 /* Unless running as KernelMode, deny access if caller desires more access
836 rights than the handle can grant */
837 if(AccessMode != KernelMode && (~GrantedAccess & DesiredAccess))
838 {
839 ExUnlockHandleTableEntry(HandleTable,
840 HandleEntry);
841
842 KeLeaveCriticalRegion();
843
844 DPRINT1("GrantedAccess: 0x%x, ~GrantedAccess: 0x%x, DesiredAccess: 0x%x, denied: 0x%x\n", GrantedAccess, ~GrantedAccess, DesiredAccess, ~GrantedAccess & DesiredAccess);
845
846 return(STATUS_ACCESS_DENIED);
847 }
848
849 ObReferenceObject(ObjectBody);
850
851 Attributes = HandleEntry->u1.ObAttributes & (EX_HANDLE_ENTRY_PROTECTFROMCLOSE |
852 EX_HANDLE_ENTRY_INHERITABLE |
853 EX_HANDLE_ENTRY_AUDITONCLOSE);
854
855 ExUnlockHandleTableEntry(HandleTable,
856 HandleEntry);
857
858 KeLeaveCriticalRegion();
859
860 if (HandleInformation != NULL)
861 {
862 HandleInformation->HandleAttributes = Attributes;
863 HandleInformation->GrantedAccess = GrantedAccess;
864 }
865
866 *Object = ObjectBody;
867
868 return(STATUS_SUCCESS);
869 }
870
871
872 /**********************************************************************
873 * NAME EXPORTED
874 * NtClose
875 *
876 * DESCRIPTION
877 * Closes a handle reference to an object.
878 *
879 * ARGUMENTS
880 * Handle
881 * Handle to close.
882 *
883 * RETURN VALUE
884 * Status.
885 *
886 * @implemented
887 */
888 NTSTATUS STDCALL
889 NtClose(IN HANDLE Handle)
890 {
891 PHANDLE_TABLE HandleTable;
892 NTSTATUS Status;
893
894 PAGED_CODE();
895
896 if(ObIsKernelHandle(Handle, ExGetPreviousMode()))
897 {
898 HandleTable = ObpKernelHandleTable;
899 Handle = ObKernelHandleToHandle(Handle);
900 }
901 else
902 {
903 HandleTable = PsGetCurrentProcess()->ObjectTable;
904 }
905
906 Status = ObpDeleteHandle(HandleTable,
907 Handle);
908 if (!NT_SUCCESS(Status))
909 {
910 if((ExGetPreviousMode() != KernelMode) &&
911 (PsGetCurrentProcess()->ExceptionPort))
912 {
913 KeRaiseUserException(Status);
914 }
915 return Status;
916 }
917
918 return(STATUS_SUCCESS);
919 }
920
921
922 /*
923 * @implemented
924 */
925 NTSTATUS
926 STDCALL
927 ObInsertObject(IN PVOID Object,
928 IN PACCESS_STATE PassedAccessState OPTIONAL,
929 IN ACCESS_MASK DesiredAccess,
930 IN ULONG AdditionalReferences,
931 OUT PVOID* ReferencedObject OPTIONAL,
932 OUT PHANDLE Handle)
933 {
934 POBJECT_CREATE_INFORMATION ObjectCreateInfo;
935 POBJECT_HEADER Header;
936 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
937 PVOID FoundObject = NULL;
938 POBJECT_HEADER FoundHeader = NULL;
939 NTSTATUS Status = STATUS_SUCCESS;
940 UNICODE_STRING RemainingPath;
941 BOOLEAN ObjectAttached = FALSE;
942 PSECURITY_DESCRIPTOR NewSecurityDescriptor = NULL;
943 SECURITY_SUBJECT_CONTEXT SubjectContext;
944
945 PAGED_CODE();
946
947 /* Get the Header and Create Info */
948 DPRINT("ObInsertObject: %x\n", Object);
949 Header = BODY_TO_HEADER(Object);
950 ObjectCreateInfo = Header->ObjectCreateInfo;
951 ObjectNameInfo = HEADER_TO_OBJECT_NAME(Header);
952
953 /* First try to find the Object */
954 if (ObjectNameInfo && ObjectNameInfo->Name.Buffer)
955 {
956 DPRINT("Object has a name. Trying to find it: %wZ.\n", &ObjectNameInfo->Name);
957 Status = ObFindObject(ObjectCreateInfo,
958 &ObjectNameInfo->Name,
959 &FoundObject,
960 &RemainingPath,
961 NULL);
962 DPRINT("FoundObject: %x, Path: %wZ\n", FoundObject, &RemainingPath);
963 if (!NT_SUCCESS(Status))
964 {
965 DPRINT1("ObFindObject() failed! (Status 0x%x)\n", Status);
966 return Status;
967 }
968
969 if (FoundObject)
970 {
971 DPRINT("Getting header: %x\n", FoundObject);
972 FoundHeader = BODY_TO_HEADER(FoundObject);
973 }
974
975 if (FoundHeader && RemainingPath.Buffer == NULL)
976 {
977 DPRINT("Object exists\n");
978 ObDereferenceObject(FoundObject);
979 return STATUS_OBJECT_NAME_COLLISION;
980 }
981 }
982 else
983 {
984 DPRINT("No name, empty remaining path\n");
985 RtlInitUnicodeString(&RemainingPath, NULL);
986 }
987
988 if (FoundHeader && FoundHeader->Type == ObDirectoryType &&
989 RemainingPath.Buffer)
990 {
991 /* The name was changed so let's update it */
992 /* FIXME: TEMPORARY HACK This will go in ObFindObject in the next commit */
993 PVOID NewName;
994 PWSTR BufferPos = RemainingPath.Buffer;
995 ULONG Delta = 0;
996
997 ObpAddEntryDirectory(FoundObject, Header, NULL);
998 ObjectAttached = TRUE;
999
1000 ObjectNameInfo = HEADER_TO_OBJECT_NAME(Header);
1001
1002 if (BufferPos[0] == L'\\')
1003 {
1004 BufferPos++;
1005 Delta = sizeof(WCHAR);
1006 }
1007 NewName = ExAllocatePool(NonPagedPool, RemainingPath.MaximumLength - Delta);
1008 RtlMoveMemory(NewName, BufferPos, RemainingPath.MaximumLength - Delta);
1009 if (ObjectNameInfo->Name.Buffer) ExFreePool(ObjectNameInfo->Name.Buffer);
1010 ObjectNameInfo->Name.Buffer = NewName;
1011 ObjectNameInfo->Name.Length = RemainingPath.Length - Delta;
1012 ObjectNameInfo->Name.MaximumLength = RemainingPath.MaximumLength - Delta;
1013 DPRINT("Name: %S\n", ObjectNameInfo->Name.Buffer);
1014 }
1015
1016 if ((Header->Type == IoFileObjectType) ||
1017 (Header->Type == ExDesktopObjectType) ||
1018 (Header->Type->TypeInfo.OpenProcedure != NULL))
1019 {
1020 DPRINT("About to call Open Routine\n");
1021 if (Header->Type == IoFileObjectType)
1022 {
1023 /* TEMPORARY HACK. DO NOT TOUCH -- Alex */
1024 DPRINT("Calling IopCreateFile: %x\n", FoundObject);
1025 Status = IopCreateFile(&Header->Body,
1026 FoundObject,
1027 RemainingPath.Buffer,
1028 ObjectCreateInfo);
1029 DPRINT("Called IopCreateFile: %x\n", Status);
1030
1031 }
1032 else if (Header->Type == ExDesktopObjectType)
1033 {
1034 /* TEMPORARY HACK. DO NOT TOUCH -- Alex */
1035 DPRINT("Calling ExpDesktopCreate\n");
1036 Status = ExpDesktopCreate(&Header->Body,
1037 FoundObject,
1038 RemainingPath.Buffer,
1039 ObjectCreateInfo);
1040 }
1041 else if (Header->Type->TypeInfo.OpenProcedure != NULL)
1042 {
1043 DPRINT("Calling %x\n", Header->Type->TypeInfo.OpenProcedure);
1044 Status = Header->Type->TypeInfo.OpenProcedure(ObCreateHandle,
1045 &Header->Body,
1046 NULL,
1047 0,
1048 0);
1049 }
1050
1051 if (!NT_SUCCESS(Status))
1052 {
1053 DPRINT("Create Failed\n");
1054 if (ObjectAttached == TRUE)
1055 {
1056 ObpRemoveEntryDirectory(Header);
1057 }
1058 if (FoundObject)
1059 {
1060 ObDereferenceObject(FoundObject);
1061 }
1062 RtlFreeUnicodeString(&RemainingPath);
1063 return Status;
1064 }
1065 }
1066
1067 RtlFreeUnicodeString(&RemainingPath);
1068
1069 DPRINT("Security Assignment in progress\n");
1070 SeCaptureSubjectContext(&SubjectContext);
1071
1072 /* Build the new security descriptor */
1073 Status = SeAssignSecurity((FoundHeader != NULL) ? FoundHeader->SecurityDescriptor : NULL,
1074 (ObjectCreateInfo != NULL) ? ObjectCreateInfo->SecurityDescriptor : NULL,
1075 &NewSecurityDescriptor,
1076 (Header->Type == ObDirectoryType),
1077 &SubjectContext,
1078 &Header->Type->TypeInfo.GenericMapping,
1079 PagedPool);
1080
1081 if (NT_SUCCESS(Status))
1082 {
1083 DPRINT("NewSecurityDescriptor %p\n", NewSecurityDescriptor);
1084
1085 if (Header->Type->TypeInfo.SecurityProcedure != NULL)
1086 {
1087 /* Call the security method */
1088 Status = Header->Type->TypeInfo.SecurityProcedure(&Header->Body,
1089 AssignSecurityDescriptor,
1090 0,
1091 NewSecurityDescriptor,
1092 NULL,
1093 NULL,
1094 NonPagedPool,
1095 NULL);
1096 }
1097 else
1098 {
1099 /* Assign the security descriptor to the object header */
1100 Status = ObpAddSecurityDescriptor(NewSecurityDescriptor,
1101 &Header->SecurityDescriptor);
1102 DPRINT("Object security descriptor %p\n", Header->SecurityDescriptor);
1103 }
1104
1105 /* Release the new security descriptor */
1106 SeDeassignSecurity(&NewSecurityDescriptor);
1107 }
1108
1109 DPRINT("Security Complete\n");
1110 SeReleaseSubjectContext(&SubjectContext);
1111
1112 /* Create the Handle */
1113 /* HACKHACK: Because of ROS's incorrect startup, this can be called
1114 * without a valid Process until I finalize the startup patch,
1115 * so don't create a handle if this is the case. We also don't create
1116 * a handle if Handle is NULL when the Registry Code calls it, because
1117 * the registry code totally bastardizes the Ob and needs to be fixed
1118 */
1119 DPRINT("Creating handle\n");
1120 if (Handle != NULL)
1121 {
1122 Status = ObpCreateHandle(PsGetCurrentProcess(),
1123 &Header->Body,
1124 DesiredAccess,
1125 ObjectCreateInfo->Attributes & OBJ_INHERIT,
1126 Handle);
1127 DPRINT("handle Created: %d. refcount. handlecount %d %d\n",
1128 *Handle, Header->PointerCount, Header->HandleCount);
1129 }
1130
1131 /* We can delete the Create Info now */
1132 Header->ObjectCreateInfo = NULL;
1133 ObpReleaseCapturedAttributes(ObjectCreateInfo);
1134 ExFreePool(ObjectCreateInfo);
1135
1136 DPRINT("Status %x\n", Status);
1137 return Status;
1138 }
1139
1140
1141 ULONG
1142 ObpGetHandleCountByHandleTable(PHANDLE_TABLE HandleTable)
1143 {
1144 return HandleTable->HandleCount;
1145 }
1146
1147 /*
1148 * FUNCTION: Searches the handle table of a specified process whether it contains a
1149 * valid handle to the Object we're looking for. If not, it'll create one.
1150 *
1151 * NOTES:
1152 * The parameters of this function is basically a mixture of some of the parameters
1153 * of ObReferenceObjectByHandle() and ObReferenceObjectByPointer(). A little thinking
1154 * about what this function does (by it's name) makes clear what parameters it requires.
1155 * For example the AccessMode parameter of ObReferenceObjectByHandle/Pointer() is not
1156 * required at all as it only has influence on the object security. This function doesn't
1157 * want to get access to an object, it just looks for a valid handle and if it can't find
1158 * one, it'll just create one. It wouldn't make sense to check for security again as the
1159 * caller already has a pointer to the object.
1160 *
1161 * A test on an XP machine shows that this prototype appears to be correct.
1162 *
1163 * ARGUMENTS:
1164 * Process = This parameter simply describes in which handle table we're looking
1165 * for a handle to the object.
1166 * Object = The object pointer that we're looking for
1167 * ObjectType = Just a sanity check as ObReferenceObjectByHandle() and
1168 * ObReferenceObjectByPointer() provides.
1169 * HandleInformation = This one has to be the opposite meaning of the usage in
1170 * ObReferenceObjectByHandle(). If we actually found a valid
1171 * handle in the table, we need to check against the information
1172 * provided so we make sure this handle has all access rights
1173 * (and attributes?!) we need. If they don't match, we can't
1174 * use this handle and keep looking because the caller is likely
1175 * to depend on these access rights.
1176 * HandleReturn = The last parameter is the same as in ObCreateHandle(). If we could
1177 * find a suitable handle in the handle table, return this handle, if
1178 * not, we'll just create one using ObCreateHandle() with all access
1179 * rights the caller needs.
1180 *
1181 * RETURNS: Status
1182 *
1183 * @unimplemented
1184 */
1185 NTSTATUS STDCALL
1186 ObFindHandleForObject(IN PEPROCESS Process,
1187 IN PVOID Object,
1188 IN POBJECT_TYPE ObjectType,
1189 IN POBJECT_HANDLE_INFORMATION HandleInformation,
1190 OUT PHANDLE HandleReturn)
1191 {
1192 DPRINT("ObFindHandleForObject is unimplemented!\n");
1193 return STATUS_UNSUCCESSFUL;
1194 }
1195
1196 VOID
1197 ObpGetNextHandleByProcessCount(PSYSTEM_HANDLE_TABLE_ENTRY_INFO pshi,
1198 PEPROCESS Process,
1199 int Count)
1200 {
1201 ULONG P;
1202 // KIRQL oldIrql;
1203
1204 // pshi->HandleValue;
1205
1206 /*
1207 This will never work with ROS! M$, I guess uses 0 -> 65535.
1208 Ros uses 0 -> 4294967295!
1209 */
1210
1211 P = (ULONG) Process->UniqueProcessId;
1212 pshi->UniqueProcessId = (USHORT) P;
1213
1214 // KeAcquireSpinLock( &Process->HandleTable.ListLock, &oldIrql );
1215
1216 // pshi->GrantedAccess;
1217 // pshi->Object;
1218 // pshi->TypeIndex;
1219 // pshi->HandleAttributes;
1220
1221 // KeReleaseSpinLock( &Process->HandleTable.ListLock, oldIrql );
1222
1223 return;
1224 }
1225
1226
1227
1228 /* EOF */