merge ROS Shell without integrated explorer part into trunk
[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 EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \
37 ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
38 EX_HANDLE_ENTRY_AUDITONCLOSE)))
39 #define EX_HTE_TO_HDR(hte) ((POBJECT_HEADER)((ULONG_PTR)((hte)->u1.Object) & \
40 ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
41 EX_HANDLE_ENTRY_AUDITONCLOSE)))
42
43 #define GENERIC_ANY (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
44
45 /* GLOBALS *****************************************************************/
46
47 PHANDLE_TABLE ObpKernelHandleTable = NULL;
48
49 /* FUNCTIONS ***************************************************************/
50
51 static VOID
52 ObpDecrementHandleCount(PVOID ObjectBody)
53 {
54 POBJECT_HEADER ObjectHeader = BODY_TO_HEADER(ObjectBody);
55 LONG NewHandleCount = InterlockedDecrement(&ObjectHeader->HandleCount);
56
57 if ((ObjectHeader->ObjectType != NULL) &&
58 (ObjectHeader->ObjectType->Close != NULL))
59 {
60 /* the handle count should be decremented but we pass the previous value
61 to the callback */
62 ObjectHeader->ObjectType->Close(ObjectBody, NewHandleCount + 1);
63 }
64
65 if(NewHandleCount == 0)
66 {
67 if(ObjectHeader->Parent != NULL && !ObjectHeader->Permanent)
68 {
69 /* delete the object from the namespace when the last handle got closed.
70 Only do this if it's actually been inserted into the namespace and
71 if it's not a permanent object. */
72 ObpRemoveEntryDirectory(ObjectHeader);
73 }
74
75 /* remove the keep-alive reference */
76 ObDereferenceObject(ObjectBody);
77 }
78 }
79
80
81 NTSTATUS
82 ObpQueryHandleAttributes(HANDLE Handle,
83 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo)
84 {
85 PHANDLE_TABLE HandleTable;
86 PHANDLE_TABLE_ENTRY HandleTableEntry;
87 LONG ExHandle;
88
89 PAGED_CODE();
90
91 DPRINT("ObpQueryHandleAttributes(Handle %x)\n", Handle);
92
93 if(ObIsKernelHandle(Handle, ExGetPreviousMode()))
94 {
95 HandleTable = ObpKernelHandleTable;
96 ExHandle = HANDLE_TO_EX_HANDLE(ObKernelHandleToHandle(Handle));
97 }
98 else
99 {
100 HandleTable = PsGetCurrentProcess()->ObjectTable;
101 ExHandle = HANDLE_TO_EX_HANDLE(Handle);
102 }
103
104 KeEnterCriticalRegion();
105
106 HandleTableEntry = ExMapHandleToPointer(HandleTable,
107 ExHandle);
108 if (HandleTableEntry == NULL)
109 {
110 KeLeaveCriticalRegion();
111 return STATUS_INVALID_HANDLE;
112 }
113
114 HandleInfo->Inherit = (HandleTableEntry->u1.ObAttributes & EX_HANDLE_ENTRY_INHERITABLE) != 0;
115 HandleInfo->ProtectFromClose = (HandleTableEntry->u1.ObAttributes & EX_HANDLE_ENTRY_PROTECTFROMCLOSE) != 0;
116
117 ExUnlockHandleTableEntry(HandleTable,
118 HandleTableEntry);
119
120 KeLeaveCriticalRegion();
121
122 return STATUS_SUCCESS;
123 }
124
125
126 NTSTATUS
127 ObpSetHandleAttributes(HANDLE Handle,
128 POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo)
129 {
130 PHANDLE_TABLE HandleTable;
131 PHANDLE_TABLE_ENTRY HandleTableEntry;
132 LONG ExHandle;
133
134 PAGED_CODE();
135
136 DPRINT("ObpSetHandleAttributes(Handle %x)\n", Handle);
137
138 if(ObIsKernelHandle(Handle, ExGetPreviousMode()))
139 {
140 HandleTable = ObpKernelHandleTable;
141 ExHandle = HANDLE_TO_EX_HANDLE(ObKernelHandleToHandle(Handle));
142 }
143 else
144 {
145 HandleTable = PsGetCurrentProcess()->ObjectTable;
146 ExHandle = HANDLE_TO_EX_HANDLE(Handle);
147 }
148
149 KeEnterCriticalRegion();
150
151 HandleTableEntry = ExMapHandleToPointer(HandleTable,
152 ExHandle);
153 if (HandleTableEntry == NULL)
154 {
155 KeLeaveCriticalRegion();
156 return STATUS_INVALID_HANDLE;
157 }
158
159 if (HandleInfo->Inherit)
160 HandleTableEntry->u1.ObAttributes |= EX_HANDLE_ENTRY_INHERITABLE;
161 else
162 HandleTableEntry->u1.ObAttributes &= ~EX_HANDLE_ENTRY_INHERITABLE;
163
164 if (HandleInfo->ProtectFromClose)
165 HandleTableEntry->u1.ObAttributes |= EX_HANDLE_ENTRY_PROTECTFROMCLOSE;
166 else
167 HandleTableEntry->u1.ObAttributes &= ~EX_HANDLE_ENTRY_PROTECTFROMCLOSE;
168
169 /* FIXME: Do we need to set anything in the object header??? */
170
171 ExUnlockHandleTableEntry(HandleTable,
172 HandleTableEntry);
173
174 KeLeaveCriticalRegion();
175
176 return STATUS_SUCCESS;
177 }
178
179
180 static NTSTATUS
181 ObpDeleteHandle(PHANDLE_TABLE HandleTable,
182 HANDLE Handle)
183 {
184 PHANDLE_TABLE_ENTRY HandleEntry;
185 PVOID Body;
186 POBJECT_HEADER ObjectHeader;
187 LONG ExHandle = HANDLE_TO_EX_HANDLE(Handle);
188
189 PAGED_CODE();
190
191 DPRINT("ObpDeleteHandle(Handle %x)\n",Handle);
192
193 KeEnterCriticalRegion();
194
195 HandleEntry = ExMapHandleToPointer(HandleTable,
196 ExHandle);
197 if(HandleEntry != NULL)
198 {
199 if(HandleEntry->u1.ObAttributes & EX_HANDLE_ENTRY_PROTECTFROMCLOSE)
200 {
201 ExUnlockHandleTableEntry(HandleTable,
202 HandleEntry);
203
204 KeLeaveCriticalRegion();
205
206 return STATUS_HANDLE_NOT_CLOSABLE;
207 }
208
209 ObjectHeader = EX_HTE_TO_HDR(HandleEntry);
210 Body = HEADER_TO_BODY(ObjectHeader);
211
212 ObpDecrementHandleCount(Body);
213
214 /* destroy and unlock the handle entry */
215 ExDestroyHandleByEntry(HandleTable,
216 HandleEntry,
217 ExHandle);
218
219 KeLeaveCriticalRegion();
220
221 return STATUS_SUCCESS;
222 }
223 KeLeaveCriticalRegion();
224 return STATUS_INVALID_HANDLE;
225 }
226
227
228 NTSTATUS
229 ObDuplicateObject(PEPROCESS SourceProcess,
230 PEPROCESS TargetProcess,
231 HANDLE SourceHandle,
232 PHANDLE TargetHandle,
233 ACCESS_MASK DesiredAccess,
234 BOOLEAN InheritHandle,
235 ULONG Options)
236 {
237 PHANDLE_TABLE SourceHandleTable;
238 PHANDLE_TABLE_ENTRY SourceHandleEntry;
239 HANDLE_TABLE_ENTRY NewHandleEntry;
240 PVOID ObjectBody;
241 POBJECT_HEADER ObjectHeader;
242 LONG ExTargetHandle;
243 LONG ExSourceHandle;
244 ULONG NewHandleCount;
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 ExSourceHandle = HANDLE_TO_EX_HANDLE(SourceHandle);
259
260 KeEnterCriticalRegion();
261
262 SourceHandleEntry = ExMapHandleToPointer(SourceHandleTable,
263 ExSourceHandle);
264 if (SourceHandleEntry == NULL)
265 {
266 KeLeaveCriticalRegion();
267 return STATUS_INVALID_HANDLE;
268 }
269
270 ObjectHeader = EX_HTE_TO_HDR(SourceHandleEntry);
271 ObjectBody = HEADER_TO_BODY(ObjectHeader);
272
273 NewHandleEntry.u1.Object = SourceHandleEntry->u1.Object;
274 if(InheritHandle)
275 NewHandleEntry.u1.ObAttributes |= EX_HANDLE_ENTRY_INHERITABLE;
276 else
277 NewHandleEntry.u1.ObAttributes &= ~EX_HANDLE_ENTRY_INHERITABLE;
278 NewHandleEntry.u2.GrantedAccess = ((Options & DUPLICATE_SAME_ACCESS) ?
279 SourceHandleEntry->u2.GrantedAccess :
280 DesiredAccess);
281 if (Options & DUPLICATE_SAME_ACCESS)
282 {
283 NewHandleEntry.u2.GrantedAccess = SourceHandleEntry->u2.GrantedAccess;
284 }
285 else
286 {
287 if (DesiredAccess & GENERIC_ANY)
288 {
289 RtlMapGenericMask(&DesiredAccess,
290 ObjectHeader->ObjectType->Mapping);
291 }
292 NewHandleEntry.u2.GrantedAccess = DesiredAccess;
293 }
294
295 /* reference the object so it doesn't get deleted after releasing the lock
296 and before creating a new handle for it */
297 ObReferenceObject(ObjectBody);
298
299 /* increment the handle count of the object, it should always be >= 2 because
300 we're holding a handle lock to this object! if the new handle count was
301 1 here, we're in big trouble... it would've been safe to increment and
302 check the handle count without using interlocked functions because the
303 entry is locked, which means the handle count can't change. */
304 NewHandleCount = InterlockedIncrement(&ObjectHeader->HandleCount);
305 ASSERT(NewHandleCount >= 2);
306
307 ExUnlockHandleTableEntry(SourceHandleTable,
308 SourceHandleEntry);
309
310 KeLeaveCriticalRegion();
311
312 /* attempt to create the new handle */
313 ExTargetHandle = ExCreateHandle(TargetProcess->ObjectTable,
314 &NewHandleEntry);
315 if (ExTargetHandle != EX_INVALID_HANDLE)
316 {
317 if (Options & DUPLICATE_CLOSE_SOURCE)
318 {
319 ObpDeleteHandle(SourceHandleTable,
320 SourceHandle);
321 }
322
323 ObDereferenceObject(ObjectBody);
324
325 *TargetHandle = EX_HANDLE_TO_HANDLE(ExTargetHandle);
326
327 return STATUS_SUCCESS;
328 }
329 else
330 {
331 /* decrement the handle count we previously incremented, but don't call the
332 closing procedure because we're not closing a handle! */
333 if(InterlockedDecrement(&ObjectHeader->HandleCount) == 0)
334 {
335 ObDereferenceObject(ObjectBody);
336 }
337
338 ObDereferenceObject(ObjectBody);
339 return STATUS_UNSUCCESSFUL;
340 }
341 }
342
343 /*
344 * @implemented
345 */
346 NTSTATUS STDCALL
347 NtDuplicateObject (IN HANDLE SourceProcessHandle,
348 IN HANDLE SourceHandle,
349 IN HANDLE TargetProcessHandle,
350 OUT PHANDLE TargetHandle,
351 IN ACCESS_MASK DesiredAccess,
352 IN BOOLEAN InheritHandle,
353 ULONG Options)
354 /*
355 * FUNCTION: Copies a handle from one process space to another
356 * ARGUMENTS:
357 * SourceProcessHandle = The source process owning the handle. The
358 * source process should have opened
359 * the SourceHandle with PROCESS_DUP_HANDLE
360 * access.
361 * SourceHandle = The handle to the object.
362 * TargetProcessHandle = The destination process owning the handle
363 * TargetHandle (OUT) = Caller should supply storage for the
364 * duplicated handle.
365 * DesiredAccess = The desired access to the handle.
366 * InheritHandle = Indicates wheter the new handle will be inheritable
367 * or not.
368 * Options = Specifies special actions upon duplicating the handle.
369 * Can be one of the values DUPLICATE_CLOSE_SOURCE |
370 * DUPLICATE_SAME_ACCESS. DUPLICATE_CLOSE_SOURCE specifies
371 * that the source handle should be closed after duplicating.
372 * DUPLICATE_SAME_ACCESS specifies to ignore the
373 * DesiredAccess paramter and just grant the same access to
374 * the new handle.
375 * RETURNS: Status
376 * REMARKS: This function maps to the win32 DuplicateHandle.
377 */
378 {
379 PEPROCESS SourceProcess;
380 PEPROCESS TargetProcess;
381 HANDLE hTarget;
382 KPROCESSOR_MODE PreviousMode;
383 NTSTATUS Status = STATUS_SUCCESS;
384
385 PAGED_CODE();
386
387 PreviousMode = ExGetPreviousMode();
388
389 if(PreviousMode != KernelMode)
390 {
391 _SEH_TRY
392 {
393 ProbeForWrite(TargetHandle,
394 sizeof(HANDLE),
395 sizeof(ULONG));
396 }
397 _SEH_HANDLE
398 {
399 Status = _SEH_GetExceptionCode();
400 }
401 _SEH_END;
402
403 if(!NT_SUCCESS(Status))
404 {
405 return Status;
406 }
407 }
408
409 Status = ObReferenceObjectByHandle(SourceProcessHandle,
410 PROCESS_DUP_HANDLE,
411 NULL,
412 PreviousMode,
413 (PVOID*)&SourceProcess,
414 NULL);
415 if (!NT_SUCCESS(Status))
416 {
417 return(Status);
418 }
419
420 Status = ObReferenceObjectByHandle(TargetProcessHandle,
421 PROCESS_DUP_HANDLE,
422 NULL,
423 PreviousMode,
424 (PVOID*)&TargetProcess,
425 NULL);
426 if (!NT_SUCCESS(Status))
427 {
428 ObDereferenceObject(SourceProcess);
429 return(Status);
430 }
431
432 /* Check for magic handle first */
433 if (SourceHandle == NtCurrentThread() ||
434 SourceHandle == NtCurrentProcess())
435 {
436 PVOID ObjectBody;
437 POBJECT_TYPE ObjectType;
438
439 ObjectType = (SourceHandle == NtCurrentThread()) ? PsThreadType : PsProcessType;
440
441 Status = ObReferenceObjectByHandle(SourceHandle,
442 0,
443 ObjectType,
444 PreviousMode,
445 &ObjectBody,
446 NULL);
447 if(NT_SUCCESS(Status))
448 {
449 if (Options & DUPLICATE_SAME_ACCESS)
450 {
451 /* grant all access rights */
452 DesiredAccess = ((ObjectType == PsThreadType) ? THREAD_ALL_ACCESS : PROCESS_ALL_ACCESS);
453 }
454 else
455 {
456 if (DesiredAccess & GENERIC_ANY)
457 {
458 RtlMapGenericMask(&DesiredAccess,
459 ObjectType->Mapping);
460 }
461 }
462 Status = ObCreateHandle(TargetProcess,
463 ObjectBody,
464 DesiredAccess,
465 InheritHandle,
466 &hTarget);
467
468 ObDereferenceObject(ObjectBody);
469
470 if (Options & DUPLICATE_CLOSE_SOURCE)
471 {
472 ObpDeleteHandle(SourceProcess->ObjectTable,
473 SourceHandle);
474 }
475 }
476 }
477 else
478 {
479 Status = ObDuplicateObject(SourceProcess,
480 TargetProcess,
481 SourceHandle,
482 &hTarget,
483 DesiredAccess,
484 InheritHandle,
485 Options);
486 }
487
488 ObDereferenceObject(TargetProcess);
489 ObDereferenceObject(SourceProcess);
490
491 if(NT_SUCCESS(Status))
492 {
493 _SEH_TRY
494 {
495 *TargetHandle = hTarget;
496 }
497 _SEH_HANDLE
498 {
499 Status = _SEH_GetExceptionCode();
500 }
501 _SEH_END;
502 }
503
504 return Status;
505 }
506
507 static VOID STDCALL
508 DeleteHandleCallback(PHANDLE_TABLE HandleTable,
509 PVOID Object,
510 ULONG GrantedAccess,
511 PVOID Context)
512 {
513 POBJECT_HEADER ObjectHeader;
514 PVOID ObjectBody;
515
516 PAGED_CODE();
517
518 ObjectHeader = EX_OBJ_TO_HDR(Object);
519 ObjectBody = HEADER_TO_BODY(ObjectHeader);
520
521 ObpDecrementHandleCount(ObjectBody);
522 }
523
524 static BOOLEAN STDCALL
525 DuplicateHandleCallback(PHANDLE_TABLE HandleTable,
526 PHANDLE_TABLE_ENTRY HandleTableEntry,
527 PVOID Context)
528 {
529 POBJECT_HEADER ObjectHeader;
530 BOOLEAN Ret = FALSE;
531
532 PAGED_CODE();
533
534 Ret = (HandleTableEntry->u1.ObAttributes & EX_HANDLE_ENTRY_INHERITABLE) != 0;
535 if(Ret)
536 {
537 ObjectHeader = EX_HTE_TO_HDR(HandleTableEntry);
538 if(InterlockedIncrement(&ObjectHeader->HandleCount) == 1)
539 {
540 ObReferenceObject(HEADER_TO_BODY(ObjectHeader));
541 }
542 }
543
544 return Ret;
545 }
546
547 VOID ObCreateHandleTable(PEPROCESS Parent,
548 BOOLEAN Inherit,
549 PEPROCESS Process)
550 /*
551 * FUNCTION: Creates a handle table for a process
552 * ARGUMENTS:
553 * Parent = Parent process (or NULL if this is the first process)
554 * Inherit = True if the process should inherit its parent's handles
555 * Process = Process whose handle table is to be created
556 */
557 {
558 PAGED_CODE();
559
560 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
561 Parent,Inherit,Process);
562 if(Parent != NULL)
563 {
564 Process->ObjectTable = ExDupHandleTable(Process,
565 DuplicateHandleCallback,
566 NULL,
567 Parent->ObjectTable);
568 }
569 else
570 {
571 Process->ObjectTable = ExCreateHandleTable(Process);
572 }
573 }
574
575
576 VOID
577 STDCALL
578 ObKillProcess(PEPROCESS Process)
579 {
580 PAGED_CODE();
581
582 ExDestroyHandleTable(Process->ObjectTable,
583 DeleteHandleCallback,
584 Process);
585 }
586
587
588 NTSTATUS
589 ObCreateHandle(PEPROCESS Process,
590 PVOID ObjectBody,
591 ACCESS_MASK GrantedAccess,
592 BOOLEAN Inherit,
593 PHANDLE HandleReturn)
594 /*
595 * FUNCTION: Add a handle referencing an object
596 * ARGUMENTS:
597 * obj = Object body that the handle should refer to
598 * RETURNS: The created handle
599 * NOTE: The handle is valid only in the context of the current process
600 */
601 {
602 HANDLE_TABLE_ENTRY NewEntry;
603 POBJECT_HEADER ObjectHeader;
604 LONG ExHandle;
605
606 PAGED_CODE();
607
608 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process,ObjectBody);
609
610 ASSERT(Process);
611 ASSERT(ObjectBody);
612
613 ObjectHeader = BODY_TO_HEADER(ObjectBody);
614
615 ASSERT((ULONG_PTR)ObjectHeader & EX_HANDLE_ENTRY_LOCKED);
616
617 if (GrantedAccess & MAXIMUM_ALLOWED)
618 {
619 GrantedAccess &= ~MAXIMUM_ALLOWED;
620 GrantedAccess |= GENERIC_ALL;
621 }
622
623 if (GrantedAccess & GENERIC_ANY)
624 {
625 RtlMapGenericMask(&GrantedAccess,
626 ObjectHeader->ObjectType->Mapping);
627 }
628
629 NewEntry.u1.Object = ObjectHeader;
630 if(Inherit)
631 NewEntry.u1.ObAttributes |= EX_HANDLE_ENTRY_INHERITABLE;
632 else
633 NewEntry.u1.ObAttributes &= ~EX_HANDLE_ENTRY_INHERITABLE;
634 NewEntry.u2.GrantedAccess = GrantedAccess;
635
636 ExHandle = ExCreateHandle(Process->ObjectTable,
637 &NewEntry);
638 DPRINT("ObCreateHandle(0x%x)==0x%x [HT:0x%x]\n", ObjectHeader, *HandleReturn, Process->ObjectTable);
639 if(ExHandle != EX_INVALID_HANDLE)
640 {
641 if(InterlockedIncrement(&ObjectHeader->HandleCount) == 1)
642 {
643 ObReferenceObjectByPointer(ObjectBody,
644 0,
645 NULL,
646 UserMode);
647 }
648
649 *HandleReturn = EX_HANDLE_TO_HANDLE(ExHandle);
650
651 return STATUS_SUCCESS;
652 }
653
654 return STATUS_UNSUCCESSFUL;
655 }
656
657
658 /*
659 * @implemented
660 */
661 NTSTATUS STDCALL
662 ObQueryObjectAuditingByHandle(IN HANDLE Handle,
663 OUT PBOOLEAN GenerateOnClose)
664 {
665 PHANDLE_TABLE_ENTRY HandleEntry;
666 PEPROCESS Process;
667 LONG ExHandle = HANDLE_TO_EX_HANDLE(Handle);
668
669 PAGED_CODE();
670
671 DPRINT("ObQueryObjectAuditingByHandle(Handle %x)\n", Handle);
672
673 Process = PsGetCurrentProcess();
674
675 KeEnterCriticalRegion();
676
677 HandleEntry = ExMapHandleToPointer(Process->ObjectTable,
678 ExHandle);
679 if(HandleEntry != NULL)
680 {
681 *GenerateOnClose = (HandleEntry->u1.ObAttributes & EX_HANDLE_ENTRY_AUDITONCLOSE) != 0;
682
683 ExUnlockHandleTableEntry(Process->ObjectTable,
684 HandleEntry);
685
686 KeLeaveCriticalRegion();
687
688 return STATUS_SUCCESS;
689 }
690
691 KeLeaveCriticalRegion();
692
693 return STATUS_INVALID_HANDLE;
694 }
695
696
697 /*
698 * FUNCTION: Increments the reference count for an object and returns a
699 * pointer to its body
700 * ARGUMENTS:
701 * Handle = Handle for the object
702 * DesiredAccess = Desired access to the object
703 * ObjectType
704 * AccessMode
705 * Object (OUT) = Points to the object body on return
706 * HandleInformation (OUT) = Contains information about the handle
707 * on return
708 * RETURNS: Status
709 *
710 * @implemented
711 */
712 NTSTATUS STDCALL
713 ObReferenceObjectByHandle(HANDLE Handle,
714 ACCESS_MASK DesiredAccess,
715 POBJECT_TYPE ObjectType,
716 KPROCESSOR_MODE AccessMode,
717 PVOID* Object,
718 POBJECT_HANDLE_INFORMATION HandleInformation)
719 {
720 PHANDLE_TABLE_ENTRY HandleEntry;
721 POBJECT_HEADER ObjectHeader;
722 PHANDLE_TABLE HandleTable;
723 PVOID ObjectBody;
724 ACCESS_MASK GrantedAccess;
725 ULONG Attributes;
726 LONG ExHandle;
727
728 PAGED_CODE();
729
730 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
731 "ObjectType %x, AccessMode %d, Object %x)\n",Handle,DesiredAccess,
732 ObjectType,AccessMode,Object);
733
734 /*
735 * Handle special handle names
736 */
737 if (Handle == NtCurrentProcess() &&
738 (ObjectType == PsProcessType || ObjectType == NULL))
739 {
740 PEPROCESS CurrentProcess = PsGetCurrentProcess();
741
742 ObReferenceObject(CurrentProcess);
743
744 if (HandleInformation != NULL)
745 {
746 HandleInformation->HandleAttributes = 0;
747 HandleInformation->GrantedAccess = PROCESS_ALL_ACCESS;
748 }
749
750 *Object = CurrentProcess;
751 DPRINT("Referencing current process %x\n", CurrentProcess);
752 return STATUS_SUCCESS;
753 }
754 else if (Handle == NtCurrentProcess())
755 {
756 CHECKPOINT;
757 return(STATUS_OBJECT_TYPE_MISMATCH);
758 }
759
760 if (Handle == NtCurrentThread() &&
761 (ObjectType == PsThreadType || ObjectType == NULL))
762 {
763 PETHREAD CurrentThread = PsGetCurrentThread();
764
765 ObReferenceObject(CurrentThread);
766
767 if (HandleInformation != NULL)
768 {
769 HandleInformation->HandleAttributes = 0;
770 HandleInformation->GrantedAccess = THREAD_ALL_ACCESS;
771 }
772
773 *Object = CurrentThread;
774 CHECKPOINT;
775 return STATUS_SUCCESS;
776 }
777 else if (Handle == NtCurrentThread())
778 {
779 CHECKPOINT;
780 return(STATUS_OBJECT_TYPE_MISMATCH);
781 }
782
783 /* desire as much access rights as possible */
784 if (DesiredAccess & MAXIMUM_ALLOWED)
785 {
786 DesiredAccess &= ~MAXIMUM_ALLOWED;
787 DesiredAccess |= GENERIC_ALL;
788 }
789
790 if(ObIsKernelHandle(Handle, AccessMode))
791 {
792 HandleTable = ObpKernelHandleTable;
793 ExHandle = HANDLE_TO_EX_HANDLE(ObKernelHandleToHandle(Handle));
794 }
795 else
796 {
797 HandleTable = PsGetCurrentProcess()->ObjectTable;
798 ExHandle = HANDLE_TO_EX_HANDLE(Handle);
799 }
800
801 KeEnterCriticalRegion();
802
803 HandleEntry = ExMapHandleToPointer(HandleTable,
804 ExHandle);
805 if (HandleEntry == NULL)
806 {
807 KeLeaveCriticalRegion();
808 DPRINT("ExMapHandleToPointer() failed for handle 0x%x\n", Handle);
809 return(STATUS_INVALID_HANDLE);
810 }
811
812 ObjectHeader = EX_HTE_TO_HDR(HandleEntry);
813 ObjectBody = HEADER_TO_BODY(ObjectHeader);
814
815 DPRINT("locked1: ObjectHeader: 0x%x [HT:0x%x]\n", ObjectHeader, HandleTable);
816
817 if (ObjectType != NULL && ObjectType != ObjectHeader->ObjectType)
818 {
819 DPRINT("ObjectType mismatch: %wZ vs %wZ (handle 0x%x)\n", &ObjectType->TypeName, ObjectHeader->ObjectType ? &ObjectHeader->ObjectType->TypeName : NULL, Handle);
820
821 ExUnlockHandleTableEntry(HandleTable,
822 HandleEntry);
823
824 KeLeaveCriticalRegion();
825
826 return(STATUS_OBJECT_TYPE_MISMATCH);
827 }
828
829 /* map the generic access masks if the caller asks for generic access */
830 if (DesiredAccess & GENERIC_ANY)
831 {
832 RtlMapGenericMask(&DesiredAccess,
833 BODY_TO_HEADER(ObjectBody)->ObjectType->Mapping);
834 }
835
836 GrantedAccess = HandleEntry->u2.GrantedAccess;
837
838 /* Unless running as KernelMode, deny access if caller desires more access
839 rights than the handle can grant */
840 if(AccessMode != KernelMode && (~GrantedAccess & DesiredAccess))
841 {
842 ExUnlockHandleTableEntry(HandleTable,
843 HandleEntry);
844
845 KeLeaveCriticalRegion();
846
847 DPRINT1("GrantedAccess: 0x%x, ~GrantedAccess: 0x%x, DesiredAccess: 0x%x, denied: 0x%x\n", GrantedAccess, ~GrantedAccess, DesiredAccess, ~GrantedAccess & DesiredAccess);
848
849 return(STATUS_ACCESS_DENIED);
850 }
851
852 ObReferenceObject(ObjectBody);
853
854 Attributes = HandleEntry->u1.ObAttributes & (EX_HANDLE_ENTRY_PROTECTFROMCLOSE |
855 EX_HANDLE_ENTRY_INHERITABLE |
856 EX_HANDLE_ENTRY_AUDITONCLOSE);
857
858 ExUnlockHandleTableEntry(HandleTable,
859 HandleEntry);
860
861 KeLeaveCriticalRegion();
862
863 if (HandleInformation != NULL)
864 {
865 HandleInformation->HandleAttributes = Attributes;
866 HandleInformation->GrantedAccess = GrantedAccess;
867 }
868
869 *Object = ObjectBody;
870
871 return(STATUS_SUCCESS);
872 }
873
874
875 /**********************************************************************
876 * NAME EXPORTED
877 * NtClose
878 *
879 * DESCRIPTION
880 * Closes a handle reference to an object.
881 *
882 * ARGUMENTS
883 * Handle
884 * Handle to close.
885 *
886 * RETURN VALUE
887 * Status.
888 *
889 * @implemented
890 */
891 NTSTATUS STDCALL
892 NtClose(IN HANDLE Handle)
893 {
894 PHANDLE_TABLE HandleTable;
895 NTSTATUS Status;
896
897 PAGED_CODE();
898
899 if(ObIsKernelHandle(Handle, ExGetPreviousMode()))
900 {
901 HandleTable = ObpKernelHandleTable;
902 Handle = ObKernelHandleToHandle(Handle);
903 }
904 else
905 {
906 HandleTable = PsGetCurrentProcess()->ObjectTable;
907 }
908
909 Status = ObpDeleteHandle(HandleTable,
910 Handle);
911 if (!NT_SUCCESS(Status))
912 {
913 if((ExGetPreviousMode() != KernelMode) &&
914 (PsGetCurrentProcess()->ExceptionPort))
915 {
916 KeRaiseUserException(Status);
917 }
918 return Status;
919 }
920
921 return(STATUS_SUCCESS);
922 }
923
924
925 /*
926 * @implemented
927 */
928 NTSTATUS STDCALL
929 ObInsertObject(IN PVOID Object,
930 IN PACCESS_STATE PassedAccessState OPTIONAL,
931 IN ACCESS_MASK DesiredAccess,
932 IN ULONG AdditionalReferences,
933 OUT PVOID* ReferencedObject OPTIONAL,
934 OUT PHANDLE Handle)
935 {
936 POBJECT_HEADER ObjectHeader;
937 ACCESS_MASK Access;
938
939 PAGED_CODE();
940
941 Access = DesiredAccess;
942 ObjectHeader = BODY_TO_HEADER(Object);
943
944 return(ObCreateHandle(PsGetCurrentProcess(),
945 Object,
946 Access,
947 ObjectHeader->Inherit,
948 Handle));
949 }
950
951
952 ULONG
953 ObpGetHandleCountByHandleTable(PHANDLE_TABLE HandleTable)
954 {
955 return HandleTable->HandleCount;
956 }
957
958 /*
959 * FUNCTION: Searches the handle table of a specified process whether it contains a
960 * valid handle to the Object we're looking for. If not, it'll create one.
961 *
962 * NOTES:
963 * The parameters of this function is basically a mixture of some of the parameters
964 * of ObReferenceObjectByHandle() and ObReferenceObjectByPointer(). A little thinking
965 * about what this function does (by it's name) makes clear what parameters it requires.
966 * For example the AccessMode parameter of ObReferenceObjectByHandle/Pointer() is not
967 * required at all as it only has influence on the object security. This function doesn't
968 * want to get access to an object, it just looks for a valid handle and if it can't find
969 * one, it'll just create one. It wouldn't make sense to check for security again as the
970 * caller already has a pointer to the object.
971 *
972 * A test on an XP machine shows that this prototype appears to be correct.
973 *
974 * ARGUMENTS:
975 * Process = This parameter simply describes in which handle table we're looking
976 * for a handle to the object.
977 * Object = The object pointer that we're looking for
978 * ObjectType = Just a sanity check as ObReferenceObjectByHandle() and
979 * ObReferenceObjectByPointer() provides.
980 * HandleInformation = This one has to be the opposite meaning of the usage in
981 * ObReferenceObjectByHandle(). If we actually found a valid
982 * handle in the table, we need to check against the information
983 * provided so we make sure this handle has all access rights
984 * (and attributes?!) we need. If they don't match, we can't
985 * use this handle and keep looking because the caller is likely
986 * to depend on these access rights.
987 * HandleReturn = The last parameter is the same as in ObCreateHandle(). If we could
988 * find a suitable handle in the handle table, return this handle, if
989 * not, we'll just create one using ObCreateHandle() with all access
990 * rights the caller needs.
991 *
992 * RETURNS: Status
993 *
994 * @unimplemented
995 */
996 NTSTATUS STDCALL
997 ObFindHandleForObject(IN PEPROCESS Process,
998 IN PVOID Object,
999 IN POBJECT_TYPE ObjectType,
1000 IN POBJECT_HANDLE_INFORMATION HandleInformation,
1001 OUT PHANDLE HandleReturn)
1002 {
1003 UNIMPLEMENTED;
1004 return STATUS_UNSUCCESSFUL;
1005 }
1006
1007 VOID
1008 ObpGetNextHandleByProcessCount(PSYSTEM_HANDLE_TABLE_ENTRY_INFO pshi,
1009 PEPROCESS Process,
1010 int Count)
1011 {
1012 ULONG P;
1013 // KIRQL oldIrql;
1014
1015 // pshi->HandleValue;
1016
1017 /*
1018 This will never work with ROS! M$, I guess uses 0 -> 65535.
1019 Ros uses 0 -> 4294967295!
1020 */
1021
1022 P = (ULONG) Process->UniqueProcessId;
1023 pshi->UniqueProcessId = (USHORT) P;
1024
1025 // KeAcquireSpinLock( &Process->HandleTable.ListLock, &oldIrql );
1026
1027 // pshi->GrantedAccess;
1028 // pshi->Object;
1029 // pshi->ObjectTypeIndex;
1030 // pshi->HandleAttributes;
1031
1032 // KeReleaseSpinLock( &Process->HandleTable.ListLock, oldIrql );
1033
1034 return;
1035 }
1036
1037
1038
1039 /* EOF */