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