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