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