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