[KERNEL32]
[reactos.git] / win32ss / user / consrv / handle.c
1 /*
2 * LICENSE: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/handle.c
5 * PURPOSE: Console IO Handle functions
6 * PROGRAMMERS:
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "consrv.h"
12 #include "conio.h"
13
14 //#define NDEBUG
15 #include <debug.h>
16
17
18 /* PRIVATE FUNCTIONS *********************************************************/
19
20 static INT
21 AdjustHandleCounts(PCONSOLE_IO_HANDLE Entry, INT Change)
22 {
23 Object_t *Object = Entry->Object;
24
25 DPRINT1("AdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->HandleCount = %d, Object->Type = %lu\n", Entry, Change, Object, Object->HandleCount, Object->Type);
26
27 if (Entry->Access & GENERIC_READ) Object->AccessRead += Change;
28 if (Entry->Access & GENERIC_WRITE) Object->AccessWrite += Change;
29 if (!(Entry->ShareMode & FILE_SHARE_READ)) Object->ExclusiveRead += Change;
30 if (!(Entry->ShareMode & FILE_SHARE_WRITE)) Object->ExclusiveWrite += Change;
31
32 Object->HandleCount += Change;
33
34 return Object->HandleCount;
35 }
36
37 static VOID
38 Win32CsrCreateHandleEntry(PCONSOLE_IO_HANDLE Entry)
39 {
40 Object_t *Object = Entry->Object;
41 EnterCriticalSection(&Object->Console->Lock);
42 AdjustHandleCounts(Entry, +1);
43 LeaveCriticalSection(&Object->Console->Lock);
44 }
45
46 static VOID
47 Win32CsrCloseHandleEntry(PCONSOLE_IO_HANDLE Entry)
48 {
49 Object_t *Object = Entry->Object;
50 if (Object != NULL)
51 {
52 PCONSOLE Console = Object->Console;
53 EnterCriticalSection(&Console->Lock);
54
55 /* If the last handle to a screen buffer is closed, delete it... */
56 if (AdjustHandleCounts(Entry, -1) == 0)
57 {
58 if (Object->Type == CONIO_SCREEN_BUFFER_MAGIC)
59 {
60 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
61 /* ...unless it's the only buffer left. Windows allows deletion
62 * even of the last buffer, but having to deal with a lack of
63 * any active buffer might be error-prone. */
64 if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink)
65 ConioDeleteScreenBuffer(Buffer);
66 }
67 else if (Object->Type == CONIO_CONSOLE_MAGIC)
68 {
69 /* TODO: FIXME: Destroy here the console ?? */
70 // ConioDeleteConsole(Console);
71 }
72 }
73
74 LeaveCriticalSection(&Console->Lock);
75 Entry->Object = NULL;
76 }
77 }
78
79
80 /* FUNCTIONS *****************************************************************/
81
82 NTSTATUS
83 FASTCALL
84 Win32CsrInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
85 IN PCONSOLE_PROCESS_DATA TargetProcessData)
86 {
87 NTSTATUS Status = STATUS_SUCCESS;
88 ULONG i;
89
90 RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
91
92 /* Inherit a handles table only if there is no already */
93 if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */)
94 {
95 Status = STATUS_UNSUCCESSFUL; /* STATUS_INVALID_PARAMETER */
96 goto Quit;
97 }
98
99 /* Allocate a new handle table for the child process */
100 TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap,
101 HEAP_ZERO_MEMORY,
102 SourceProcessData->HandleTableSize
103 * sizeof(CONSOLE_IO_HANDLE));
104 if (TargetProcessData->HandleTable == NULL)
105 {
106 Status = STATUS_NO_MEMORY;
107 goto Quit;
108 }
109
110 TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
111
112 /*
113 * Parse the parent process' handles table and, for each handle,
114 * do a copy of it and reference it, if the handle is inheritable.
115 */
116 for (i = 0; i < SourceProcessData->HandleTableSize; i++)
117 {
118 if (SourceProcessData->HandleTable[i].Object != NULL &&
119 SourceProcessData->HandleTable[i].Inheritable)
120 {
121 /*
122 * Copy the handle data and increment the reference count of the
123 * pointed object (via the call to Win32CsrCreateHandleEntry).
124 */
125 TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
126 Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]);
127 }
128 }
129
130 Quit:
131 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
132 return Status;
133 }
134
135 VOID
136 FASTCALL
137 Win32CsrFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData)
138 {
139 DPRINT1("Win32CsrFreeHandlesTable\n");
140
141 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
142
143 if (ProcessData->HandleTable != NULL)
144 {
145 ULONG i;
146
147 /* Close all console handles and free the handle table memory */
148 for (i = 0; i < ProcessData->HandleTableSize; i++)
149 {
150 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
151 }
152 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
153 ProcessData->HandleTable = NULL;
154 }
155
156 ProcessData->HandleTableSize = 0;
157
158 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
159 }
160
161 NTSTATUS
162 FASTCALL
163 Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
164 PHANDLE Handle,
165 Object_t *Object,
166 DWORD Access,
167 BOOL Inheritable,
168 DWORD ShareMode)
169 {
170 ULONG i;
171 PCONSOLE_IO_HANDLE Block;
172
173 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
174
175 for (i = 0; i < ProcessData->HandleTableSize; i++)
176 {
177 if (ProcessData->HandleTable[i].Object == NULL)
178 {
179 break;
180 }
181 }
182 if (i >= ProcessData->HandleTableSize)
183 {
184 Block = RtlAllocateHeap(ConSrvHeap,
185 HEAP_ZERO_MEMORY,
186 (ProcessData->HandleTableSize + 64) * sizeof(CONSOLE_IO_HANDLE));
187 if (Block == NULL)
188 {
189 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
190 return STATUS_UNSUCCESSFUL;
191 }
192 RtlCopyMemory(Block,
193 ProcessData->HandleTable,
194 ProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE));
195 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
196 ProcessData->HandleTable = Block;
197 ProcessData->HandleTableSize += 64;
198 }
199 ProcessData->HandleTable[i].Object = Object;
200 ProcessData->HandleTable[i].Access = Access;
201 ProcessData->HandleTable[i].Inheritable = Inheritable;
202 ProcessData->HandleTable[i].ShareMode = ShareMode;
203 Win32CsrCreateHandleEntry(&ProcessData->HandleTable[i]);
204 *Handle = ULongToHandle((i << 2) | 0x3);
205
206 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
207 return STATUS_SUCCESS;
208 }
209
210 NTSTATUS
211 FASTCALL
212 Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData,
213 HANDLE Handle)
214 {
215 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
216 Object_t *Object;
217
218 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
219
220 if (h >= ProcessData->HandleTableSize ||
221 (Object = ProcessData->HandleTable[h].Object) == NULL)
222 {
223 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
224 return STATUS_INVALID_HANDLE;
225 }
226
227 DPRINT1("Win32CsrReleaseObject - Process 0x%p, Release 0x%p\n", ProcessData->Process, &ProcessData->HandleTable[h]);
228 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[h]);
229
230 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
231
232 return STATUS_SUCCESS;
233 }
234
235 NTSTATUS
236 FASTCALL
237 Win32CsrLockObject(PCONSOLE_PROCESS_DATA ProcessData,
238 HANDLE Handle,
239 Object_t **Object,
240 DWORD Access,
241 LONG Type)
242 {
243 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
244
245 DPRINT("Win32CsrLockObject, Object: %x, %x, %x\n",
246 Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0);
247
248 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
249
250 if ( !IsConsoleHandle(Handle) ||
251 h >= ProcessData->HandleTableSize ||
252 (*Object = ProcessData->HandleTable[h].Object) == NULL ||
253 ~ProcessData->HandleTable[h].Access & Access ||
254 (Type != 0 && (*Object)->Type != Type) )
255 {
256 DPRINT1("CsrGetObject returning invalid handle (%x)\n", Handle);
257 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
258 return STATUS_INVALID_HANDLE;
259 }
260
261 _InterlockedIncrement(&(*Object)->Console->ReferenceCount);
262 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
263
264 EnterCriticalSection(&((*Object)->Console->Lock));
265 return STATUS_SUCCESS;
266 }
267
268 VOID FASTCALL
269 Win32CsrUnlockConsole(PCONSOLE Console)
270 {
271 LeaveCriticalSection(&Console->Lock);
272
273 /* Decrement reference count */
274 if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
275 ConioDeleteConsole(Console);
276 }
277
278 VOID
279 FASTCALL
280 Win32CsrUnlockObject(Object_t *Object)
281 {
282 Win32CsrUnlockConsole(Object->Console);
283 }
284
285 VOID
286 FASTCALL
287 Win32CsrReleaseConsole(PCONSOLE_PROCESS_DATA ProcessData)
288 {
289 PCONSOLE Console;
290
291 DPRINT1("Win32CsrReleaseConsole\n");
292
293 /* Close all console handles and free the handle table memory */
294 Win32CsrFreeHandlesTable(ProcessData);
295
296 /* Detach process from console */
297 Console = ProcessData->Console;
298 if (Console != NULL)
299 {
300 DPRINT1("Win32CsrReleaseConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount);
301 ProcessData->Console = NULL;
302 EnterCriticalSection(&Console->Lock);
303 RemoveEntryList(&ProcessData->ConsoleLink);
304 Win32CsrUnlockConsole(Console);
305 //CloseHandle(ProcessData->ConsoleEvent);
306 //ProcessData->ConsoleEvent = NULL;
307 }
308 }
309
310
311
312 NTSTATUS
313 NTAPI
314 ConsoleNewProcess(PCSR_PROCESS SourceProcess,
315 PCSR_PROCESS TargetProcess)
316 {
317 /**************************************************************************
318 * This function is called whenever a new process (GUI or CUI) is created.
319 *
320 * Copy the parent's handles table here if both the parent and the child
321 * processes are CUI. If we must actually create our proper console (and
322 * thus do not inherit from the console handles of the parent's), then we
323 * will clean this table in the next ConsoleConnect call. Why we are doing
324 * this? It's because here, we still don't know whether or not we must create
325 * a new console instead of inherit it from the parent, and, because in
326 * ConsoleConnect we don't have any reference to the parent process anymore.
327 **************************************************************************/
328
329 PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
330
331 DPRINT1("ConsoleNewProcess inside\n");
332 DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess, TargetProcess);
333
334 /* An empty target process is invalid */
335 if (!TargetProcess)
336 return STATUS_INVALID_PARAMETER;
337
338 DPRINT1("ConsoleNewProcess - OK\n");
339
340 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
341 DPRINT1("TargetProcessData = 0x%p\n", TargetProcessData);
342
343 /**** HACK !!!! ****/ RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData));
344
345 /* Initialize the new (target) process */
346 TargetProcessData->Process = TargetProcess;
347 TargetProcessData->ConsoleEvent = NULL;
348 TargetProcessData->Console = TargetProcessData->ParentConsole = NULL;
349 TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE);
350
351 // Testing
352 TargetProcessData->HandleTableSize = 0;
353 TargetProcessData->HandleTable = NULL;
354
355 /**** HACK !!!! ****/ RtlZeroMemory(&TargetProcessData->HandleTableLock, sizeof(RTL_CRITICAL_SECTION));
356 RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
357
358 /* Do nothing if the source process is NULL */
359 if (!SourceProcess)
360 return STATUS_SUCCESS;
361
362 SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
363 DPRINT1("SourceProcessData = 0x%p\n", SourceProcessData);
364
365 /*
366 * If both of the processes (parent and new child) are console applications,
367 * then try to inherit handles from the parent process.
368 */
369 if ( SourceProcessData->Console != NULL && /* SourceProcessData->ConsoleApp */
370 TargetProcessData->ConsoleApp )
371 {
372 NTSTATUS Status;
373
374 Status = Win32CsrInheritHandlesTable(SourceProcessData, TargetProcessData);
375 if (!NT_SUCCESS(Status))
376 {
377 return Status;
378 }
379
380 // FIXME: Do it before, or after the handles table inheritance ??
381 /* Temporary "inherit" the console from the parent */
382 TargetProcessData->ParentConsole = SourceProcessData->Console;
383 }
384 else
385 {
386 DPRINT1("ConsoleNewProcess - We don't launch a Console process : SourceProcessData->Console = 0x%p ; TargetProcess->Flags = %lu\n", SourceProcessData->Console, TargetProcess->Flags);
387 }
388
389 return STATUS_SUCCESS;
390 }
391
392 NTSTATUS
393 NTAPI
394 ConsoleConnect(IN PCSR_PROCESS CsrProcess,
395 IN OUT PVOID ConnectionInfo,
396 IN OUT PULONG ConnectionInfoLength)
397 {
398 /**************************************************************************
399 * This function is called whenever a CUI new process is created.
400 **************************************************************************/
401
402 NTSTATUS Status = STATUS_SUCCESS;
403 PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo;
404 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
405 BOOLEAN NewConsole = FALSE;
406
407 DPRINT1("ConsoleConnect\n");
408
409 if ( ConnectionInfo == NULL ||
410 ConnectionInfoLength == NULL ||
411 *ConnectionInfoLength != sizeof(CONSOLE_CONNECTION_INFO) )
412 {
413 DPRINT1("CONSRV: Connection failed\n");
414 return STATUS_UNSUCCESSFUL;
415 }
416
417 /* If we don't need a console, then get out of here */
418 if (!ConnectInfo->ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps.
419 {
420 DPRINT("ConsoleConnect - No console needed\n");
421 return STATUS_SUCCESS;
422 }
423
424 /* If we don't have a console, then create a new one... */
425 if (!ConnectInfo->Console ||
426 ConnectInfo->Console != ProcessData->ParentConsole)
427 {
428 DPRINT1("ConsoleConnect - Allocate a new console\n");
429
430 /*
431 * We are about to create a new console. However when ConsoleNewProcess
432 * was called, we didn't know that we wanted to create a new console and
433 * therefore, we by default inherited the handles table from our parent
434 * process. It's only now that we notice that in fact we do not need
435 * them, because we've created a new console and thus we must use it.
436 *
437 * Therefore, free the console we can have and our handles table,
438 * and recreate a new one later on.
439 */
440 Win32CsrReleaseConsole(ProcessData);
441
442 /* Initialize a new Console owned by the Console Leader Process */
443 NewConsole = TRUE;
444 Status = CsrInitConsole(&ProcessData->Console, ConnectInfo->ShowCmd, CsrProcess);
445 if (!NT_SUCCESS(Status))
446 {
447 DPRINT1("Console initialization failed\n");
448 return Status;
449 }
450 }
451 else /* We inherit it from the parent */
452 {
453 DPRINT1("ConsoleConnect - Reuse current (parent's) console\n");
454
455 /* Reuse our current console */
456 NewConsole = FALSE;
457 ProcessData->Console = ConnectInfo->Console;
458 }
459
460 /* Add a reference count because the process is tied to the console */
461 _InterlockedIncrement(&ProcessData->Console->ReferenceCount);
462
463 /* Insert the process into the processes list of the console */
464 InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
465
466 /* Return it to the caller */
467 ConnectInfo->Console = ProcessData->Console;
468
469 if (NewConsole)
470 {
471 /*
472 * Create a new handle table - Insert the IO handles
473 */
474
475 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
476
477 /* Insert the Input handle */
478 Status = Win32CsrInsertObject(ProcessData,
479 &ConnectInfo->InputHandle,
480 &ProcessData->Console->Header,
481 GENERIC_READ | GENERIC_WRITE,
482 TRUE,
483 FILE_SHARE_READ | FILE_SHARE_WRITE);
484 if (!NT_SUCCESS(Status))
485 {
486 DPRINT1("Failed to insert the input handle\n");
487 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
488 Win32CsrReleaseConsole(ProcessData);
489 // ConioDeleteConsole(ProcessData->Console);
490 // ProcessData->Console = NULL;
491 return Status;
492 }
493
494 /* Insert the Output handle */
495 Status = Win32CsrInsertObject(ProcessData,
496 &ConnectInfo->OutputHandle,
497 &ProcessData->Console->ActiveBuffer->Header,
498 GENERIC_READ | GENERIC_WRITE,
499 TRUE,
500 FILE_SHARE_READ | FILE_SHARE_WRITE);
501 if (!NT_SUCCESS(Status))
502 {
503 DPRINT1("Failed to insert the output handle\n");
504 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
505 Win32CsrReleaseConsole(ProcessData);
506 // Win32CsrReleaseObject(ProcessData,
507 // ConnectInfo->InputHandle);
508 // ConioDeleteConsole(ProcessData->Console);
509 // ProcessData->Console = NULL;
510 return Status;
511 }
512
513 /* Insert the Error handle */
514 Status = Win32CsrInsertObject(ProcessData,
515 &ConnectInfo->ErrorHandle,
516 &ProcessData->Console->ActiveBuffer->Header,
517 GENERIC_READ | GENERIC_WRITE,
518 TRUE,
519 FILE_SHARE_READ | FILE_SHARE_WRITE);
520 if (!NT_SUCCESS(Status))
521 {
522 DPRINT1("Failed to insert the error handle\n");
523 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
524 Win32CsrReleaseConsole(ProcessData);
525 // Win32CsrReleaseObject(ProcessData,
526 // ConnectInfo->OutputHandle);
527 // Win32CsrReleaseObject(ProcessData,
528 // ConnectInfo->InputHandle);
529 // ConioDeleteConsole(ProcessData->Console);
530 // ProcessData->Console = NULL;
531 return Status;
532 }
533
534 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
535 }
536
537 /* Duplicate the Event */
538 Status = NtDuplicateObject(NtCurrentProcess(),
539 ProcessData->Console->ActiveEvent,
540 ProcessData->Process->ProcessHandle,
541 &ProcessData->ConsoleEvent,
542 EVENT_ALL_ACCESS, 0, 0);
543 if (!NT_SUCCESS(Status))
544 {
545 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
546 Win32CsrReleaseConsole(ProcessData);
547 // if (NewConsole)
548 // {
549 // Win32CsrReleaseObject(ProcessData,
550 // ConnectInfo->ErrorHandle);
551 // Win32CsrReleaseObject(ProcessData,
552 // ConnectInfo->OutputHandle);
553 // Win32CsrReleaseObject(ProcessData,
554 // ConnectInfo->InputHandle);
555 // }
556 // ConioDeleteConsole(ProcessData->Console); // FIXME: Just release the console ?
557 // ProcessData->Console = NULL;
558 return Status;
559 }
560 /* Input Wait Handle */
561 ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent;
562
563 /* Set the Ctrl Dispatcher */
564 ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher;
565 DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
566
567 return STATUS_SUCCESS;
568 }
569
570 VOID
571 WINAPI
572 ConsoleDisconnect(PCSR_PROCESS Process)
573 {
574 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
575
576 /**************************************************************************
577 * This function is called whenever a new process (GUI or CUI) is destroyed.
578 **************************************************************************/
579
580 DPRINT1("ConsoleDisconnect called\n");
581 if ( ProcessData->Console != NULL ||
582 ProcessData->HandleTable != NULL )
583 {
584 DPRINT1("ConsoleDisconnect - calling Win32CsrReleaseConsole\n");
585 Win32CsrReleaseConsole(ProcessData);
586 }
587
588 RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
589 }
590
591
592
593 CSR_API(SrvCloseHandle)
594 {
595 PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
596
597 return Win32CsrReleaseObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
598 CloseHandleRequest->ConsoleHandle);
599 }
600
601 CSR_API(SrvVerifyConsoleIoHandle)
602 {
603 NTSTATUS Status = STATUS_SUCCESS;
604 PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
605 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
606 HANDLE ConsoleHandle = VerifyHandleRequest->ConsoleHandle;
607 ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2;
608
609 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
610
611 if (!IsConsoleHandle(ConsoleHandle) ||
612 Index >= ProcessData->HandleTableSize ||
613 ProcessData->HandleTable[Index].Object == NULL)
614 {
615 DPRINT("CsrVerifyObject failed\n");
616 Status = STATUS_INVALID_HANDLE;
617 }
618
619 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
620
621 return Status;
622 }
623
624 CSR_API(SrvDuplicateHandle)
625 {
626 PCONSOLE_IO_HANDLE Entry;
627 DWORD DesiredAccess;
628 PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
629 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
630 HANDLE ConsoleHandle = DuplicateHandleRequest->ConsoleHandle;
631 ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2;
632
633 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
634
635 if ( /** !IsConsoleHandle(ConsoleHandle) || **/
636 Index >= ProcessData->HandleTableSize ||
637 (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
638 {
639 DPRINT1("Couldn't duplicate invalid handle %p\n", ConsoleHandle);
640 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
641 return STATUS_INVALID_HANDLE;
642 }
643
644 if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
645 {
646 DesiredAccess = Entry->Access;
647 }
648 else
649 {
650 DesiredAccess = DuplicateHandleRequest->Access;
651 /* Make sure the source handle has all the desired flags */
652 if (~Entry->Access & DesiredAccess)
653 {
654 DPRINT1("Handle %p only has access %X; requested %X\n",
655 ConsoleHandle, Entry->Access, DesiredAccess);
656 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
657 return STATUS_INVALID_PARAMETER;
658 }
659 }
660
661 ApiMessage->Status = Win32CsrInsertObject(ProcessData,
662 &DuplicateHandleRequest->ConsoleHandle, // Use the new handle value!
663 Entry->Object,
664 DesiredAccess,
665 DuplicateHandleRequest->Inheritable,
666 Entry->ShareMode);
667 if (NT_SUCCESS(ApiMessage->Status) &&
668 DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE)
669 {
670 Win32CsrCloseHandleEntry(Entry);
671 }
672
673 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
674 return ApiMessage->Status;
675 }
676
677 /**
678 CSR_API(CsrGetInputWaitHandle)
679 {
680 PCSRSS_GET_INPUT_WAIT_HANDLE GetConsoleInputWaitHandle = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputWaitHandle;
681
682 GetConsoleInputWaitHandle->InputWaitHandle =
683 ConsoleGetPerProcessData(CsrGetClientThread()->Process)->ConsoleEvent;
684
685 return STATUS_SUCCESS;
686 }
687 **/
688
689 /* EOF */