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