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