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