xref: /reactos/win32ss/user/winsrv/consrv/handle.c (revision b77b9b9b)
1 /*
2  * LICENSE:         GPL - See COPYING in the top level directory
3  * PROJECT:         ReactOS Console Server DLL
4  * FILE:            win32ss/user/winsrv/consrv/handle.c
5  * PURPOSE:         Console I/O Handles functions
6  * PROGRAMMERS:     David Welch
7  *                  Jeffrey Morlan
8  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
9  */
10 
11 /* INCLUDES *******************************************************************/
12 
13 #include "consrv.h"
14 
15 #include <win/console.h>
16 
17 #define NDEBUG
18 #include <debug.h>
19 
20 /* GLOBALS ********************************************************************/
21 
22 /* Console handle */
23 typedef struct _CONSOLE_IO_HANDLE
24 {
25     PCONSOLE_IO_OBJECT Object;   /* The object on which the handle points to */
26     ULONG   Access;
27     ULONG   ShareMode;
28     BOOLEAN Inheritable;
29 } CONSOLE_IO_HANDLE, *PCONSOLE_IO_HANDLE;
30 
31 
32 /* PRIVATE FUNCTIONS **********************************************************/
33 
34 static LONG
35 AdjustHandleCounts(IN PCONSOLE_IO_HANDLE Handle,
36                    IN LONG Change)
37 {
38     PCONSOLE_IO_OBJECT Object = Handle->Object;
39 
40     DPRINT("AdjustHandleCounts(0x%p, %d), Object = 0x%p\n",
41            Handle, Change, Object);
42     DPRINT("\tAdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->ReferenceCount = %d, Object->Type = %lu\n",
43            Handle, Change, Object, Object->ReferenceCount, Object->Type);
44 
45     if (Handle->Access & GENERIC_READ)           Object->AccessRead += Change;
46     if (Handle->Access & GENERIC_WRITE)          Object->AccessWrite += Change;
47     if (!(Handle->ShareMode & FILE_SHARE_READ))  Object->ExclusiveRead += Change;
48     if (!(Handle->ShareMode & FILE_SHARE_WRITE)) Object->ExclusiveWrite += Change;
49 
50     Object->ReferenceCount += Change;
51 
52     return Object->ReferenceCount;
53 }
54 
55 static VOID
56 ConSrvCloseHandle(IN PCONSOLE_IO_HANDLE Handle)
57 {
58     PCONSOLE_IO_OBJECT Object = Handle->Object;
59     if (Object != NULL)
60     {
61         /*
62          * If this is a input handle, notify and dereference
63          * all the waits related to this handle.
64          */
65         if (Object->Type == INPUT_BUFFER)
66         {
67             // PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
68             PCONSOLE Console = Object->Console;
69 
70             /*
71              * Wake up all the writing waiters related to this handle for this
72              * input buffer, if any, then dereference them and purge them all
73              * from the list.
74              * To select them amongst all the waiters for this input buffer,
75              * pass the handle pointer to the waiters, then they will check
76              * whether or not they are related to this handle and if so, they
77              * return.
78              */
79             CsrNotifyWait(&Console->ReadWaitQueue,
80                           TRUE,
81                           NULL,
82                           (PVOID)Handle);
83             if (!IsListEmpty(&Console->ReadWaitQueue))
84             {
85                 CsrDereferenceWait(&Console->ReadWaitQueue);
86             }
87         }
88 
89         /* If the last handle to a screen buffer is closed, delete it... */
90         if (AdjustHandleCounts(Handle, -1) == 0)
91         {
92             if (Object->Type == TEXTMODE_BUFFER || Object->Type == GRAPHICS_BUFFER)
93             {
94                 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
95                 /* ...unless it's the only buffer left. Windows allows deletion
96                  * even of the last buffer, but having to deal with a lack of
97                  * any active buffer might be error-prone. */
98                 if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink)
99                     ConioDeleteScreenBuffer(Buffer);
100             }
101             else if (Object->Type == INPUT_BUFFER)
102             {
103                 DPRINT("Closing the input buffer\n");
104             }
105             else
106             {
107                 DPRINT1("Invalid object type %d\n", Object->Type);
108             }
109         }
110 
111         /* Invalidate (zero-out) this handle entry */
112         // Handle->Object = NULL;
113         // RtlZeroMemory(Handle, sizeof(*Handle));
114     }
115     RtlZeroMemory(Handle, sizeof(*Handle)); // Be sure the whole entry is invalidated.
116 }
117 
118 
119 
120 
121 
122 
123 /* Forward declaration, used in ConSrvInitHandlesTable */
124 static VOID ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData);
125 
126 static NTSTATUS
127 ConSrvInitHandlesTable(IN OUT PCONSOLE_PROCESS_DATA ProcessData,
128                        IN PCONSOLE Console,
129                        OUT PHANDLE pInputHandle,
130                        OUT PHANDLE pOutputHandle,
131                        OUT PHANDLE pErrorHandle)
132 {
133     NTSTATUS Status;
134     HANDLE InputHandle  = INVALID_HANDLE_VALUE,
135            OutputHandle = INVALID_HANDLE_VALUE,
136            ErrorHandle  = INVALID_HANDLE_VALUE;
137 
138     /*
139      * Initialize the handles table. Use temporary variables to store
140      * the handles values in such a way that, if we fail, we don't
141      * return to the caller invalid handle values.
142      *
143      * Insert the IO handles.
144      */
145 
146     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
147 
148     /* Insert the Input handle */
149     Status = ConSrvInsertObject(ProcessData,
150                                 &InputHandle,
151                                 &Console->InputBuffer.Header,
152                                 GENERIC_READ | GENERIC_WRITE,
153                                 TRUE,
154                                 FILE_SHARE_READ | FILE_SHARE_WRITE);
155     if (!NT_SUCCESS(Status))
156     {
157         DPRINT1("Failed to insert the input handle\n");
158         RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
159         ConSrvFreeHandlesTable(ProcessData);
160         return Status;
161     }
162 
163     /* Insert the Output handle */
164     Status = ConSrvInsertObject(ProcessData,
165                                 &OutputHandle,
166                                 &Console->ActiveBuffer->Header,
167                                 GENERIC_READ | GENERIC_WRITE,
168                                 TRUE,
169                                 FILE_SHARE_READ | FILE_SHARE_WRITE);
170     if (!NT_SUCCESS(Status))
171     {
172         DPRINT1("Failed to insert the output handle\n");
173         RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
174         ConSrvFreeHandlesTable(ProcessData);
175         return Status;
176     }
177 
178     /* Insert the Error handle */
179     Status = ConSrvInsertObject(ProcessData,
180                                 &ErrorHandle,
181                                 &Console->ActiveBuffer->Header,
182                                 GENERIC_READ | GENERIC_WRITE,
183                                 TRUE,
184                                 FILE_SHARE_READ | FILE_SHARE_WRITE);
185     if (!NT_SUCCESS(Status))
186     {
187         DPRINT1("Failed to insert the error handle\n");
188         RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
189         ConSrvFreeHandlesTable(ProcessData);
190         return Status;
191     }
192 
193     /* Return the newly created handles */
194     *pInputHandle  = InputHandle;
195     *pOutputHandle = OutputHandle;
196     *pErrorHandle  = ErrorHandle;
197 
198     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
199     return STATUS_SUCCESS;
200 }
201 
202 NTSTATUS
203 ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
204                           IN PCONSOLE_PROCESS_DATA TargetProcessData)
205 {
206     NTSTATUS Status = STATUS_SUCCESS;
207     ULONG i, j;
208 
209     RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
210 
211     /* Inherit a handles table only if there is no already */
212     if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */)
213     {
214         Status = STATUS_UNSUCCESSFUL;
215         goto Quit;
216     }
217 
218     /* Allocate a new handle table for the child process */
219     TargetProcessData->HandleTable = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
220                                                       SourceProcessData->HandleTableSize
221                                                         * sizeof(CONSOLE_IO_HANDLE));
222     if (TargetProcessData->HandleTable == NULL)
223     {
224         Status = STATUS_NO_MEMORY;
225         goto Quit;
226     }
227 
228     TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
229 
230     /*
231      * Parse the parent process' handles table and, for each handle,
232      * do a copy of it and reference it, if the handle is inheritable.
233      */
234     for (i = 0, j = 0; i < SourceProcessData->HandleTableSize; i++)
235     {
236         if (SourceProcessData->HandleTable[i].Object != NULL &&
237             SourceProcessData->HandleTable[i].Inheritable)
238         {
239             /*
240              * Copy the handle data and increment the reference count of the
241              * pointed object (via the call to ConSrvCreateHandleEntry == AdjustHandleCounts).
242              */
243             TargetProcessData->HandleTable[j] = SourceProcessData->HandleTable[i];
244             AdjustHandleCounts(&TargetProcessData->HandleTable[j], +1);
245             ++j;
246         }
247     }
248 
249 Quit:
250     RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
251     return Status;
252 }
253 
254 static VOID
255 ConSrvFreeHandlesTable(IN PCONSOLE_PROCESS_DATA ProcessData)
256 {
257     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
258 
259     if (ProcessData->HandleTable != NULL)
260     {
261         ULONG i;
262 
263         /*
264          * ProcessData->ConsoleHandle is NULL (and the assertion fails) when
265          * ConSrvFreeHandlesTable is called in ConSrvConnect during the
266          * allocation of a new console.
267          */
268         // ASSERT(ProcessData->ConsoleHandle);
269         if (ProcessData->ConsoleHandle != NULL)
270         {
271             /* Close all the console handles */
272             for (i = 0; i < ProcessData->HandleTableSize; i++)
273             {
274                 ConSrvCloseHandle(&ProcessData->HandleTable[i]);
275             }
276         }
277         /* Free the handles table memory */
278         ConsoleFreeHeap(ProcessData->HandleTable);
279         ProcessData->HandleTable = NULL;
280     }
281 
282     ProcessData->HandleTableSize = 0;
283 
284     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
285 }
286 
287 
288 
289 
290 
291 
292 // ConSrvCreateObject
293 VOID
294 ConSrvInitObject(IN OUT PCONSOLE_IO_OBJECT Object,
295                  IN CONSOLE_IO_OBJECT_TYPE Type,
296                  IN PCONSOLE Console)
297 {
298     ASSERT(Object);
299     // if (!Object) return;
300 
301     Object->Type    = Type;
302     Object->Console = Console;
303     Object->ReferenceCount = 0;
304 
305     Object->AccessRead    = Object->AccessWrite    = 0;
306     Object->ExclusiveRead = Object->ExclusiveWrite = 0;
307 }
308 
309 NTSTATUS
310 ConSrvInsertObject(IN PCONSOLE_PROCESS_DATA ProcessData,
311                    OUT PHANDLE Handle,
312                    IN PCONSOLE_IO_OBJECT Object,
313                    IN ULONG Access,
314                    IN BOOLEAN Inheritable,
315                    IN ULONG ShareMode)
316 {
317 #define IO_HANDLES_INCREMENT    2 * 3
318 
319     ULONG i = 0;
320     PCONSOLE_IO_HANDLE Block;
321 
322     // NOTE: Commented out because calling code always lock HandleTableLock before.
323     // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
324 
325     ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
326             (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
327 
328     if (ProcessData->HandleTable)
329     {
330         for (i = 0; i < ProcessData->HandleTableSize; i++)
331         {
332             if (ProcessData->HandleTable[i].Object == NULL)
333                 break;
334         }
335     }
336 
337     if (i >= ProcessData->HandleTableSize)
338     {
339         /* Allocate a new handles table */
340         Block = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
341                                  (ProcessData->HandleTableSize +
342                                     IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE));
343         if (Block == NULL)
344         {
345             // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
346             return STATUS_UNSUCCESSFUL;
347         }
348 
349         /* If we previously had a handles table, free it and use the new one */
350         if (ProcessData->HandleTable)
351         {
352             /* Copy the handles from the old table to the new one */
353             RtlCopyMemory(Block,
354                           ProcessData->HandleTable,
355                           ProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE));
356             ConsoleFreeHeap(ProcessData->HandleTable);
357         }
358         ProcessData->HandleTable = Block;
359         ProcessData->HandleTableSize += IO_HANDLES_INCREMENT;
360     }
361 
362     ProcessData->HandleTable[i].Object      = Object;
363     ProcessData->HandleTable[i].Access      = Access;
364     ProcessData->HandleTable[i].Inheritable = Inheritable;
365     ProcessData->HandleTable[i].ShareMode   = ShareMode;
366     AdjustHandleCounts(&ProcessData->HandleTable[i], +1);
367     *Handle = ULongToHandle((i << 2) | 0x3);
368 
369     // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
370 
371     return STATUS_SUCCESS;
372 }
373 
374 NTSTATUS
375 ConSrvRemoveObject(IN PCONSOLE_PROCESS_DATA ProcessData,
376                    IN HANDLE Handle)
377 {
378     ULONG Index = HandleToULong(Handle) >> 2;
379 
380     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
381 
382     ASSERT(ProcessData->HandleTable);
383     // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
384     //         (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
385 
386     if (Index >= ProcessData->HandleTableSize ||
387         ProcessData->HandleTable[Index].Object == NULL)
388     {
389         RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
390         return STATUS_INVALID_HANDLE;
391     }
392 
393     ASSERT(ProcessData->ConsoleHandle);
394     ConSrvCloseHandle(&ProcessData->HandleTable[Index]);
395 
396     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
397     return STATUS_SUCCESS;
398 }
399 
400 NTSTATUS
401 ConSrvGetObject(IN PCONSOLE_PROCESS_DATA ProcessData,
402                 IN HANDLE Handle,
403                 OUT PCONSOLE_IO_OBJECT* Object,
404                 OUT PVOID* Entry OPTIONAL,
405                 IN ULONG Access,
406                 IN BOOLEAN LockConsole,
407                 IN CONSOLE_IO_OBJECT_TYPE Type)
408 {
409     // NTSTATUS Status;
410     ULONG Index = HandleToULong(Handle) >> 2;
411     PCONSOLE_IO_HANDLE HandleEntry = NULL;
412     PCONSOLE_IO_OBJECT ObjectEntry = NULL;
413     // PCONSOLE ObjectConsole;
414 
415     ASSERT(Object);
416     if (Entry) *Entry = NULL;
417 
418     DPRINT("ConSrvGetObject -- Object: 0x%x, Handle: 0x%x\n", Object, Handle);
419 
420     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
421 
422     if ( IsConsoleHandle(Handle) &&
423          Index < ProcessData->HandleTableSize )
424     {
425         HandleEntry = &ProcessData->HandleTable[Index];
426         ObjectEntry = HandleEntry->Object;
427     }
428 
429     if ( HandleEntry == NULL ||
430          ObjectEntry == NULL ||
431          (HandleEntry->Access & Access) == 0 ||
432          /*(Type != 0 && ObjectEntry->Type != Type)*/
433          (Type != 0 && (ObjectEntry->Type & Type) == 0) )
434     {
435         DPRINT("ConSrvGetObject -- Invalid handle 0x%x of type %lu with access %lu ; retrieved object 0x%x (handle 0x%x) of type %lu with access %lu\n",
436                Handle, Type, Access, ObjectEntry, HandleEntry, (ObjectEntry ? ObjectEntry->Type : 0), (HandleEntry ? HandleEntry->Access : 0));
437 
438         RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
439         return STATUS_INVALID_HANDLE;
440     }
441 
442     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
443 
444     // Status = ConSrvGetConsole(ProcessData, &ObjectConsole, LockConsole);
445     // if (NT_SUCCESS(Status))
446     if (ConDrvValidateConsoleUnsafe(ObjectEntry->Console, CONSOLE_RUNNING, LockConsole))
447     {
448         _InterlockedIncrement(&ObjectEntry->Console->ReferenceCount);
449 
450         /* Return the objects to the caller */
451         *Object = ObjectEntry;
452         if (Entry) *Entry = HandleEntry;
453 
454         // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
455         return STATUS_SUCCESS;
456     }
457     else
458     {
459         // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
460         return STATUS_INVALID_HANDLE;
461     }
462 }
463 
464 VOID
465 ConSrvReleaseObject(IN PCONSOLE_IO_OBJECT Object,
466                     IN BOOLEAN IsConsoleLocked)
467 {
468     ConSrvReleaseConsole(Object->Console, IsConsoleLocked);
469 }
470 
471 
472 
473 
474 
475 
476 NTSTATUS
477 ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData,
478                       PHANDLE pInputHandle,
479                       PHANDLE pOutputHandle,
480                       PHANDLE pErrorHandle,
481                       PCONSOLE_START_INFO ConsoleStartInfo)
482 {
483     NTSTATUS Status = STATUS_SUCCESS;
484     HANDLE ConsoleHandle;
485     PCONSRV_CONSOLE Console;
486 
487     /*
488      * We are about to create a new console. However when ConSrvNewProcess
489      * was called, we didn't know that we wanted to create a new console and
490      * therefore, we by default inherited the handles table from our parent
491      * process. It's only now that we notice that in fact we do not need
492      * them, because we've created a new console and thus we must use it.
493      *
494      * Therefore, free the handles table so that we can recreate
495      * a new one later on.
496      */
497     ConSrvFreeHandlesTable(ProcessData);
498 
499     /* Initialize a new Console owned by this process */
500     Status = ConSrvInitConsole(&ConsoleHandle,
501                                &Console,
502                                ConsoleStartInfo,
503                                HandleToUlong(ProcessData->Process->ClientId.UniqueProcess));
504     if (!NT_SUCCESS(Status))
505     {
506         DPRINT1("Console initialization failed\n");
507         return Status;
508     }
509 
510     /* Assign the new console handle */
511     ProcessData->ConsoleHandle = ConsoleHandle;
512 
513     /* Initialize the handles table */
514     Status = ConSrvInitHandlesTable(ProcessData,
515                                     Console,
516                                     pInputHandle,
517                                     pOutputHandle,
518                                     pErrorHandle);
519     if (!NT_SUCCESS(Status))
520     {
521         DPRINT1("Failed to initialize the handles table\n");
522         ConSrvDeleteConsole(Console);
523         ProcessData->ConsoleHandle = NULL;
524         return Status;
525     }
526 
527     /* Duplicate the Input Event */
528     Status = NtDuplicateObject(NtCurrentProcess(),
529                                Console->InputBuffer.ActiveEvent,
530                                ProcessData->Process->ProcessHandle,
531                                &ProcessData->InputWaitHandle,
532                                EVENT_ALL_ACCESS, 0, 0);
533     if (!NT_SUCCESS(Status))
534     {
535         DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
536         ConSrvFreeHandlesTable(ProcessData);
537         ConSrvDeleteConsole(Console);
538         ProcessData->ConsoleHandle = NULL;
539         return Status;
540     }
541 
542     /* Insert the process into the processes list of the console */
543     InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
544 
545     /* Add a reference count because the process is tied to the console */
546     _InterlockedIncrement(&Console->ReferenceCount);
547 
548     /* Update the internal info of the terminal */
549     TermRefreshInternalInfo(Console);
550 
551     return STATUS_SUCCESS;
552 }
553 
554 NTSTATUS
555 ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
556                      HANDLE ConsoleHandle,
557                      BOOLEAN CreateNewHandlesTable,
558                      PHANDLE pInputHandle,
559                      PHANDLE pOutputHandle,
560                      PHANDLE pErrorHandle)
561 {
562     NTSTATUS Status = STATUS_SUCCESS;
563     PCONSOLE Console;
564 
565     /* Validate and lock the console */
566     if (!ConSrvValidateConsole(&Console,
567                                ConsoleHandle,
568                                CONSOLE_RUNNING, TRUE))
569     {
570         // FIXME: Find another status code
571         return STATUS_UNSUCCESSFUL;
572     }
573 
574     /* Inherit the console */
575     ProcessData->ConsoleHandle = ConsoleHandle;
576 
577     if (CreateNewHandlesTable)
578     {
579         /*
580          * We are about to create a new console. However when ConSrvNewProcess
581          * was called, we didn't know that we wanted to create a new console and
582          * therefore, we by default inherited the handles table from our parent
583          * process. It's only now that we notice that in fact we do not need
584          * them, because we've created a new console and thus we must use it.
585          *
586          * Therefore, free the handles table so that we can recreate
587          * a new one later on.
588          */
589         ConSrvFreeHandlesTable(ProcessData);
590 
591         /* Initialize the handles table */
592         Status = ConSrvInitHandlesTable(ProcessData,
593                                         Console,
594                                         pInputHandle,
595                                         pOutputHandle,
596                                         pErrorHandle);
597         if (!NT_SUCCESS(Status))
598         {
599             DPRINT1("Failed to initialize the handles table\n");
600             ProcessData->ConsoleHandle = NULL;
601             goto Quit;
602         }
603     }
604 
605     /* Duplicate the Input Event */
606     Status = NtDuplicateObject(NtCurrentProcess(),
607                                Console->InputBuffer.ActiveEvent,
608                                ProcessData->Process->ProcessHandle,
609                                &ProcessData->InputWaitHandle,
610                                EVENT_ALL_ACCESS, 0, 0);
611     if (!NT_SUCCESS(Status))
612     {
613         DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
614         ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table.
615         ProcessData->ConsoleHandle = NULL;
616         goto Quit;
617     }
618 
619     /* Insert the process into the processes list of the console */
620     InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
621 
622     /* Add a reference count because the process is tied to the console */
623     _InterlockedIncrement(&Console->ReferenceCount);
624 
625     /* Update the internal info of the terminal */
626     TermRefreshInternalInfo(Console);
627 
628     Status = STATUS_SUCCESS;
629 
630 Quit:
631     /* Unlock the console and return */
632     LeaveCriticalSection(&Console->Lock);
633     return Status;
634 }
635 
636 VOID
637 ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
638 {
639     PCONSOLE Console;
640 
641     DPRINT("ConSrvRemoveConsole\n");
642 
643     // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
644 
645     /* Validate and lock the console */
646     if (ConSrvValidateConsole(&Console,
647                               ProcessData->ConsoleHandle,
648                               CONSOLE_RUNNING, TRUE))
649     {
650         /* Retrieve the console leader process */
651         PCONSOLE_PROCESS_DATA ConsoleLeaderProcess = ConSrvGetConsoleLeaderProcess(Console);
652 
653         DPRINT("ConSrvRemoveConsole - Locking OK\n");
654 
655         /* Close all console handles and free the handles table */
656         ConSrvFreeHandlesTable(ProcessData);
657 
658         /* Detach the process from the console */
659         ProcessData->ConsoleHandle = NULL;
660 
661         /* Remove the process from the console's list of processes */
662         RemoveEntryList(&ProcessData->ConsoleLink);
663 
664         /* Check whether the console should send a last close notification */
665         if (Console->NotifyLastClose)
666         {
667             /* If we are removing the process which wants the last close notification... */
668             if (ProcessData == Console->NotifiedLastCloseProcess)
669             {
670                 /* ... just reset the flag and the pointer... */
671                 Console->NotifyLastClose = FALSE;
672                 Console->NotifiedLastCloseProcess = NULL;
673             }
674             /*
675              * ... otherwise, if we are removing the console leader process
676              * (that cannot be the process wanting the notification, because
677              * the previous case already dealt with it)...
678              */
679             else if (ProcessData == ConsoleLeaderProcess)
680             {
681                 /*
682                  * ... reset the flag first (so that we avoid multiple notifications)
683                  * and then send the last close notification.
684                  */
685                 Console->NotifyLastClose = FALSE;
686                 ConSrvConsoleCtrlEvent(CTRL_LAST_CLOSE_EVENT, Console->NotifiedLastCloseProcess);
687 
688                 /* Only now, reset the pointer */
689                 Console->NotifiedLastCloseProcess = NULL;
690             }
691         }
692 
693         /* Update the internal info of the terminal */
694         TermRefreshInternalInfo(Console);
695 
696         /* Release the console */
697         DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount);
698         ConSrvReleaseConsole(Console, TRUE);
699         //CloseHandle(ProcessData->InputWaitHandle);
700         //ProcessData->InputWaitHandle = NULL;
701     }
702 
703     // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
704 }
705 
706 
707 /* PUBLIC SERVER APIS *********************************************************/
708 
709 CSR_API(SrvOpenConsole)
710 {
711     /*
712      * This API opens a handle to either the input buffer or to
713      * a screen-buffer of the console of the current process.
714      */
715 
716     NTSTATUS Status;
717     PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
718     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
719     PCONSOLE Console;
720 
721     DWORD DesiredAccess = OpenConsoleRequest->DesiredAccess;
722     DWORD ShareMode = OpenConsoleRequest->ShareMode;
723     PCONSOLE_IO_OBJECT Object;
724 
725     OpenConsoleRequest->Handle = INVALID_HANDLE_VALUE;
726 
727     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
728     if (!NT_SUCCESS(Status))
729     {
730         DPRINT1("Can't get console\n");
731         return Status;
732     }
733 
734     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
735 
736     /*
737      * Open a handle to either the active screen buffer or the input buffer.
738      */
739     if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
740     {
741         Object = &Console->ActiveBuffer->Header;
742     }
743     else // HANDLE_INPUT
744     {
745         Object = &Console->InputBuffer.Header;
746     }
747 
748     if (((DesiredAccess & GENERIC_READ)  && Object->ExclusiveRead  != 0) ||
749         ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) ||
750         (!(ShareMode & FILE_SHARE_READ)  && Object->AccessRead     != 0) ||
751         (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite    != 0))
752     {
753         DPRINT1("Sharing violation\n");
754         Status = STATUS_SHARING_VIOLATION;
755     }
756     else
757     {
758         Status = ConSrvInsertObject(ProcessData,
759                                     &OpenConsoleRequest->Handle,
760                                     Object,
761                                     DesiredAccess,
762                                     OpenConsoleRequest->InheritHandle,
763                                     ShareMode);
764     }
765 
766     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
767 
768     ConSrvReleaseConsole(Console, TRUE);
769     return Status;
770 }
771 
772 CSR_API(SrvDuplicateHandle)
773 {
774     NTSTATUS Status;
775     PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
776     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
777     PCONSOLE Console;
778 
779     HANDLE SourceHandle = DuplicateHandleRequest->SourceHandle;
780     ULONG Index = HandleToULong(SourceHandle) >> 2;
781     PCONSOLE_IO_HANDLE Entry;
782     DWORD DesiredAccess;
783 
784     DuplicateHandleRequest->TargetHandle = INVALID_HANDLE_VALUE;
785 
786     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
787     if (!NT_SUCCESS(Status))
788     {
789         DPRINT1("Can't get console\n");
790         return Status;
791     }
792 
793     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
794 
795     // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
796     //         (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
797 
798     if ( /** !IsConsoleHandle(SourceHandle)   || **/
799         Index >= ProcessData->HandleTableSize ||
800         (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
801     {
802         DPRINT1("Couldn't duplicate invalid handle 0x%p\n", SourceHandle);
803         Status = STATUS_INVALID_HANDLE;
804         goto Quit;
805     }
806 
807     if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
808     {
809         DesiredAccess = Entry->Access;
810     }
811     else
812     {
813         DesiredAccess = DuplicateHandleRequest->DesiredAccess;
814         /* Make sure the source handle has all the desired flags */
815         if ((Entry->Access & DesiredAccess) == 0)
816         {
817             DPRINT1("Handle 0x%p only has access %X; requested %X\n",
818                     SourceHandle, Entry->Access, DesiredAccess);
819             Status = STATUS_INVALID_PARAMETER;
820             goto Quit;
821         }
822     }
823 
824     /* Insert the new handle inside the process handles table */
825     Status = ConSrvInsertObject(ProcessData,
826                                 &DuplicateHandleRequest->TargetHandle,
827                                 Entry->Object,
828                                 DesiredAccess,
829                                 DuplicateHandleRequest->InheritHandle,
830                                 Entry->ShareMode);
831     if (NT_SUCCESS(Status) &&
832         (DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE))
833     {
834         /* Close the original handle if needed */
835         ConSrvCloseHandle(Entry);
836     }
837 
838 Quit:
839     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
840 
841     ConSrvReleaseConsole(Console, TRUE);
842     return Status;
843 }
844 
845 CSR_API(SrvGetHandleInformation)
846 {
847     NTSTATUS Status;
848     PCONSOLE_GETHANDLEINFO GetHandleInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetHandleInfoRequest;
849     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
850     PCONSOLE Console;
851 
852     HANDLE Handle = GetHandleInfoRequest->Handle;
853     ULONG Index = HandleToULong(Handle) >> 2;
854     PCONSOLE_IO_HANDLE Entry;
855 
856     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
857     if (!NT_SUCCESS(Status))
858     {
859         DPRINT1("Can't get console\n");
860         return Status;
861     }
862 
863     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
864 
865     ASSERT(ProcessData->HandleTable);
866     // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
867     //         (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
868 
869     if (!IsConsoleHandle(Handle)              ||
870         Index >= ProcessData->HandleTableSize ||
871         (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
872     {
873         Status = STATUS_INVALID_HANDLE;
874         goto Quit;
875     }
876 
877     /*
878      * Retrieve the handle information flags. The console server
879      * doesn't support HANDLE_FLAG_PROTECT_FROM_CLOSE.
880      */
881     GetHandleInfoRequest->Flags = 0;
882     if (Entry->Inheritable) GetHandleInfoRequest->Flags |= HANDLE_FLAG_INHERIT;
883 
884     Status = STATUS_SUCCESS;
885 
886 Quit:
887     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
888 
889     ConSrvReleaseConsole(Console, TRUE);
890     return Status;
891 }
892 
893 CSR_API(SrvSetHandleInformation)
894 {
895     NTSTATUS Status;
896     PCONSOLE_SETHANDLEINFO SetHandleInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetHandleInfoRequest;
897     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
898     PCONSOLE Console;
899 
900     HANDLE Handle = SetHandleInfoRequest->Handle;
901     ULONG Index = HandleToULong(Handle) >> 2;
902     PCONSOLE_IO_HANDLE Entry;
903 
904     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
905     if (!NT_SUCCESS(Status))
906     {
907         DPRINT1("Can't get console\n");
908         return Status;
909     }
910 
911     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
912 
913     ASSERT(ProcessData->HandleTable);
914     // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
915     //         (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
916 
917     if (!IsConsoleHandle(Handle)              ||
918         Index >= ProcessData->HandleTableSize ||
919         (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
920     {
921         Status = STATUS_INVALID_HANDLE;
922         goto Quit;
923     }
924 
925     /*
926      * Modify the handle information flags. The console server
927      * doesn't support HANDLE_FLAG_PROTECT_FROM_CLOSE.
928      */
929     if (SetHandleInfoRequest->Mask & HANDLE_FLAG_INHERIT)
930     {
931         Entry->Inheritable = ((SetHandleInfoRequest->Flags & HANDLE_FLAG_INHERIT) != 0);
932     }
933 
934     Status = STATUS_SUCCESS;
935 
936 Quit:
937     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
938 
939     ConSrvReleaseConsole(Console, TRUE);
940     return Status;
941 }
942 
943 CSR_API(SrvCloseHandle)
944 {
945     NTSTATUS Status;
946     PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
947     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
948     PCONSOLE Console;
949 
950     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
951     if (!NT_SUCCESS(Status))
952     {
953         DPRINT1("Can't get console\n");
954         return Status;
955     }
956 
957     Status = ConSrvRemoveObject(ProcessData, CloseHandleRequest->Handle);
958 
959     ConSrvReleaseConsole(Console, TRUE);
960     return Status;
961 }
962 
963 CSR_API(SrvVerifyConsoleIoHandle)
964 {
965     NTSTATUS Status;
966     PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
967     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
968     PCONSOLE Console;
969 
970     HANDLE IoHandle = VerifyHandleRequest->Handle;
971     ULONG Index = HandleToULong(IoHandle) >> 2;
972 
973     VerifyHandleRequest->IsValid = FALSE;
974 
975     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
976     if (!NT_SUCCESS(Status))
977     {
978         DPRINT1("Can't get console\n");
979         return Status;
980     }
981 
982     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
983 
984     // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
985     //         (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
986 
987     if (!IsConsoleHandle(IoHandle)            ||
988         Index >= ProcessData->HandleTableSize ||
989         ProcessData->HandleTable[Index].Object == NULL)
990     {
991         DPRINT("SrvVerifyConsoleIoHandle failed\n");
992     }
993     else
994     {
995         VerifyHandleRequest->IsValid = TRUE;
996     }
997 
998     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
999 
1000     ConSrvReleaseConsole(Console, TRUE);
1001     return STATUS_SUCCESS;
1002 }
1003 
1004 /* EOF */
1005