[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 I/O Handles 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 ConSrvCreateHandleEntry(PCONSOLE_IO_HANDLE Entry)
39 {
40 /// LOCK /// Object_t *Object = Entry->Object;
41 /// LOCK /// EnterCriticalSection(&Object->Console->Lock);
42 AdjustHandleCounts(Entry, +1);
43 /// LOCK /// LeaveCriticalSection(&Object->Console->Lock);
44 }
45
46 static VOID
47 ConSrvCloseHandleEntry(PCONSOLE_IO_HANDLE Entry)
48 {
49 Object_t *Object = Entry->Object;
50 if (Object != NULL)
51 {
52 /// LOCK /// PCONSOLE Console = Object->Console;
53 /// LOCK /// EnterCriticalSection(&Console->Lock);
54
55 /*
56 * If this is a input handle, notify and dereference
57 * all the waits related to this handle.
58 */
59 if (Object->Type == CONIO_INPUT_BUFFER_MAGIC)
60 {
61 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
62
63 /*
64 * Wake up all the writing waiters related to this handle for this
65 * input buffer, if any, then dereference them and purge them all
66 * from the list.
67 * To select them amongst all the waiters for this input buffer,
68 * pass the handle pointer to the waiters, then they will check
69 * whether or not they are related to this handle and if so, they
70 * return.
71 */
72 CsrNotifyWait(&InputBuffer->ReadWaitQueue,
73 WaitAll,
74 NULL,
75 (PVOID)Entry);
76
77 if (!IsListEmpty(&InputBuffer->ReadWaitQueue))
78 {
79 CsrDereferenceWait(&InputBuffer->ReadWaitQueue);
80 }
81 }
82
83 /* If the last handle to a screen buffer is closed, delete it... */
84 if (AdjustHandleCounts(Entry, -1) == 0)
85 {
86 if (Object->Type == CONIO_SCREEN_BUFFER_MAGIC)
87 {
88 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
89 /* ...unless it's the only buffer left. Windows allows deletion
90 * even of the last buffer, but having to deal with a lack of
91 * any active buffer might be error-prone. */
92 if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink)
93 ConioDeleteScreenBuffer(Buffer);
94 }
95 else if (Object->Type == CONIO_INPUT_BUFFER_MAGIC)
96 {
97 DPRINT1("Closing the input buffer\n");
98 }
99 }
100
101 /// LOCK /// LeaveCriticalSection(&Console->Lock);
102 Entry->Object = NULL;
103 }
104 }
105
106
107 /* FUNCTIONS *****************************************************************/
108
109 /* static */ NTSTATUS
110 FASTCALL
111 ConSrvInitHandlesTable(IN OUT PCONSOLE_PROCESS_DATA ProcessData,
112 OUT PHANDLE pInputHandle,
113 OUT PHANDLE pOutputHandle,
114 OUT PHANDLE pErrorHandle)
115 {
116 NTSTATUS Status;
117 HANDLE InputHandle = INVALID_HANDLE_VALUE,
118 OutputHandle = INVALID_HANDLE_VALUE,
119 ErrorHandle = INVALID_HANDLE_VALUE;
120
121 /*
122 * Initialize the handles table. Use temporary variables to store
123 * the handles values in such a way that, if we fail, we don't
124 * return to the caller invalid handle values.
125 *
126 * Insert the IO handles.
127 */
128
129 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
130
131 /* Insert the Input handle */
132 Status = ConSrvInsertObject(ProcessData,
133 &InputHandle,
134 &ProcessData->Console->InputBuffer.Header,
135 GENERIC_READ | GENERIC_WRITE,
136 TRUE,
137 FILE_SHARE_READ | FILE_SHARE_WRITE);
138 if (!NT_SUCCESS(Status))
139 {
140 DPRINT1("Failed to insert the input handle\n");
141 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
142 ConSrvFreeHandlesTable(ProcessData);
143 return Status;
144 }
145
146 /* Insert the Output handle */
147 Status = ConSrvInsertObject(ProcessData,
148 &OutputHandle,
149 &ProcessData->Console->ActiveBuffer->Header,
150 GENERIC_READ | GENERIC_WRITE,
151 TRUE,
152 FILE_SHARE_READ | FILE_SHARE_WRITE);
153 if (!NT_SUCCESS(Status))
154 {
155 DPRINT1("Failed to insert the output handle\n");
156 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
157 ConSrvFreeHandlesTable(ProcessData);
158 return Status;
159 }
160
161 /* Insert the Error handle */
162 Status = ConSrvInsertObject(ProcessData,
163 &ErrorHandle,
164 &ProcessData->Console->ActiveBuffer->Header,
165 GENERIC_READ | GENERIC_WRITE,
166 TRUE,
167 FILE_SHARE_READ | FILE_SHARE_WRITE);
168 if (!NT_SUCCESS(Status))
169 {
170 DPRINT1("Failed to insert the error handle\n");
171 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
172 ConSrvFreeHandlesTable(ProcessData);
173 return Status;
174 }
175
176 /* Return the newly created handles */
177 *pInputHandle = InputHandle;
178 *pOutputHandle = OutputHandle;
179 *pErrorHandle = ErrorHandle;
180
181 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
182 return STATUS_SUCCESS;
183 }
184
185 NTSTATUS
186 FASTCALL
187 ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
188 IN PCONSOLE_PROCESS_DATA TargetProcessData)
189 {
190 NTSTATUS Status = STATUS_SUCCESS;
191 ULONG i;
192
193 RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
194
195 /* Inherit a handles table only if there is no already */
196 if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */)
197 {
198 Status = STATUS_UNSUCCESSFUL; /* STATUS_INVALID_PARAMETER */
199 goto Quit;
200 }
201
202 /* Allocate a new handle table for the child process */
203 TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap,
204 HEAP_ZERO_MEMORY,
205 SourceProcessData->HandleTableSize
206 * sizeof(CONSOLE_IO_HANDLE));
207 if (TargetProcessData->HandleTable == NULL)
208 {
209 Status = STATUS_NO_MEMORY;
210 goto Quit;
211 }
212
213 TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
214
215 /*
216 * Parse the parent process' handles table and, for each handle,
217 * do a copy of it and reference it, if the handle is inheritable.
218 */
219 for (i = 0; i < SourceProcessData->HandleTableSize; i++)
220 {
221 if (SourceProcessData->HandleTable[i].Object != NULL &&
222 SourceProcessData->HandleTable[i].Inheritable)
223 {
224 /*
225 * Copy the handle data and increment the reference count of the
226 * pointed object (via the call to ConSrvCreateHandleEntry).
227 */
228 TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
229 ConSrvCreateHandleEntry(&TargetProcessData->HandleTable[i]);
230 }
231 }
232
233 Quit:
234 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
235 return Status;
236 }
237
238 VOID
239 FASTCALL
240 ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData)
241 {
242 DPRINT1("ConSrvFreeHandlesTable\n");
243
244 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
245
246 if (ProcessData->HandleTable != NULL)
247 {
248 ULONG i;
249
250 /* Close all console handles and free the handle table memory */
251 for (i = 0; i < ProcessData->HandleTableSize; i++)
252 {
253 ConSrvCloseHandleEntry(&ProcessData->HandleTable[i]);
254 }
255 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
256 ProcessData->HandleTable = NULL;
257 }
258
259 ProcessData->HandleTableSize = 0;
260
261 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
262 }
263
264 NTSTATUS
265 FASTCALL
266 ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
267 PHANDLE Handle,
268 Object_t *Object,
269 DWORD Access,
270 BOOL Inheritable,
271 DWORD ShareMode)
272 {
273 #define IO_HANDLES_INCREMENT 2*3
274
275 ULONG i;
276 PCONSOLE_IO_HANDLE Block;
277
278 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
279
280 for (i = 0; i < ProcessData->HandleTableSize; i++)
281 {
282 if (ProcessData->HandleTable[i].Object == NULL)
283 {
284 break;
285 }
286 }
287 if (i >= ProcessData->HandleTableSize)
288 {
289 Block = RtlAllocateHeap(ConSrvHeap,
290 HEAP_ZERO_MEMORY,
291 (ProcessData->HandleTableSize +
292 IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE));
293 if (Block == NULL)
294 {
295 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
296 return STATUS_UNSUCCESSFUL;
297 }
298 RtlCopyMemory(Block,
299 ProcessData->HandleTable,
300 ProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE));
301 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
302 ProcessData->HandleTable = Block;
303 ProcessData->HandleTableSize += IO_HANDLES_INCREMENT;
304 }
305
306 ProcessData->HandleTable[i].Object = Object;
307 ProcessData->HandleTable[i].Access = Access;
308 ProcessData->HandleTable[i].Inheritable = Inheritable;
309 ProcessData->HandleTable[i].ShareMode = ShareMode;
310 ConSrvCreateHandleEntry(&ProcessData->HandleTable[i]);
311 *Handle = ULongToHandle((i << 2) | 0x3);
312
313 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
314
315 return STATUS_SUCCESS;
316 }
317
318 NTSTATUS
319 FASTCALL
320 ConSrvRemoveObject(PCONSOLE_PROCESS_DATA ProcessData,
321 HANDLE Handle)
322 {
323 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
324 Object_t *Object;
325
326 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
327
328 if (h >= ProcessData->HandleTableSize ||
329 (Object = ProcessData->HandleTable[h].Object) == NULL)
330 {
331 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
332 return STATUS_INVALID_HANDLE;
333 }
334
335 DPRINT1("ConSrvRemoveObject - Process 0x%p, Release 0x%p\n", ProcessData->Process, &ProcessData->HandleTable[h]);
336 ConSrvCloseHandleEntry(&ProcessData->HandleTable[h]);
337
338 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
339
340 return STATUS_SUCCESS;
341 }
342
343 NTSTATUS
344 FASTCALL
345 ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData,
346 HANDLE Handle,
347 Object_t** Object,
348 PCONSOLE_IO_HANDLE* Entry OPTIONAL,
349 DWORD Access,
350 BOOL LockConsole,
351 ULONG Type)
352 {
353 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
354 PCONSOLE_IO_HANDLE HandleEntry = NULL;
355 Object_t* ObjectEntry = NULL;
356
357 ASSERT(Object);
358 if (Entry) *Entry = NULL;
359
360 // DPRINT("ConSrvGetObject, Object: %x, %x, %x\n",
361 // Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0);
362
363 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
364
365 if ( IsConsoleHandle(Handle) &&
366 h < ProcessData->HandleTableSize )
367 {
368 HandleEntry = &ProcessData->HandleTable[h];
369 ObjectEntry = HandleEntry->Object;
370 }
371
372 if ( HandleEntry == NULL ||
373 ObjectEntry == NULL ||
374 (HandleEntry->Access & Access) == 0 ||
375 (Type != 0 && ObjectEntry->Type != Type) )
376 {
377 DPRINT1("CsrGetObject returning invalid handle (%x) of type %lu with access %lu\n", Handle, Type, Access);
378 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
379 return STATUS_INVALID_HANDLE;
380 }
381
382 _InterlockedIncrement(&ObjectEntry->Console->ReferenceCount);
383 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
384
385 if (LockConsole) EnterCriticalSection(&ObjectEntry->Console->Lock);
386
387 /* Return the objects to the caller */
388 *Object = ObjectEntry;
389 if (Entry) *Entry = HandleEntry;
390
391 return STATUS_SUCCESS;
392 }
393
394 VOID
395 FASTCALL
396 ConSrvReleaseObject(Object_t *Object,
397 BOOL IsConsoleLocked)
398 {
399 ConSrvReleaseConsole(Object->Console, IsConsoleLocked);
400 }
401
402 NTSTATUS
403 FASTCALL
404 ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData,
405 PHANDLE pInputHandle,
406 PHANDLE pOutputHandle,
407 PHANDLE pErrorHandle,
408 int ShowCmd,
409 PCSR_PROCESS CsrProcess)
410 {
411 NTSTATUS Status = STATUS_SUCCESS;
412
413 /* Initialize a new Console owned by the Console Leader Process */
414 Status = ConSrvInitConsole(&ProcessData->Console, ShowCmd, CsrProcess);
415 if (!NT_SUCCESS(Status))
416 {
417 DPRINT1("Console initialization failed\n");
418 return Status;
419 }
420
421 /* Initialize the handles table */
422 Status = ConSrvInitHandlesTable(ProcessData,
423 pInputHandle,
424 pOutputHandle,
425 pErrorHandle);
426 if (!NT_SUCCESS(Status))
427 {
428 DPRINT1("Failed to initialize the handles table\n");
429 ConSrvDeleteConsole(ProcessData->Console);
430 ProcessData->Console = NULL;
431 return Status;
432 }
433
434 /* Duplicate the Input Event */
435 Status = NtDuplicateObject(NtCurrentProcess(),
436 ProcessData->Console->InputBuffer.ActiveEvent,
437 ProcessData->Process->ProcessHandle,
438 &ProcessData->ConsoleEvent,
439 EVENT_ALL_ACCESS, 0, 0);
440 if (!NT_SUCCESS(Status))
441 {
442 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
443 ConSrvFreeHandlesTable(ProcessData);
444 ConSrvDeleteConsole(ProcessData->Console);
445 ProcessData->Console = NULL;
446 return Status;
447 }
448
449 /* Insert the process into the processes list of the console */
450 InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
451
452 /* Add a reference count because the process is tied to the console */
453 _InterlockedIncrement(&ProcessData->Console->ReferenceCount);
454
455 return STATUS_SUCCESS;
456 }
457
458 NTSTATUS
459 FASTCALL
460 ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
461 PCONSOLE Console,
462 BOOL CreateNewHandlesTable,
463 PHANDLE pInputHandle,
464 PHANDLE pOutputHandle,
465 PHANDLE pErrorHandle)
466 {
467 NTSTATUS Status = STATUS_SUCCESS;
468
469 /* Inherit the console */
470 ProcessData->Console = Console;
471
472 if (CreateNewHandlesTable)
473 {
474 /* Initialize the handles table */
475 Status = ConSrvInitHandlesTable(ProcessData,
476 pInputHandle,
477 pOutputHandle,
478 pErrorHandle);
479 if (!NT_SUCCESS(Status))
480 {
481 DPRINT1("Failed to initialize the handles table\n");
482 ProcessData->Console = NULL;
483 return Status;
484 }
485 }
486
487 /* Duplicate the Input Event */
488 Status = NtDuplicateObject(NtCurrentProcess(),
489 ProcessData->Console->InputBuffer.ActiveEvent,
490 ProcessData->Process->ProcessHandle,
491 &ProcessData->ConsoleEvent,
492 EVENT_ALL_ACCESS, 0, 0);
493 if (!NT_SUCCESS(Status))
494 {
495 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
496 ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table.
497 ProcessData->Console = NULL;
498 return Status;
499 }
500
501 /* Insert the process into the processes list of the console */
502 InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
503
504 /* Add a reference count because the process is tied to the console */
505 _InterlockedIncrement(&ProcessData->Console->ReferenceCount);
506
507 return STATUS_SUCCESS;
508 }
509
510 VOID
511 FASTCALL
512 ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
513 {
514 PCONSOLE Console;
515
516 DPRINT1("ConSrvRemoveConsole\n");
517
518 /* Close all console handles and free the handle table memory */
519 ConSrvFreeHandlesTable(ProcessData);
520
521 /* Detach process from console */
522 Console = ProcessData->Console;
523 if (Console != NULL)
524 {
525 DPRINT1("ConSrvRemoveConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount);
526 ProcessData->Console = NULL;
527 EnterCriticalSection(&Console->Lock);
528 DPRINT1("ConSrvRemoveConsole - Locking OK\n");
529 RemoveEntryList(&ProcessData->ConsoleLink);
530 ConSrvReleaseConsole(Console, TRUE);
531 //CloseHandle(ProcessData->ConsoleEvent);
532 //ProcessData->ConsoleEvent = NULL;
533 }
534 }
535
536 NTSTATUS
537 FASTCALL
538 ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
539 PCONSOLE* Console,
540 BOOL LockConsole)
541 {
542 PCONSOLE ProcessConsole;
543
544 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
545 ProcessConsole = ProcessData->Console;
546
547 if (!ProcessConsole)
548 {
549 *Console = NULL;
550 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
551 return STATUS_INVALID_HANDLE;
552 }
553
554 InterlockedIncrement(&ProcessConsole->ReferenceCount);
555 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
556
557 if (LockConsole) EnterCriticalSection(&ProcessConsole->Lock);
558
559 *Console = ProcessConsole;
560
561 return STATUS_SUCCESS;
562 }
563
564 VOID FASTCALL
565 ConSrvReleaseConsole(PCONSOLE Console,
566 BOOL IsConsoleLocked)
567 {
568 if (IsConsoleLocked) LeaveCriticalSection(&Console->Lock);
569
570 /* Decrement reference count */
571 if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
572 ConSrvDeleteConsole(Console);
573 }
574
575 NTSTATUS
576 NTAPI
577 ConSrvNewProcess(PCSR_PROCESS SourceProcess,
578 PCSR_PROCESS TargetProcess)
579 {
580 /**************************************************************************
581 * This function is called whenever a new process (GUI or CUI) is created.
582 *
583 * Copy the parent's handles table here if both the parent and the child
584 * processes are CUI. If we must actually create our proper console (and
585 * thus do not inherit from the console handles of the parent's), then we
586 * will clean this table in the next ConSrvConnect call. Why we are doing
587 * this? It's because here, we still don't know whether or not we must create
588 * a new console instead of inherit it from the parent, and, because in
589 * ConSrvConnect we don't have any reference to the parent process anymore.
590 **************************************************************************/
591
592 PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
593
594 DPRINT1("ConSrvNewProcess\n");
595 DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess, TargetProcess);
596
597 /* An empty target process is invalid */
598 if (!TargetProcess)
599 return STATUS_INVALID_PARAMETER;
600
601 DPRINT1("ConSrvNewProcess - OK\n");
602
603 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
604 DPRINT1("TargetProcessData = 0x%p\n", TargetProcessData);
605
606 /**** HACK !!!! ****/ RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData));
607
608 /* Initialize the new (target) process */
609 TargetProcessData->Process = TargetProcess;
610 TargetProcessData->ConsoleEvent = NULL;
611 TargetProcessData->Console = TargetProcessData->ParentConsole = NULL;
612 TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE);
613
614 // Testing
615 TargetProcessData->HandleTableSize = 0;
616 TargetProcessData->HandleTable = NULL;
617
618 /**** HACK !!!! ****/ RtlZeroMemory(&TargetProcessData->HandleTableLock, sizeof(RTL_CRITICAL_SECTION));
619 RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
620
621 /* Do nothing if the source process is NULL */
622 if (!SourceProcess)
623 return STATUS_SUCCESS;
624
625 SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
626 DPRINT1("SourceProcessData = 0x%p\n", SourceProcessData);
627
628 /*
629 * If both of the processes (parent and new child) are console applications,
630 * then try to inherit handles from the parent process.
631 */
632 if ( SourceProcessData->Console != NULL && /* SourceProcessData->ConsoleApp */
633 TargetProcessData->ConsoleApp )
634 {
635 NTSTATUS Status;
636
637 Status = ConSrvInheritHandlesTable(SourceProcessData, TargetProcessData);
638 if (!NT_SUCCESS(Status)) return Status;
639
640 /* Temporary save the parent's console */
641 TargetProcessData->ParentConsole = SourceProcessData->Console;
642 }
643 else
644 {
645 DPRINT1("ConSrvNewProcess - We don't inherit a handle table : SourceProcessData->Console = 0x%p ; TargetProcess->Flags = %lu\n", SourceProcessData->Console, TargetProcess->Flags);
646 }
647
648 return STATUS_SUCCESS;
649 }
650
651 NTSTATUS
652 NTAPI
653 ConSrvConnect(IN PCSR_PROCESS CsrProcess,
654 IN OUT PVOID ConnectionInfo,
655 IN OUT PULONG ConnectionInfoLength)
656 {
657 /**************************************************************************
658 * This function is called whenever a CUI new process is created.
659 **************************************************************************/
660
661 NTSTATUS Status = STATUS_SUCCESS;
662 PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo;
663 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
664
665 DPRINT1("ConSrvConnect\n");
666
667 if ( ConnectionInfo == NULL ||
668 ConnectionInfoLength == NULL ||
669 *ConnectionInfoLength != sizeof(CONSOLE_CONNECTION_INFO) )
670 {
671 DPRINT1("CONSRV: Connection failed\n");
672 return STATUS_UNSUCCESSFUL;
673 }
674
675 /* If we don't need a console, then get out of here */
676 if (!ConnectInfo->ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps.
677 {
678 DPRINT("ConSrvConnect - No console needed\n");
679 return STATUS_SUCCESS;
680 }
681
682 /* If we don't have a console, then create a new one... */
683 if (!ConnectInfo->Console ||
684 ConnectInfo->Console != ProcessData->ParentConsole)
685 {
686 DPRINT1("ConSrvConnect - Allocate a new console\n");
687
688 /*
689 * We are about to create a new console. However when ConSrvNewProcess
690 * was called, we didn't know that we wanted to create a new console and
691 * therefore, we by default inherited the handles table from our parent
692 * process. It's only now that we notice that in fact we do not need
693 * them, because we've created a new console and thus we must use it.
694 *
695 * Therefore, free the console we can have and our handles table,
696 * and recreate a new one later on.
697 */
698 ConSrvRemoveConsole(ProcessData);
699
700 /* Initialize a new Console owned by the Console Leader Process */
701 Status = ConSrvAllocateConsole(ProcessData,
702 &ConnectInfo->InputHandle,
703 &ConnectInfo->OutputHandle,
704 &ConnectInfo->ErrorHandle,
705 ConnectInfo->ShowCmd,
706 CsrProcess);
707 if (!NT_SUCCESS(Status))
708 {
709 DPRINT1("Console allocation failed\n");
710 return Status;
711 }
712 }
713 else /* We inherit it from the parent */
714 {
715 DPRINT1("ConSrvConnect - Reuse current (parent's) console\n");
716
717 /* Reuse our current console */
718 Status = ConSrvInheritConsole(ProcessData,
719 ConnectInfo->Console,
720 FALSE,
721 NULL, // &ConnectInfo->InputHandle,
722 NULL, // &ConnectInfo->OutputHandle,
723 NULL); // &ConnectInfo->ErrorHandle);
724 if (!NT_SUCCESS(Status))
725 {
726 DPRINT1("Console inheritance failed\n");
727 return Status;
728 }
729 }
730
731 /* Return it to the caller */
732 ConnectInfo->Console = ProcessData->Console;
733
734 /* Input Wait Handle */
735 ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent;
736
737 /* Set the Ctrl Dispatcher */
738 ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher;
739 DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
740
741 return STATUS_SUCCESS;
742 }
743
744 VOID
745 WINAPI
746 ConSrvDisconnect(PCSR_PROCESS Process)
747 {
748 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
749
750 /**************************************************************************
751 * This function is called whenever a new process (GUI or CUI) is destroyed.
752 **************************************************************************/
753
754 DPRINT1("ConSrvDisconnect\n");
755
756 if ( ProcessData->Console != NULL ||
757 ProcessData->HandleTable != NULL )
758 {
759 DPRINT1("ConSrvDisconnect - calling ConSrvRemoveConsole\n");
760 ConSrvRemoveConsole(ProcessData);
761 }
762
763 RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
764 }
765
766
767
768 CSR_API(SrvCloseHandle)
769 {
770 PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
771
772 return ConSrvRemoveObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
773 CloseHandleRequest->ConsoleHandle);
774 }
775
776 CSR_API(SrvVerifyConsoleIoHandle)
777 {
778 NTSTATUS Status = STATUS_SUCCESS;
779 PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
780 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
781 HANDLE ConsoleHandle = VerifyHandleRequest->ConsoleHandle;
782 ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2;
783
784 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
785
786 if (!IsConsoleHandle(ConsoleHandle) ||
787 Index >= ProcessData->HandleTableSize ||
788 ProcessData->HandleTable[Index].Object == NULL)
789 {
790 DPRINT("CsrVerifyObject failed\n");
791 Status = STATUS_INVALID_HANDLE;
792 }
793
794 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
795
796 return Status;
797 }
798
799 CSR_API(SrvDuplicateHandle)
800 {
801 PCONSOLE_IO_HANDLE Entry;
802 DWORD DesiredAccess;
803 PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
804 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
805 HANDLE ConsoleHandle = DuplicateHandleRequest->ConsoleHandle;
806 ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2;
807
808 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
809
810 if ( /** !IsConsoleHandle(ConsoleHandle) || **/
811 Index >= ProcessData->HandleTableSize ||
812 (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
813 {
814 DPRINT1("Couldn't duplicate invalid handle %p\n", ConsoleHandle);
815 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
816 return STATUS_INVALID_HANDLE;
817 }
818
819 if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
820 {
821 DesiredAccess = Entry->Access;
822 }
823 else
824 {
825 DesiredAccess = DuplicateHandleRequest->Access;
826 /* Make sure the source handle has all the desired flags */
827 if ((Entry->Access & DesiredAccess) == 0)
828 {
829 DPRINT1("Handle %p only has access %X; requested %X\n",
830 ConsoleHandle, Entry->Access, DesiredAccess);
831 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
832 return STATUS_INVALID_PARAMETER;
833 }
834 }
835
836 ApiMessage->Status = ConSrvInsertObject(ProcessData,
837 &DuplicateHandleRequest->ConsoleHandle, // Use the new handle value!
838 Entry->Object,
839 DesiredAccess,
840 DuplicateHandleRequest->Inheritable,
841 Entry->ShareMode);
842 if (NT_SUCCESS(ApiMessage->Status) &&
843 DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE)
844 {
845 ConSrvCloseHandleEntry(Entry);
846 }
847
848 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
849 return ApiMessage->Status;
850 }
851
852 /**
853 CSR_API(CsrGetInputWaitHandle)
854 {
855 PCSRSS_GET_INPUT_WAIT_HANDLE GetConsoleInputWaitHandle = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputWaitHandle;
856
857 GetConsoleInputWaitHandle->InputWaitHandle =
858 ConsoleGetPerProcessData(CsrGetClientThread()->Process)->ConsoleEvent;
859
860 return STATUS_SUCCESS;
861 }
862 **/
863
864 /* EOF */