Merge 15329:15546 from 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 /* 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 DPRINT("Header: %x\n", ObjectHeader);
64 LONG NewHandleCount = InterlockedDecrement(&ObjectHeader->HandleCount);
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 BOOLEAN InheritHandle,
366 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->TypeName, ObjectHeader->Type ? &ObjectHeader->Type->TypeName : 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 ObpAddEntryDirectory(FoundObject, Header, NULL);
1012 ObjectAttached = TRUE;
1013
1014 /* The name was changed so let's update it */
1015 /* FIXME: TEMPORARY HACK This will go in ObFindObject in the next commit */
1016 PVOID NewName;
1017 PWSTR BufferPos = RemainingPath.Buffer;
1018
1019 NewName = ExAllocatePool(NonPagedPool, RemainingPath.MaximumLength);
1020 ObjectNameInfo = HEADER_TO_OBJECT_NAME(Header);
1021
1022 if (BufferPos[0] == L'\\')
1023 {
1024 BufferPos++;
1025 }
1026
1027 RtlMoveMemory(NewName, BufferPos, RemainingPath.MaximumLength);
1028 if (ObjectNameInfo->Name.Buffer) ExFreePool(ObjectNameInfo->Name.Buffer);
1029 ObjectNameInfo->Name.Buffer = NewName;
1030 ObjectNameInfo->Name.Length = RemainingPath.Length;
1031 ObjectNameInfo->Name.MaximumLength = RemainingPath.MaximumLength;
1032 DPRINT("Name: %S\n", ObjectNameInfo->Name.Buffer);
1033 }
1034
1035 if ((Header->Type == IoFileObjectType) ||
1036 (Header->Type == ExDesktopObjectType) ||
1037 (Header->Type->TypeInfo.OpenProcedure != NULL))
1038 {
1039 DPRINT("About to call Open Routine\n");
1040 if (Header->Type == IoFileObjectType)
1041 {
1042 /* TEMPORARY HACK. DO NOT TOUCH -- Alex */
1043 DPRINT("Calling IopCreateFile: %x\n", FoundObject);
1044 Status = IopCreateFile(&Header->Body,
1045 FoundObject,
1046 RemainingPath.Buffer,
1047 ObjectCreateInfo);
1048 DPRINT("Called IopCreateFile: %x\n", Status);
1049
1050 }
1051 else if (Header->Type == ExDesktopObjectType)
1052 {
1053 /* TEMPORARY HACK. DO NOT TOUCH -- Alex */
1054 DPRINT("Calling ExpDesktopCreate\n");
1055 Status = ExpDesktopCreate(&Header->Body,
1056 FoundObject,
1057 RemainingPath.Buffer,
1058 ObjectCreateInfo);
1059 }
1060 else if (Header->Type->TypeInfo.OpenProcedure != NULL)
1061 {
1062 DPRINT("Calling %x\n", Header->Type->TypeInfo.OpenProcedure);
1063 Status = Header->Type->TypeInfo.OpenProcedure(ObCreateHandle,
1064 &Header->Body,
1065 NULL,
1066 0,
1067 0);
1068 }
1069
1070 if (!NT_SUCCESS(Status))
1071 {
1072 DPRINT("Create Failed\n");
1073 if (ObjectAttached == TRUE)
1074 {
1075 ObpRemoveEntryDirectory(Header);
1076 }
1077 if (FoundObject)
1078 {
1079 ObDereferenceObject(FoundObject);
1080 }
1081 RtlFreeUnicodeString(&RemainingPath);
1082 return Status;
1083 }
1084 }
1085
1086 RtlFreeUnicodeString(&RemainingPath);
1087
1088 DPRINT("Security Assignment in progress\n");
1089 SeCaptureSubjectContext(&SubjectContext);
1090
1091 /* Build the new security descriptor */
1092 Status = SeAssignSecurity((FoundHeader != NULL) ? FoundHeader->SecurityDescriptor : NULL,
1093 (ObjectCreateInfo != NULL) ? ObjectCreateInfo->SecurityDescriptor : NULL,
1094 &NewSecurityDescriptor,
1095 (Header->Type == ObDirectoryType),
1096 &SubjectContext,
1097 &Header->Type->TypeInfo.GenericMapping,
1098 PagedPool);
1099
1100 if (NT_SUCCESS(Status))
1101 {
1102 DPRINT("NewSecurityDescriptor %p\n", NewSecurityDescriptor);
1103
1104 if (Header->Type->TypeInfo.SecurityProcedure != NULL)
1105 {
1106 /* Call the security method */
1107 Status = Header->Type->TypeInfo.SecurityProcedure(&Header->Body,
1108 AssignSecurityDescriptor,
1109 0,
1110 NewSecurityDescriptor,
1111 NULL);
1112 }
1113 else
1114 {
1115 /* Assign the security descriptor to the object header */
1116 Status = ObpAddSecurityDescriptor(NewSecurityDescriptor,
1117 &Header->SecurityDescriptor);
1118 DPRINT("Object security descriptor %p\n", Header->SecurityDescriptor);
1119 }
1120
1121 /* Release the new security descriptor */
1122 SeDeassignSecurity(&NewSecurityDescriptor);
1123 }
1124
1125 DPRINT("Security Complete\n");
1126 SeReleaseSubjectContext(&SubjectContext);
1127
1128 /* Create the Handle */
1129 /* HACKHACK: Because of ROS's incorrect startup, this can be called
1130 * without a valid Process until I finalize the startup patch,
1131 * so don't create a handle if this is the case. We also don't create
1132 * a handle if Handle is NULL when the Registry Code calls it, because
1133 * the registry code totally bastardizes the Ob and needs to be fixed
1134 */
1135 DPRINT("Creating handle\n");
1136 if (Handle != NULL)
1137 {
1138 Status = ObpCreateHandle(PsGetCurrentProcess(),
1139 &Header->Body,
1140 DesiredAccess,
1141 ObjectCreateInfo->Attributes & OBJ_INHERIT,
1142 Handle);
1143 DPRINT("handle Created: %d. refcount. handlecount %d %d\n",
1144 *Handle, Header->RefCount, Header->HandleCount);
1145 }
1146
1147 /* We can delete the Create Info now */
1148 Header->ObjectCreateInfo = NULL;
1149 ObpReleaseCapturedAttributes(ObjectCreateInfo);
1150 ExFreePool(ObjectCreateInfo);
1151
1152 DPRINT("Status %x\n", Status);
1153 return Status;
1154 }
1155
1156
1157 ULONG
1158 ObpGetHandleCountByHandleTable(PHANDLE_TABLE HandleTable)
1159 {
1160 return HandleTable->HandleCount;
1161 }
1162
1163 /*
1164 * FUNCTION: Searches the handle table of a specified process whether it contains a
1165 * valid handle to the Object we're looking for. If not, it'll create one.
1166 *
1167 * NOTES:
1168 * The parameters of this function is basically a mixture of some of the parameters
1169 * of ObReferenceObjectByHandle() and ObReferenceObjectByPointer(). A little thinking
1170 * about what this function does (by it's name) makes clear what parameters it requires.
1171 * For example the AccessMode parameter of ObReferenceObjectByHandle/Pointer() is not
1172 * required at all as it only has influence on the object security. This function doesn't
1173 * want to get access to an object, it just looks for a valid handle and if it can't find
1174 * one, it'll just create one. It wouldn't make sense to check for security again as the
1175 * caller already has a pointer to the object.
1176 *
1177 * A test on an XP machine shows that this prototype appears to be correct.
1178 *
1179 * ARGUMENTS:
1180 * Process = This parameter simply describes in which handle table we're looking
1181 * for a handle to the object.
1182 * Object = The object pointer that we're looking for
1183 * ObjectType = Just a sanity check as ObReferenceObjectByHandle() and
1184 * ObReferenceObjectByPointer() provides.
1185 * HandleInformation = This one has to be the opposite meaning of the usage in
1186 * ObReferenceObjectByHandle(). If we actually found a valid
1187 * handle in the table, we need to check against the information
1188 * provided so we make sure this handle has all access rights
1189 * (and attributes?!) we need. If they don't match, we can't
1190 * use this handle and keep looking because the caller is likely
1191 * to depend on these access rights.
1192 * HandleReturn = The last parameter is the same as in ObCreateHandle(). If we could
1193 * find a suitable handle in the handle table, return this handle, if
1194 * not, we'll just create one using ObCreateHandle() with all access
1195 * rights the caller needs.
1196 *
1197 * RETURNS: Status
1198 *
1199 * @unimplemented
1200 */
1201 NTSTATUS STDCALL
1202 ObFindHandleForObject(IN PEPROCESS Process,
1203 IN PVOID Object,
1204 IN POBJECT_TYPE ObjectType,
1205 IN POBJECT_HANDLE_INFORMATION HandleInformation,
1206 OUT PHANDLE HandleReturn)
1207 {
1208 UNIMPLEMENTED;
1209 return STATUS_UNSUCCESSFUL;
1210 }
1211
1212 VOID
1213 ObpGetNextHandleByProcessCount(PSYSTEM_HANDLE_TABLE_ENTRY_INFO pshi,
1214 PEPROCESS Process,
1215 int Count)
1216 {
1217 ULONG P;
1218 // KIRQL oldIrql;
1219
1220 // pshi->HandleValue;
1221
1222 /*
1223 This will never work with ROS! M$, I guess uses 0 -> 65535.
1224 Ros uses 0 -> 4294967295!
1225 */
1226
1227 P = (ULONG) Process->UniqueProcessId;
1228 pshi->UniqueProcessId = (USHORT) P;
1229
1230 // KeAcquireSpinLock( &Process->HandleTable.ListLock, &oldIrql );
1231
1232 // pshi->GrantedAccess;
1233 // pshi->Object;
1234 // pshi->TypeIndex;
1235 // pshi->HandleAttributes;
1236
1237 // KeReleaseSpinLock( &Process->HandleTable.ListLock, oldIrql );
1238
1239 return;
1240 }
1241
1242
1243
1244 /* EOF */