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