[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 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 DPRINT1("ConSrvNewProcess\n");
602 DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess, TargetProcess);
603
604 /* An empty target process is invalid */
605 if (!TargetProcess)
606 return STATUS_INVALID_PARAMETER;
607
608 DPRINT1("ConSrvNewProcess - OK\n");
609
610 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
611
612 /**** HACK !!!! ****/ RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData));
613
614 /* Initialize the new (target) process */
615 TargetProcessData->Process = TargetProcess;
616 TargetProcessData->ConsoleEvent = NULL;
617 TargetProcessData->Console = TargetProcessData->ParentConsole = NULL;
618 TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE);
619
620 // Testing
621 TargetProcessData->HandleTableSize = 0;
622 TargetProcessData->HandleTable = NULL;
623
624 RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
625
626 /* Do nothing if the source process is NULL */
627 if (!SourceProcess)
628 return STATUS_SUCCESS;
629
630 SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
631
632 /*
633 * If both of the processes (parent and new child) are console applications,
634 * then try to inherit handles from the parent process.
635 */
636 if ( SourceProcessData->Console != NULL && /* SourceProcessData->ConsoleApp */
637 TargetProcessData->ConsoleApp )
638 {
639 NTSTATUS Status;
640
641 Status = ConSrvInheritHandlesTable(SourceProcessData, TargetProcessData);
642 if (!NT_SUCCESS(Status)) return Status;
643
644 /* Temporary save the parent's console */
645 TargetProcessData->ParentConsole = SourceProcessData->Console;
646 }
647 else
648 {
649 DPRINT1("ConSrvNewProcess - We don't inherit a handle table : SourceProcessData->Console = 0x%p ; TargetProcess->Flags = %lu\n", SourceProcessData->Console, TargetProcess->Flags);
650 }
651
652 return STATUS_SUCCESS;
653 }
654
655 NTSTATUS
656 NTAPI
657 ConSrvConnect(IN PCSR_PROCESS CsrProcess,
658 IN OUT PVOID ConnectionInfo,
659 IN OUT PULONG ConnectionInfoLength)
660 {
661 /**************************************************************************
662 * This function is called whenever a CUI new process is created.
663 **************************************************************************/
664
665 NTSTATUS Status = STATUS_SUCCESS;
666 PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo;
667 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
668
669 DPRINT1("ConSrvConnect\n");
670
671 if ( ConnectionInfo == NULL ||
672 ConnectionInfoLength == NULL ||
673 *ConnectionInfoLength != sizeof(CONSOLE_CONNECTION_INFO) )
674 {
675 DPRINT1("CONSRV: Connection failed\n");
676 return STATUS_UNSUCCESSFUL;
677 }
678
679 /* If we don't need a console, then get out of here */
680 if (!ConnectInfo->ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps.
681 {
682 DPRINT("ConSrvConnect - No console needed\n");
683 return STATUS_SUCCESS;
684 }
685
686 /* If we don't have a console, then create a new one... */
687 if (!ConnectInfo->Console ||
688 ConnectInfo->Console != ProcessData->ParentConsole)
689 {
690 DPRINT1("ConSrvConnect - Allocate a new console\n");
691
692 /*
693 * We are about to create a new console. However when ConSrvNewProcess
694 * was called, we didn't know that we wanted to create a new console and
695 * therefore, we by default inherited the handles table from our parent
696 * process. It's only now that we notice that in fact we do not need
697 * them, because we've created a new console and thus we must use it.
698 *
699 * Therefore, free the console we can have and our handles table,
700 * and recreate a new one later on.
701 */
702 ConSrvRemoveConsole(ProcessData);
703
704 /* Initialize a new Console owned by the Console Leader Process */
705 Status = ConSrvAllocateConsole(ProcessData,
706 ConnectInfo->AppPath,
707 &ConnectInfo->InputHandle,
708 &ConnectInfo->OutputHandle,
709 &ConnectInfo->ErrorHandle,
710 &ConnectInfo->ConsoleStartInfo);
711 if (!NT_SUCCESS(Status))
712 {
713 DPRINT1("Console allocation failed\n");
714 return Status;
715 }
716 }
717 else /* We inherit it from the parent */
718 {
719 DPRINT1("ConSrvConnect - Reuse current (parent's) console\n");
720
721 /* Reuse our current console */
722 Status = ConSrvInheritConsole(ProcessData,
723 ConnectInfo->Console,
724 FALSE,
725 NULL, // &ConnectInfo->InputHandle,
726 NULL, // &ConnectInfo->OutputHandle,
727 NULL); // &ConnectInfo->ErrorHandle);
728 if (!NT_SUCCESS(Status))
729 {
730 DPRINT1("Console inheritance failed\n");
731 return Status;
732 }
733 }
734
735 /* Return it to the caller */
736 ConnectInfo->Console = ProcessData->Console;
737
738 /* Input Wait Handle */
739 ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent;
740
741 /* Set the Property Dialog Handler */
742 ProcessData->PropDispatcher = ConnectInfo->PropDispatcher;
743
744 /* Set the Ctrl Dispatcher */
745 ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher;
746 DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
747
748 return STATUS_SUCCESS;
749 }
750
751 VOID
752 NTAPI
753 ConSrvDisconnect(PCSR_PROCESS Process)
754 {
755 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
756
757 /**************************************************************************
758 * This function is called whenever a new process (GUI or CUI) is destroyed.
759 **************************************************************************/
760
761 DPRINT1("ConSrvDisconnect\n");
762
763 if ( ProcessData->Console != NULL ||
764 ProcessData->HandleTable != NULL )
765 {
766 DPRINT1("ConSrvDisconnect - calling ConSrvRemoveConsole\n");
767 ConSrvRemoveConsole(ProcessData);
768 }
769
770 RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
771 }
772
773
774
775 CSR_API(SrvCloseHandle)
776 {
777 PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
778
779 return ConSrvRemoveObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
780 CloseHandleRequest->ConsoleHandle);
781 }
782
783 CSR_API(SrvVerifyConsoleIoHandle)
784 {
785 NTSTATUS Status = STATUS_SUCCESS;
786 PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
787 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
788 HANDLE ConsoleHandle = VerifyHandleRequest->ConsoleHandle;
789 ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2;
790
791 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
792
793 if (!IsConsoleHandle(ConsoleHandle) ||
794 Index >= ProcessData->HandleTableSize ||
795 ProcessData->HandleTable[Index].Object == NULL)
796 {
797 DPRINT("SrvVerifyConsoleIoHandle failed\n");
798 Status = STATUS_INVALID_HANDLE;
799 }
800
801 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
802
803 return Status;
804 }
805
806 CSR_API(SrvDuplicateHandle)
807 {
808 PCONSOLE_IO_HANDLE Entry;
809 DWORD DesiredAccess;
810 PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
811 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
812 HANDLE ConsoleHandle = DuplicateHandleRequest->ConsoleHandle;
813 ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2;
814
815 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
816
817 if ( /** !IsConsoleHandle(ConsoleHandle) || **/
818 Index >= ProcessData->HandleTableSize ||
819 (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
820 {
821 DPRINT1("Couldn't duplicate invalid handle %p\n", ConsoleHandle);
822 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
823 return STATUS_INVALID_HANDLE;
824 }
825
826 if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
827 {
828 DesiredAccess = Entry->Access;
829 }
830 else
831 {
832 DesiredAccess = DuplicateHandleRequest->Access;
833 /* Make sure the source handle has all the desired flags */
834 if ((Entry->Access & DesiredAccess) == 0)
835 {
836 DPRINT1("Handle %p only has access %X; requested %X\n",
837 ConsoleHandle, Entry->Access, DesiredAccess);
838 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
839 return STATUS_INVALID_PARAMETER;
840 }
841 }
842
843 ApiMessage->Status = ConSrvInsertObject(ProcessData,
844 &DuplicateHandleRequest->ConsoleHandle, // Use the new handle value!
845 Entry->Object,
846 DesiredAccess,
847 DuplicateHandleRequest->Inheritable,
848 Entry->ShareMode);
849 if (NT_SUCCESS(ApiMessage->Status) &&
850 DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE)
851 {
852 ConSrvCloseHandleEntry(Entry);
853 }
854
855 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
856 return ApiMessage->Status;
857 }
858
859 /* EOF */