94549d60675acae37e1b91660a4a72f81e67411e
[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 /* Forward declaration, used in ConSrvInitHandlesTable */
107 static VOID ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData);
108
109 static NTSTATUS
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 static NTSTATUS
185 ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
186 IN PCONSOLE_PROCESS_DATA TargetProcessData)
187 {
188 NTSTATUS Status = STATUS_SUCCESS;
189 ULONG i;
190
191 RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
192
193 /* Inherit a handles table only if there is no already */
194 if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */)
195 {
196 Status = STATUS_UNSUCCESSFUL; /* STATUS_INVALID_PARAMETER */
197 goto Quit;
198 }
199
200 /* Allocate a new handle table for the child process */
201 TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap,
202 HEAP_ZERO_MEMORY,
203 SourceProcessData->HandleTableSize
204 * sizeof(CONSOLE_IO_HANDLE));
205 if (TargetProcessData->HandleTable == NULL)
206 {
207 Status = STATUS_NO_MEMORY;
208 goto Quit;
209 }
210
211 TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
212
213 /*
214 * Parse the parent process' handles table and, for each handle,
215 * do a copy of it and reference it, if the handle is inheritable.
216 */
217 for (i = 0; i < SourceProcessData->HandleTableSize; i++)
218 {
219 if (SourceProcessData->HandleTable[i].Object != NULL &&
220 SourceProcessData->HandleTable[i].Inheritable)
221 {
222 /*
223 * Copy the handle data and increment the reference count of the
224 * pointed object (via the call to ConSrvCreateHandleEntry).
225 */
226 TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
227 ConSrvCreateHandleEntry(&TargetProcessData->HandleTable[i]);
228 }
229 }
230
231 Quit:
232 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
233 return Status;
234 }
235
236 static VOID
237 ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData)
238 {
239 DPRINT1("ConSrvFreeHandlesTable\n");
240
241 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
242
243 if (ProcessData->HandleTable != NULL)
244 {
245 ULONG i;
246
247 /* Close all console handles and free the handle table memory */
248 for (i = 0; i < ProcessData->HandleTableSize; i++)
249 {
250 ConSrvCloseHandleEntry(&ProcessData->HandleTable[i]);
251 }
252 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
253 ProcessData->HandleTable = NULL;
254 }
255
256 ProcessData->HandleTableSize = 0;
257
258 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
259 }
260
261 NTSTATUS
262 FASTCALL
263 ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
264 PHANDLE Handle,
265 Object_t *Object,
266 DWORD Access,
267 BOOL Inheritable,
268 DWORD ShareMode)
269 {
270 #define IO_HANDLES_INCREMENT 2*3
271
272 ULONG i;
273 PCONSOLE_IO_HANDLE Block;
274
275 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
276
277 for (i = 0; i < ProcessData->HandleTableSize; i++)
278 {
279 if (ProcessData->HandleTable[i].Object == NULL)
280 {
281 break;
282 }
283 }
284 if (i >= ProcessData->HandleTableSize)
285 {
286 Block = RtlAllocateHeap(ConSrvHeap,
287 HEAP_ZERO_MEMORY,
288 (ProcessData->HandleTableSize +
289 IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE));
290 if (Block == NULL)
291 {
292 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
293 return STATUS_UNSUCCESSFUL;
294 }
295 RtlCopyMemory(Block,
296 ProcessData->HandleTable,
297 ProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE));
298 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
299 ProcessData->HandleTable = Block;
300 ProcessData->HandleTableSize += IO_HANDLES_INCREMENT;
301 }
302
303 ProcessData->HandleTable[i].Object = Object;
304 ProcessData->HandleTable[i].Access = Access;
305 ProcessData->HandleTable[i].Inheritable = Inheritable;
306 ProcessData->HandleTable[i].ShareMode = ShareMode;
307 ConSrvCreateHandleEntry(&ProcessData->HandleTable[i]);
308 *Handle = ULongToHandle((i << 2) | 0x3);
309
310 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
311
312 return STATUS_SUCCESS;
313 }
314
315 NTSTATUS
316 FASTCALL
317 ConSrvRemoveObject(PCONSOLE_PROCESS_DATA ProcessData,
318 HANDLE Handle)
319 {
320 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
321 Object_t *Object;
322
323 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
324
325 if (h >= ProcessData->HandleTableSize ||
326 (Object = ProcessData->HandleTable[h].Object) == NULL)
327 {
328 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
329 return STATUS_INVALID_HANDLE;
330 }
331
332 DPRINT1("ConSrvRemoveObject - Process 0x%p, Release 0x%p\n", ProcessData->Process, &ProcessData->HandleTable[h]);
333 ConSrvCloseHandleEntry(&ProcessData->HandleTable[h]);
334
335 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
336
337 return STATUS_SUCCESS;
338 }
339
340 NTSTATUS
341 FASTCALL
342 ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData,
343 HANDLE Handle,
344 Object_t** Object,
345 PCONSOLE_IO_HANDLE* Entry OPTIONAL,
346 DWORD Access,
347 BOOL LockConsole,
348 ULONG Type)
349 {
350 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
351 PCONSOLE_IO_HANDLE HandleEntry = NULL;
352 Object_t* ObjectEntry = NULL;
353
354 ASSERT(Object);
355 if (Entry) *Entry = NULL;
356
357 // DPRINT("ConSrvGetObject, Object: %x, %x, %x\n",
358 // Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0);
359
360 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
361
362 if ( IsConsoleHandle(Handle) &&
363 h < ProcessData->HandleTableSize )
364 {
365 HandleEntry = &ProcessData->HandleTable[h];
366 ObjectEntry = HandleEntry->Object;
367 }
368
369 if ( HandleEntry == NULL ||
370 ObjectEntry == NULL ||
371 (HandleEntry->Access & Access) == 0 ||
372 (Type != 0 && ObjectEntry->Type != Type) )
373 {
374 DPRINT1("ConSrvGetObject returning invalid handle (%x) of type %lu with access %lu\n", Handle, Type, Access);
375 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
376 return STATUS_INVALID_HANDLE;
377 }
378
379 _InterlockedIncrement(&ObjectEntry->Console->ReferenceCount);
380 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
381
382 if (LockConsole) EnterCriticalSection(&ObjectEntry->Console->Lock);
383
384 /* Return the objects to the caller */
385 *Object = ObjectEntry;
386 if (Entry) *Entry = HandleEntry;
387
388 return STATUS_SUCCESS;
389 }
390
391 VOID
392 FASTCALL
393 ConSrvReleaseObject(Object_t *Object,
394 BOOL IsConsoleLocked)
395 {
396 ConSrvReleaseConsole(Object->Console, IsConsoleLocked);
397 }
398
399 NTSTATUS
400 FASTCALL
401 ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData,
402 PHANDLE pInputHandle,
403 PHANDLE pOutputHandle,
404 PHANDLE pErrorHandle,
405 PCONSOLE_START_INFO ConsoleStartInfo)
406 {
407 NTSTATUS Status = STATUS_SUCCESS;
408
409 /* Initialize a new Console owned by this process */
410 Status = ConSrvInitConsole(&ProcessData->Console, ConsoleStartInfo, ProcessData->Process);
411 if (!NT_SUCCESS(Status))
412 {
413 DPRINT1("Console initialization failed\n");
414 return Status;
415 }
416
417 /* Initialize the handles table */
418 Status = ConSrvInitHandlesTable(ProcessData,
419 pInputHandle,
420 pOutputHandle,
421 pErrorHandle);
422 if (!NT_SUCCESS(Status))
423 {
424 DPRINT1("Failed to initialize the handles table\n");
425 ConSrvDeleteConsole(ProcessData->Console);
426 ProcessData->Console = NULL;
427 return Status;
428 }
429
430 /* Duplicate the Input Event */
431 Status = NtDuplicateObject(NtCurrentProcess(),
432 ProcessData->Console->InputBuffer.ActiveEvent,
433 ProcessData->Process->ProcessHandle,
434 &ProcessData->ConsoleEvent,
435 EVENT_ALL_ACCESS, 0, 0);
436 if (!NT_SUCCESS(Status))
437 {
438 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
439 ConSrvFreeHandlesTable(ProcessData);
440 ConSrvDeleteConsole(ProcessData->Console);
441 ProcessData->Console = NULL;
442 return Status;
443 }
444
445 /* Insert the process into the processes list of the console */
446 InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
447
448 /* Add a reference count because the process is tied to the console */
449 _InterlockedIncrement(&ProcessData->Console->ReferenceCount);
450
451 /* Update the internal info of the terminal */
452 ConioRefreshInternalInfo(ProcessData->Console);
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 /* Update the internal info of the terminal */
507 ConioRefreshInternalInfo(ProcessData->Console);
508
509 return STATUS_SUCCESS;
510 }
511
512 VOID
513 FASTCALL
514 ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
515 {
516 PCONSOLE Console;
517
518 DPRINT1("ConSrvRemoveConsole\n");
519
520 /* Close all console handles and free the handle table memory */
521 ConSrvFreeHandlesTable(ProcessData);
522
523 /* Detach process from console */
524 Console = ProcessData->Console;
525 if (Console != NULL)
526 {
527 DPRINT1("ConSrvRemoveConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount);
528 ProcessData->Console = NULL;
529
530 EnterCriticalSection(&Console->Lock);
531 DPRINT1("ConSrvRemoveConsole - Locking OK\n");
532
533 /* Remove ourselves from the console's list of processes */
534 RemoveEntryList(&ProcessData->ConsoleLink);
535
536 /* Update the internal info of the terminal */
537 ConioRefreshInternalInfo(Console);
538
539 /* Release the console */
540 ConSrvReleaseConsole(Console, TRUE);
541 //CloseHandle(ProcessData->ConsoleEvent);
542 //ProcessData->ConsoleEvent = NULL;
543 }
544 }
545
546 NTSTATUS
547 FASTCALL
548 ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
549 PCONSOLE* Console,
550 BOOL LockConsole)
551 {
552 PCONSOLE ProcessConsole;
553
554 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
555 ProcessConsole = ProcessData->Console;
556
557 if (!ProcessConsole)
558 {
559 *Console = NULL;
560 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
561 return STATUS_INVALID_HANDLE;
562 }
563
564 InterlockedIncrement(&ProcessConsole->ReferenceCount);
565 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
566
567 if (LockConsole) EnterCriticalSection(&ProcessConsole->Lock);
568
569 *Console = ProcessConsole;
570
571 return STATUS_SUCCESS;
572 }
573
574 VOID FASTCALL
575 ConSrvReleaseConsole(PCONSOLE Console,
576 BOOL IsConsoleLocked)
577 {
578 if (IsConsoleLocked) LeaveCriticalSection(&Console->Lock);
579
580 /* Decrement reference count */
581 if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
582 ConSrvDeleteConsole(Console);
583 }
584
585 NTSTATUS
586 NTAPI
587 ConSrvNewProcess(PCSR_PROCESS SourceProcess,
588 PCSR_PROCESS TargetProcess)
589 {
590 /**************************************************************************
591 * This function is called whenever a new process (GUI or CUI) is created.
592 *
593 * Copy the parent's handles table here if both the parent and the child
594 * processes are CUI. If we must actually create our proper console (and
595 * thus do not inherit from the console handles of the parent's), then we
596 * will clean this table in the next ConSrvConnect call. Why we are doing
597 * this? It's because here, we still don't know whether or not we must create
598 * a new console instead of inherit it from the parent, and, because in
599 * ConSrvConnect we don't have any reference to the parent process anymore.
600 **************************************************************************/
601
602 PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
603
604 /* An empty target process is invalid */
605 if (!TargetProcess) return STATUS_INVALID_PARAMETER;
606
607 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
608
609 /**** HACK !!!! ****/ RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData));
610
611 /* Initialize the new (target) process */
612 TargetProcessData->Process = TargetProcess;
613 TargetProcessData->ConsoleEvent = NULL;
614 TargetProcessData->Console = TargetProcessData->ParentConsole = NULL;
615 TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE);
616
617 // Testing
618 TargetProcessData->HandleTableSize = 0;
619 TargetProcessData->HandleTable = NULL;
620
621 RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
622
623 /* Do nothing if the source process is NULL */
624 if (!SourceProcess) return STATUS_SUCCESS;
625
626 SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
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
644 return STATUS_SUCCESS;
645 }
646
647 NTSTATUS
648 NTAPI
649 ConSrvConnect(IN PCSR_PROCESS CsrProcess,
650 IN OUT PVOID ConnectionInfo,
651 IN OUT PULONG ConnectionInfoLength)
652 {
653 /**************************************************************************
654 * This function is called whenever a CUI new process is created.
655 **************************************************************************/
656
657 NTSTATUS Status = STATUS_SUCCESS;
658 PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo;
659 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
660
661 if ( ConnectionInfo == NULL ||
662 ConnectionInfoLength == NULL ||
663 *ConnectionInfoLength != sizeof(CONSOLE_CONNECTION_INFO) )
664 {
665 DPRINT1("CONSRV: Connection failed\n");
666 return STATUS_UNSUCCESSFUL;
667 }
668
669 /* If we don't need a console, then get out of here */
670 if (!ConnectInfo->ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps.
671 {
672 return STATUS_SUCCESS;
673 }
674
675 /* If we don't have a console, then create a new one... */
676 if (!ConnectInfo->Console ||
677 ConnectInfo->Console != ProcessData->ParentConsole)
678 {
679 DPRINT1("ConSrvConnect - Allocate a new console\n");
680
681 /*
682 * We are about to create a new console. However when ConSrvNewProcess
683 * was called, we didn't know that we wanted to create a new console and
684 * therefore, we by default inherited the handles table from our parent
685 * process. It's only now that we notice that in fact we do not need
686 * them, because we've created a new console and thus we must use it.
687 *
688 * Therefore, free the console we can have and our handles table,
689 * and recreate a new one later on.
690 */
691 ConSrvRemoveConsole(ProcessData);
692
693 /* Initialize a new Console owned by the Console Leader Process */
694 Status = ConSrvAllocateConsole(ProcessData,
695 &ConnectInfo->InputHandle,
696 &ConnectInfo->OutputHandle,
697 &ConnectInfo->ErrorHandle,
698 &ConnectInfo->ConsoleStartInfo);
699 if (!NT_SUCCESS(Status))
700 {
701 DPRINT1("Console allocation failed\n");
702 return Status;
703 }
704 }
705 else /* We inherit it from the parent */
706 {
707 DPRINT1("ConSrvConnect - Reuse current (parent's) console\n");
708
709 /* Reuse our current console */
710 Status = ConSrvInheritConsole(ProcessData,
711 ConnectInfo->Console,
712 FALSE,
713 NULL, // &ConnectInfo->InputHandle,
714 NULL, // &ConnectInfo->OutputHandle,
715 NULL); // &ConnectInfo->ErrorHandle);
716 if (!NT_SUCCESS(Status))
717 {
718 DPRINT1("Console inheritance failed\n");
719 return Status;
720 }
721 }
722
723 /* Return it to the caller */
724 ConnectInfo->Console = ProcessData->Console;
725
726 /* Input Wait Handle */
727 ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent;
728
729 /* Set the Property Dialog Handler */
730 ProcessData->PropDispatcher = ConnectInfo->PropDispatcher;
731
732 /* Set the Ctrl Dispatcher */
733 ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher;
734
735 return STATUS_SUCCESS;
736 }
737
738 VOID
739 NTAPI
740 ConSrvDisconnect(PCSR_PROCESS Process)
741 {
742 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
743
744 /**************************************************************************
745 * This function is called whenever a new process (GUI or CUI) is destroyed.
746 **************************************************************************/
747
748 DPRINT1("ConSrvDisconnect\n");
749
750 if ( ProcessData->Console != NULL ||
751 ProcessData->HandleTable != NULL )
752 {
753 DPRINT1("ConSrvDisconnect - calling ConSrvRemoveConsole\n");
754 ConSrvRemoveConsole(ProcessData);
755 }
756
757 RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
758 }
759
760
761 /* PUBLIC SERVER APIS *********************************************************/
762
763 CSR_API(SrvCloseHandle)
764 {
765 PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
766
767 return ConSrvRemoveObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
768 CloseHandleRequest->ConsoleHandle);
769 }
770
771 CSR_API(SrvVerifyConsoleIoHandle)
772 {
773 NTSTATUS Status = STATUS_SUCCESS;
774 PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
775 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
776 HANDLE ConsoleHandle = VerifyHandleRequest->ConsoleHandle;
777 ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2;
778
779 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
780
781 if (!IsConsoleHandle(ConsoleHandle) ||
782 Index >= ProcessData->HandleTableSize ||
783 ProcessData->HandleTable[Index].Object == NULL)
784 {
785 DPRINT("SrvVerifyConsoleIoHandle failed\n");
786 Status = STATUS_INVALID_HANDLE;
787 }
788
789 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
790
791 return Status;
792 }
793
794 CSR_API(SrvDuplicateHandle)
795 {
796 PCONSOLE_IO_HANDLE Entry;
797 DWORD DesiredAccess;
798 PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
799 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
800 HANDLE ConsoleHandle = DuplicateHandleRequest->ConsoleHandle;
801 ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2;
802
803 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
804
805 if ( /** !IsConsoleHandle(ConsoleHandle) || **/
806 Index >= ProcessData->HandleTableSize ||
807 (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
808 {
809 DPRINT1("Couldn't duplicate invalid handle %p\n", ConsoleHandle);
810 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
811 return STATUS_INVALID_HANDLE;
812 }
813
814 if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
815 {
816 DesiredAccess = Entry->Access;
817 }
818 else
819 {
820 DesiredAccess = DuplicateHandleRequest->Access;
821 /* Make sure the source handle has all the desired flags */
822 if ((Entry->Access & DesiredAccess) == 0)
823 {
824 DPRINT1("Handle %p only has access %X; requested %X\n",
825 ConsoleHandle, Entry->Access, DesiredAccess);
826 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
827 return STATUS_INVALID_PARAMETER;
828 }
829 }
830
831 ApiMessage->Status = ConSrvInsertObject(ProcessData,
832 &DuplicateHandleRequest->ConsoleHandle, // Use the new handle value!
833 Entry->Object,
834 DesiredAccess,
835 DuplicateHandleRequest->Inheritable,
836 Entry->ShareMode);
837 if (NT_SUCCESS(ApiMessage->Status) &&
838 DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE)
839 {
840 ConSrvCloseHandleEntry(Entry);
841 }
842
843 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
844 return ApiMessage->Status;
845 }
846
847 /* EOF */