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