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