779284e0e208f4b0471ce4de1274454ab4d9068a
[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 PCONSOLE_IO_OBJECT Object;
381
382 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
383
384 ASSERT(ProcessData->HandleTable);
385 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
386 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
387
388 if (Index >= ProcessData->HandleTableSize ||
389 (Object = ProcessData->HandleTable[Index].Object) == NULL)
390 {
391 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
392 return STATUS_INVALID_HANDLE;
393 }
394
395 ASSERT(ProcessData->ConsoleHandle);
396 ConSrvCloseHandleEntry(&ProcessData->HandleTable[Index]);
397
398 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
399 return STATUS_SUCCESS;
400 }
401
402 NTSTATUS
403 FASTCALL
404 ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData,
405 HANDLE Handle,
406 PCONSOLE_IO_OBJECT* Object,
407 PVOID* Entry OPTIONAL,
408 DWORD Access,
409 BOOL LockConsole,
410 CONSOLE_IO_OBJECT_TYPE Type)
411 {
412 // NTSTATUS Status;
413 ULONG Index = HandleToULong(Handle) >> 2;
414 PCONSOLE_IO_HANDLE HandleEntry = NULL;
415 PCONSOLE_IO_OBJECT ObjectEntry = NULL;
416 // PCONSOLE ObjectConsole;
417
418 ASSERT(Object);
419 if (Entry) *Entry = NULL;
420
421 DPRINT("ConSrvGetObject -- Object: 0x%x, Handle: 0x%x\n", Object, Handle);
422
423 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
424
425 if ( IsConsoleHandle(Handle) &&
426 Index < ProcessData->HandleTableSize )
427 {
428 HandleEntry = &ProcessData->HandleTable[Index];
429 ObjectEntry = HandleEntry->Object;
430 }
431
432 if ( HandleEntry == NULL ||
433 ObjectEntry == NULL ||
434 (HandleEntry->Access & Access) == 0 ||
435 /*(Type != 0 && ObjectEntry->Type != Type)*/
436 (Type != 0 && (ObjectEntry->Type & Type) == 0) )
437 {
438 DPRINT1("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",
439 Handle, Type, Access, ObjectEntry, HandleEntry, (ObjectEntry ? ObjectEntry->Type : 0), (HandleEntry ? HandleEntry->Access : 0));
440
441 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
442 return STATUS_INVALID_HANDLE;
443 }
444
445 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
446
447 // Status = ConDrvGetConsole(&ObjectConsole, ProcessData->ConsoleHandle, LockConsole);
448 // if (NT_SUCCESS(Status))
449 if (ConDrvValidateConsoleUnsafe(ObjectEntry->Console, CONSOLE_RUNNING, LockConsole))
450 {
451 _InterlockedIncrement(&ObjectEntry->Console->ReferenceCount);
452
453 /* Return the objects to the caller */
454 *Object = ObjectEntry;
455 if (Entry) *Entry = HandleEntry;
456
457 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
458 return STATUS_SUCCESS;
459 }
460 else
461 {
462 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
463 return STATUS_INVALID_HANDLE;
464 }
465 }
466
467 VOID
468 FASTCALL
469 ConSrvReleaseObject(PCONSOLE_IO_OBJECT Object,
470 BOOL IsConsoleLocked)
471 {
472 ConSrvReleaseConsole(Object->Console, IsConsoleLocked);
473 }
474
475 NTSTATUS
476 FASTCALL
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 PCONSOLE 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->ConsoleEvent,
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 FASTCALL
556 ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
557 HANDLE ConsoleHandle,
558 BOOL CreateNewHandlesTable,
559 PHANDLE pInputHandle,
560 PHANDLE pOutputHandle,
561 PHANDLE pErrorHandle)
562 {
563 NTSTATUS Status = STATUS_SUCCESS;
564 PCONSOLE Console;
565
566 /* Validate and lock the console */
567 if (!ConDrvValidateConsole(&Console,
568 ConsoleHandle,
569 CONSOLE_RUNNING, TRUE))
570 {
571 // FIXME: Find another status code
572 return STATUS_UNSUCCESSFUL;
573 }
574
575 /* Inherit the console */
576 ProcessData->ConsoleHandle = ConsoleHandle;
577
578 if (CreateNewHandlesTable)
579 {
580 /*
581 * We are about to create a new console. However when ConSrvNewProcess
582 * was called, we didn't know that we wanted to create a new console and
583 * therefore, we by default inherited the handles table from our parent
584 * process. It's only now that we notice that in fact we do not need
585 * them, because we've created a new console and thus we must use it.
586 *
587 * Therefore, free the handles table so that we can recreate
588 * a new one later on.
589 */
590 ConSrvFreeHandlesTable(ProcessData);
591
592 /* Initialize the handles table */
593 Status = ConSrvInitHandlesTable(ProcessData,
594 Console,
595 pInputHandle,
596 pOutputHandle,
597 pErrorHandle);
598 if (!NT_SUCCESS(Status))
599 {
600 DPRINT1("Failed to initialize the handles table\n");
601 ProcessData->ConsoleHandle = NULL;
602 goto Quit;
603 }
604 }
605
606 /* Duplicate the Input Event */
607 Status = NtDuplicateObject(NtCurrentProcess(),
608 Console->InputBuffer.ActiveEvent,
609 ProcessData->Process->ProcessHandle,
610 &ProcessData->ConsoleEvent,
611 EVENT_ALL_ACCESS, 0, 0);
612 if (!NT_SUCCESS(Status))
613 {
614 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
615 ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table.
616 ProcessData->ConsoleHandle = NULL;
617 goto Quit;
618 }
619
620 /* Insert the process into the processes list of the console */
621 InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
622
623 /* Add a reference count because the process is tied to the console */
624 _InterlockedIncrement(&Console->ReferenceCount);
625
626 /* Update the internal info of the terminal */
627 TermRefreshInternalInfo(Console);
628
629 Status = STATUS_SUCCESS;
630
631 Quit:
632 /* Unlock the console and return */
633 LeaveCriticalSection(&Console->Lock);
634 return Status;
635 }
636
637 VOID
638 FASTCALL
639 ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
640 {
641 PCONSOLE Console;
642
643 DPRINT("ConSrvRemoveConsole\n");
644
645 // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
646
647 /* Validate and lock the console */
648 if (ConDrvValidateConsole(&Console,
649 ProcessData->ConsoleHandle,
650 CONSOLE_RUNNING, TRUE))
651 {
652 DPRINT("ConSrvRemoveConsole - Locking OK\n");
653
654 /* Close all console handles and free the handles table */
655 ConSrvFreeHandlesTable(ProcessData);
656
657 /* Detach the process from the console */
658 ProcessData->ConsoleHandle = NULL;
659
660 /* Remove ourselves from the console's list of processes */
661 RemoveEntryList(&ProcessData->ConsoleLink);
662
663 /* Update the internal info of the terminal */
664 TermRefreshInternalInfo(Console);
665
666 /* Release the console */
667 DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount);
668 ConDrvReleaseConsole(Console, TRUE);
669 //CloseHandle(ProcessData->ConsoleEvent);
670 //ProcessData->ConsoleEvent = NULL;
671 }
672
673 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
674 }
675
676
677 /* PUBLIC SERVER APIS *********************************************************/
678
679 CSR_API(SrvOpenConsole)
680 {
681 /*
682 * This API opens a handle to either the input buffer or to
683 * a screen-buffer of the console of the current process.
684 */
685
686 NTSTATUS Status;
687 PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
688 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
689 PCONSOLE Console;
690
691 DWORD DesiredAccess = OpenConsoleRequest->Access;
692 DWORD ShareMode = OpenConsoleRequest->ShareMode;
693 PCONSOLE_IO_OBJECT Object;
694
695 OpenConsoleRequest->ConsoleHandle = INVALID_HANDLE_VALUE;
696
697 Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
698 if (!NT_SUCCESS(Status))
699 {
700 DPRINT1("Can't get console\n");
701 return Status;
702 }
703
704 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
705
706 /*
707 * Open a handle to either the active screen buffer or the input buffer.
708 */
709 if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
710 {
711 Object = &Console->ActiveBuffer->Header;
712 }
713 else // HANDLE_INPUT
714 {
715 Object = &Console->InputBuffer.Header;
716 }
717
718 if (((DesiredAccess & GENERIC_READ) && Object->ExclusiveRead != 0) ||
719 ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) ||
720 (!(ShareMode & FILE_SHARE_READ) && Object->AccessRead != 0) ||
721 (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite != 0))
722 {
723 DPRINT1("Sharing violation\n");
724 Status = STATUS_SHARING_VIOLATION;
725 }
726 else
727 {
728 Status = ConSrvInsertObject(ProcessData,
729 &OpenConsoleRequest->ConsoleHandle,
730 Object,
731 DesiredAccess,
732 OpenConsoleRequest->Inheritable,
733 ShareMode);
734 }
735
736 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
737
738 ConSrvReleaseConsole(Console, TRUE);
739 return Status;
740 }
741
742 CSR_API(SrvDuplicateHandle)
743 {
744 NTSTATUS Status;
745 PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
746 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
747 PCONSOLE Console;
748
749 HANDLE ConsoleHandle = DuplicateHandleRequest->ConsoleHandle;
750 ULONG Index = HandleToULong(ConsoleHandle) >> 2;
751 PCONSOLE_IO_HANDLE Entry;
752 DWORD DesiredAccess;
753
754 Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
755 if (!NT_SUCCESS(Status))
756 {
757 DPRINT1("Can't get console\n");
758 return Status;
759 }
760
761 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
762
763 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
764 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
765
766 if ( /** !IsConsoleHandle(ConsoleHandle) || **/
767 Index >= ProcessData->HandleTableSize ||
768 (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
769 {
770 DPRINT1("Couldn't duplicate invalid handle %p\n", ConsoleHandle);
771 Status = STATUS_INVALID_HANDLE;
772 goto Quit;
773 }
774
775 if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
776 {
777 DesiredAccess = Entry->Access;
778 }
779 else
780 {
781 DesiredAccess = DuplicateHandleRequest->Access;
782 /* Make sure the source handle has all the desired flags */
783 if ((Entry->Access & DesiredAccess) == 0)
784 {
785 DPRINT1("Handle %p only has access %X; requested %X\n",
786 ConsoleHandle, Entry->Access, DesiredAccess);
787 Status = STATUS_INVALID_PARAMETER;
788 goto Quit;
789 }
790 }
791
792 /* Insert the new handle inside the process handles table */
793 Status = ConSrvInsertObject(ProcessData,
794 &DuplicateHandleRequest->ConsoleHandle, // Use the new handle value!
795 Entry->Object,
796 DesiredAccess,
797 DuplicateHandleRequest->Inheritable,
798 Entry->ShareMode);
799 if (NT_SUCCESS(Status) &&
800 (DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE))
801 {
802 /* Close the original handle if needed */
803 ConSrvCloseHandleEntry(Entry);
804 }
805
806 Quit:
807 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
808
809 ConSrvReleaseConsole(Console, TRUE);
810 return Status;
811 }
812
813 CSR_API(SrvGetHandleInformation)
814 {
815 DPRINT1("%s not yet implemented\n", __FUNCTION__);
816 return STATUS_NOT_IMPLEMENTED;
817 }
818
819 CSR_API(SrvSetHandleInformation)
820 {
821 DPRINT1("%s not yet implemented\n", __FUNCTION__);
822 return STATUS_NOT_IMPLEMENTED;
823 }
824
825 CSR_API(SrvCloseHandle)
826 {
827 NTSTATUS Status;
828 PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
829 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
830 PCONSOLE Console;
831
832 Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
833 if (!NT_SUCCESS(Status))
834 {
835 DPRINT1("Can't get console\n");
836 return Status;
837 }
838
839 Status = ConSrvRemoveObject(ProcessData, CloseHandleRequest->ConsoleHandle);
840
841 ConSrvReleaseConsole(Console, TRUE);
842 return Status;
843 }
844
845 CSR_API(SrvVerifyConsoleIoHandle)
846 {
847 NTSTATUS Status;
848 PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
849 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
850 PCONSOLE Console;
851
852 HANDLE ConsoleHandle = VerifyHandleRequest->ConsoleHandle;
853 ULONG Index = HandleToULong(ConsoleHandle) >> 2;
854
855 Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
856 if (!NT_SUCCESS(Status))
857 {
858 DPRINT1("Can't get console\n");
859 return Status;
860 }
861
862 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
863
864 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) ||
865 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) );
866
867 if (!IsConsoleHandle(ConsoleHandle) ||
868 Index >= ProcessData->HandleTableSize ||
869 ProcessData->HandleTable[Index].Object == NULL)
870 {
871 DPRINT("SrvVerifyConsoleIoHandle failed\n");
872 Status = STATUS_INVALID_HANDLE;
873 }
874
875 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
876
877 ConSrvReleaseConsole(Console, TRUE);
878 return Status;
879 }
880
881 /* EOF */