Sync with trunk r63887.
[reactos.git] / win32ss / user / winsrv / consrv / handle.c
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 */