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