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 ConDrvDeleteScreenBuffer(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 NTSTATUS 474 ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData, 475 PHANDLE pInputHandle, 476 PHANDLE pOutputHandle, 477 PHANDLE pErrorHandle, 478 PCONSOLE_INIT_INFO ConsoleInitInfo) 479 { 480 NTSTATUS Status = STATUS_SUCCESS; 481 HANDLE ConsoleHandle; 482 PCONSRV_CONSOLE Console; 483 484 /* 485 * We are about to create a new console. However when ConSrvNewProcess 486 * was called, we didn't know that we wanted to create a new console and 487 * therefore, we by default inherited the handles table from our parent 488 * process. It's only now that we notice that in fact we do not need 489 * them, because we've created a new console and thus we must use it. 490 * 491 * Therefore, free the handles table so that we can recreate 492 * a new one later on. 493 */ 494 ConSrvFreeHandlesTable(ProcessData); 495 496 /* Initialize a new Console owned by this process */ 497 DPRINT("Initialization of console '%S' for process '%S' on desktop '%S'\n", 498 ConsoleInitInfo->ConsoleTitle ? ConsoleInitInfo->ConsoleTitle : L"n/a", 499 ConsoleInitInfo->AppName ? ConsoleInitInfo->AppName : L"n/a", 500 ConsoleInitInfo->Desktop ? ConsoleInitInfo->Desktop : L"n/a"); 501 Status = ConSrvInitConsole(&ConsoleHandle, 502 &Console, 503 ConsoleInitInfo, 504 ProcessData->Process); 505 if (!NT_SUCCESS(Status)) 506 { 507 DPRINT1("Console initialization failed\n"); 508 return Status; 509 } 510 511 /* Assign the new console handle */ 512 ProcessData->ConsoleHandle = ConsoleHandle; 513 514 /* Initialize the handles table */ 515 Status = ConSrvInitHandlesTable(ProcessData, 516 Console, 517 pInputHandle, 518 pOutputHandle, 519 pErrorHandle); 520 if (!NT_SUCCESS(Status)) 521 { 522 DPRINT1("Failed to initialize the handles table\n"); 523 ConSrvDeleteConsole(Console); 524 ProcessData->ConsoleHandle = NULL; 525 return Status; 526 } 527 528 /* Duplicate the Initialization Events */ 529 Status = NtDuplicateObject(NtCurrentProcess(), 530 Console->InitEvents[INIT_SUCCESS], 531 ProcessData->Process->ProcessHandle, 532 &ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS], 533 EVENT_ALL_ACCESS, 0, 0); 534 if (!NT_SUCCESS(Status)) 535 { 536 DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status); 537 ConSrvFreeHandlesTable(ProcessData); 538 ConSrvDeleteConsole(Console); 539 ProcessData->ConsoleHandle = NULL; 540 return Status; 541 } 542 543 Status = NtDuplicateObject(NtCurrentProcess(), 544 Console->InitEvents[INIT_FAILURE], 545 ProcessData->Process->ProcessHandle, 546 &ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_FAILURE], 547 EVENT_ALL_ACCESS, 0, 0); 548 if (!NT_SUCCESS(Status)) 549 { 550 DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status); 551 NtDuplicateObject(ProcessData->Process->ProcessHandle, 552 ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS], 553 NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); 554 ConSrvFreeHandlesTable(ProcessData); 555 ConSrvDeleteConsole(Console); 556 ProcessData->ConsoleHandle = NULL; 557 return Status; 558 } 559 560 /* Duplicate the Input Event */ 561 Status = NtDuplicateObject(NtCurrentProcess(), 562 Console->InputBuffer.ActiveEvent, 563 ProcessData->Process->ProcessHandle, 564 &ConsoleInitInfo->ConsoleStartInfo->InputWaitHandle, 565 EVENT_ALL_ACCESS, 0, 0); 566 if (!NT_SUCCESS(Status)) 567 { 568 DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status); 569 NtDuplicateObject(ProcessData->Process->ProcessHandle, 570 ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_FAILURE], 571 NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); 572 NtDuplicateObject(ProcessData->Process->ProcessHandle, 573 ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS], 574 NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); 575 ConSrvFreeHandlesTable(ProcessData); 576 ConSrvDeleteConsole(Console); 577 ProcessData->ConsoleHandle = NULL; 578 return Status; 579 } 580 581 /* Mark the process as having a console */ 582 ProcessData->ConsoleApp = TRUE; 583 ProcessData->Process->Flags |= CsrProcessIsConsoleApp; 584 585 /* Return the console handle to the caller */ 586 ConsoleInitInfo->ConsoleStartInfo->ConsoleHandle = ProcessData->ConsoleHandle; 587 588 /* 589 * Insert the process into the processes list of the console, 590 * and set its foreground priority. 591 */ 592 InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink); 593 ConSrvSetProcessFocus(ProcessData->Process, Console->HasFocus); 594 595 /* Add a reference count because the process is tied to the console */ 596 _InterlockedIncrement(&Console->ReferenceCount); 597 598 /* Update the internal info of the terminal */ 599 TermRefreshInternalInfo(Console); 600 601 return STATUS_SUCCESS; 602 } 603 604 NTSTATUS 605 ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData, 606 HANDLE ConsoleHandle, 607 BOOLEAN CreateNewHandlesTable, 608 PHANDLE pInputHandle, 609 PHANDLE pOutputHandle, 610 PHANDLE pErrorHandle, 611 PCONSOLE_START_INFO ConsoleStartInfo) 612 { 613 NTSTATUS Status = STATUS_SUCCESS; 614 PCONSOLE Console; 615 616 /* Validate and lock the console */ 617 if (!ConSrvValidateConsole(&Console, 618 ConsoleHandle, 619 CONSOLE_RUNNING, TRUE)) 620 { 621 // FIXME: Find another status code 622 return STATUS_UNSUCCESSFUL; 623 } 624 625 /* Inherit the console */ 626 ProcessData->ConsoleHandle = ConsoleHandle; 627 628 if (CreateNewHandlesTable) 629 { 630 /* 631 * We are about to create a new console. However when ConSrvNewProcess 632 * was called, we didn't know that we wanted to create a new console and 633 * therefore, we by default inherited the handles table from our parent 634 * process. It's only now that we notice that in fact we do not need 635 * them, because we've created a new console and thus we must use it. 636 * 637 * Therefore, free the handles table so that we can recreate 638 * a new one later on. 639 */ 640 ConSrvFreeHandlesTable(ProcessData); 641 642 /* Initialize the handles table */ 643 Status = ConSrvInitHandlesTable(ProcessData, 644 Console, 645 pInputHandle, 646 pOutputHandle, 647 pErrorHandle); 648 if (!NT_SUCCESS(Status)) 649 { 650 DPRINT1("Failed to initialize the handles table\n"); 651 ProcessData->ConsoleHandle = NULL; 652 goto Quit; 653 } 654 } 655 656 /* Duplicate the Initialization Events */ 657 Status = NtDuplicateObject(NtCurrentProcess(), 658 Console->InitEvents[INIT_SUCCESS], 659 ProcessData->Process->ProcessHandle, 660 &ConsoleStartInfo->InitEvents[INIT_SUCCESS], 661 EVENT_ALL_ACCESS, 0, 0); 662 if (!NT_SUCCESS(Status)) 663 { 664 DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status); 665 ConSrvFreeHandlesTable(ProcessData); 666 ProcessData->ConsoleHandle = NULL; 667 goto Quit; 668 } 669 670 Status = NtDuplicateObject(NtCurrentProcess(), 671 Console->InitEvents[INIT_FAILURE], 672 ProcessData->Process->ProcessHandle, 673 &ConsoleStartInfo->InitEvents[INIT_FAILURE], 674 EVENT_ALL_ACCESS, 0, 0); 675 if (!NT_SUCCESS(Status)) 676 { 677 DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status); 678 NtDuplicateObject(ProcessData->Process->ProcessHandle, 679 ConsoleStartInfo->InitEvents[INIT_SUCCESS], 680 NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); 681 ConSrvFreeHandlesTable(ProcessData); 682 ProcessData->ConsoleHandle = NULL; 683 goto Quit; 684 } 685 686 /* Duplicate the Input Event */ 687 Status = NtDuplicateObject(NtCurrentProcess(), 688 Console->InputBuffer.ActiveEvent, 689 ProcessData->Process->ProcessHandle, 690 &ConsoleStartInfo->InputWaitHandle, 691 EVENT_ALL_ACCESS, 0, 0); 692 if (!NT_SUCCESS(Status)) 693 { 694 DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status); 695 NtDuplicateObject(ProcessData->Process->ProcessHandle, 696 ConsoleStartInfo->InitEvents[INIT_FAILURE], 697 NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); 698 NtDuplicateObject(ProcessData->Process->ProcessHandle, 699 ConsoleStartInfo->InitEvents[INIT_SUCCESS], 700 NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); 701 ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table. 702 ProcessData->ConsoleHandle = NULL; 703 goto Quit; 704 } 705 706 /* Mark the process as having a console */ 707 ProcessData->ConsoleApp = TRUE; 708 ProcessData->Process->Flags |= CsrProcessIsConsoleApp; 709 710 /* Return the console handle to the caller */ 711 ConsoleStartInfo->ConsoleHandle = ProcessData->ConsoleHandle; 712 713 /* 714 * Insert the process into the processes list of the console, 715 * and set its foreground priority. 716 */ 717 InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink); 718 ConSrvSetProcessFocus(ProcessData->Process, Console->HasFocus); 719 720 /* Add a reference count because the process is tied to the console */ 721 _InterlockedIncrement(&Console->ReferenceCount); 722 723 /* Update the internal info of the terminal */ 724 TermRefreshInternalInfo(Console); 725 726 Status = STATUS_SUCCESS; 727 728 Quit: 729 /* Unlock the console and return */ 730 LeaveCriticalSection(&Console->Lock); 731 return Status; 732 } 733 734 NTSTATUS 735 ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData) 736 { 737 PCONSOLE Console; 738 PCONSOLE_PROCESS_DATA ConsoleLeaderProcess; 739 740 DPRINT("ConSrvRemoveConsole\n"); 741 742 /* Mark the process as not having a console anymore */ 743 ProcessData->ConsoleApp = FALSE; 744 ProcessData->Process->Flags &= ~CsrProcessIsConsoleApp; 745 746 /* Validate and lock the console */ 747 if (!ConSrvValidateConsole(&Console, 748 ProcessData->ConsoleHandle, 749 CONSOLE_RUNNING, TRUE)) 750 { 751 // FIXME: Find another status code 752 return STATUS_UNSUCCESSFUL; 753 } 754 755 DPRINT("ConSrvRemoveConsole - Locking OK\n"); 756 757 /* Retrieve the console leader process */ 758 ConsoleLeaderProcess = ConSrvGetConsoleLeaderProcess(Console); 759 760 /* Close all console handles and free the handles table */ 761 ConSrvFreeHandlesTable(ProcessData); 762 763 /* Detach the process from the console */ 764 ProcessData->ConsoleHandle = NULL; 765 766 /* Remove the process from the console's list of processes */ 767 RemoveEntryList(&ProcessData->ConsoleLink); 768 769 /* Check whether the console should send a last close notification */ 770 if (Console->NotifyLastClose) 771 { 772 /* If we are removing the process which wants the last close notification... */ 773 if (ProcessData == Console->NotifiedLastCloseProcess) 774 { 775 /* ... just reset the flag and the pointer... */ 776 Console->NotifyLastClose = FALSE; 777 Console->NotifiedLastCloseProcess = NULL; 778 } 779 /* 780 * ... otherwise, if we are removing the console leader process 781 * (that cannot be the process wanting the notification, because 782 * the previous case already dealt with it)... 783 */ 784 else if (ProcessData == ConsoleLeaderProcess) 785 { 786 /* 787 * ... reset the flag first (so that we avoid multiple notifications) 788 * and then send the last close notification. 789 */ 790 Console->NotifyLastClose = FALSE; 791 ConSrvConsoleCtrlEvent(CTRL_LAST_CLOSE_EVENT, Console->NotifiedLastCloseProcess); 792 793 /* Only now, reset the pointer */ 794 Console->NotifiedLastCloseProcess = NULL; 795 } 796 } 797 798 /* Update the internal info of the terminal */ 799 TermRefreshInternalInfo(Console); 800 801 /* Release the console */ 802 DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount); 803 ConSrvReleaseConsole(Console, TRUE); 804 805 return STATUS_SUCCESS; 806 } 807 808 809 /* PUBLIC SERVER APIS *********************************************************/ 810 811 CSR_API(SrvOpenConsole) 812 { 813 /* 814 * This API opens a handle to either the input buffer or to 815 * a screen-buffer of the console of the current process. 816 */ 817 818 NTSTATUS Status; 819 PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest; 820 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); 821 PCONSOLE Console; 822 823 DWORD DesiredAccess = OpenConsoleRequest->DesiredAccess; 824 DWORD ShareMode = OpenConsoleRequest->ShareMode; 825 PCONSOLE_IO_OBJECT Object; 826 827 OpenConsoleRequest->Handle = INVALID_HANDLE_VALUE; 828 829 Status = ConSrvGetConsole(ProcessData, &Console, TRUE); 830 if (!NT_SUCCESS(Status)) 831 { 832 DPRINT1("Can't get console, status %lx\n", Status); 833 return Status; 834 } 835 836 RtlEnterCriticalSection(&ProcessData->HandleTableLock); 837 838 /* 839 * Open a handle to either the active screen buffer or the input buffer. 840 */ 841 if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT) 842 { 843 Object = &Console->ActiveBuffer->Header; 844 } 845 else // HANDLE_INPUT 846 { 847 Object = &Console->InputBuffer.Header; 848 } 849 850 if (((DesiredAccess & GENERIC_READ) && Object->ExclusiveRead != 0) || 851 ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) || 852 (!(ShareMode & FILE_SHARE_READ) && Object->AccessRead != 0) || 853 (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite != 0)) 854 { 855 DPRINT1("Sharing violation\n"); 856 Status = STATUS_SHARING_VIOLATION; 857 } 858 else 859 { 860 Status = ConSrvInsertObject(ProcessData, 861 &OpenConsoleRequest->Handle, 862 Object, 863 DesiredAccess, 864 OpenConsoleRequest->InheritHandle, 865 ShareMode); 866 } 867 868 RtlLeaveCriticalSection(&ProcessData->HandleTableLock); 869 870 ConSrvReleaseConsole(Console, TRUE); 871 return Status; 872 } 873 874 CSR_API(SrvDuplicateHandle) 875 { 876 NTSTATUS Status; 877 PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest; 878 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); 879 PCONSOLE Console; 880 881 HANDLE SourceHandle = DuplicateHandleRequest->SourceHandle; 882 ULONG Index = HandleToULong(SourceHandle) >> 2; 883 PCONSOLE_IO_HANDLE Entry; 884 DWORD DesiredAccess; 885 886 DuplicateHandleRequest->TargetHandle = INVALID_HANDLE_VALUE; 887 888 Status = ConSrvGetConsole(ProcessData, &Console, TRUE); 889 if (!NT_SUCCESS(Status)) 890 { 891 DPRINT1("Can't get console, status %lx\n", Status); 892 return Status; 893 } 894 895 RtlEnterCriticalSection(&ProcessData->HandleTableLock); 896 897 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) || 898 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) ); 899 900 if ( /** !IsConsoleHandle(SourceHandle) || **/ 901 Index >= ProcessData->HandleTableSize || 902 (Entry = &ProcessData->HandleTable[Index])->Object == NULL) 903 { 904 DPRINT1("Couldn't duplicate invalid handle 0x%p\n", SourceHandle); 905 Status = STATUS_INVALID_HANDLE; 906 goto Quit; 907 } 908 909 if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS) 910 { 911 DesiredAccess = Entry->Access; 912 } 913 else 914 { 915 DesiredAccess = DuplicateHandleRequest->DesiredAccess; 916 /* Make sure the source handle has all the desired flags */ 917 if ((Entry->Access & DesiredAccess) == 0) 918 { 919 DPRINT1("Handle 0x%p only has access %X; requested %X\n", 920 SourceHandle, Entry->Access, DesiredAccess); 921 Status = STATUS_INVALID_PARAMETER; 922 goto Quit; 923 } 924 } 925 926 /* Insert the new handle inside the process handles table */ 927 Status = ConSrvInsertObject(ProcessData, 928 &DuplicateHandleRequest->TargetHandle, 929 Entry->Object, 930 DesiredAccess, 931 DuplicateHandleRequest->InheritHandle, 932 Entry->ShareMode); 933 if (NT_SUCCESS(Status) && 934 (DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE)) 935 { 936 /* Close the original handle if needed */ 937 ConSrvCloseHandle(Entry); 938 } 939 940 Quit: 941 RtlLeaveCriticalSection(&ProcessData->HandleTableLock); 942 943 ConSrvReleaseConsole(Console, TRUE); 944 return Status; 945 } 946 947 CSR_API(SrvGetHandleInformation) 948 { 949 NTSTATUS Status; 950 PCONSOLE_GETHANDLEINFO GetHandleInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetHandleInfoRequest; 951 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); 952 PCONSOLE Console; 953 954 HANDLE Handle = GetHandleInfoRequest->Handle; 955 ULONG Index = HandleToULong(Handle) >> 2; 956 PCONSOLE_IO_HANDLE Entry; 957 958 Status = ConSrvGetConsole(ProcessData, &Console, TRUE); 959 if (!NT_SUCCESS(Status)) 960 { 961 DPRINT1("Can't get console, status %lx\n", Status); 962 return Status; 963 } 964 965 RtlEnterCriticalSection(&ProcessData->HandleTableLock); 966 967 ASSERT(ProcessData->HandleTable); 968 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) || 969 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) ); 970 971 if (!IsConsoleHandle(Handle) || 972 Index >= ProcessData->HandleTableSize || 973 (Entry = &ProcessData->HandleTable[Index])->Object == NULL) 974 { 975 Status = STATUS_INVALID_HANDLE; 976 goto Quit; 977 } 978 979 /* 980 * Retrieve the handle information flags. The console server 981 * doesn't support HANDLE_FLAG_PROTECT_FROM_CLOSE. 982 */ 983 GetHandleInfoRequest->Flags = 0; 984 if (Entry->Inheritable) GetHandleInfoRequest->Flags |= HANDLE_FLAG_INHERIT; 985 986 Status = STATUS_SUCCESS; 987 988 Quit: 989 RtlLeaveCriticalSection(&ProcessData->HandleTableLock); 990 991 ConSrvReleaseConsole(Console, TRUE); 992 return Status; 993 } 994 995 CSR_API(SrvSetHandleInformation) 996 { 997 NTSTATUS Status; 998 PCONSOLE_SETHANDLEINFO SetHandleInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetHandleInfoRequest; 999 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); 1000 PCONSOLE Console; 1001 1002 HANDLE Handle = SetHandleInfoRequest->Handle; 1003 ULONG Index = HandleToULong(Handle) >> 2; 1004 PCONSOLE_IO_HANDLE Entry; 1005 1006 Status = ConSrvGetConsole(ProcessData, &Console, TRUE); 1007 if (!NT_SUCCESS(Status)) 1008 { 1009 DPRINT1("Can't get console, status %lx\n", Status); 1010 return Status; 1011 } 1012 1013 RtlEnterCriticalSection(&ProcessData->HandleTableLock); 1014 1015 ASSERT(ProcessData->HandleTable); 1016 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) || 1017 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) ); 1018 1019 if (!IsConsoleHandle(Handle) || 1020 Index >= ProcessData->HandleTableSize || 1021 (Entry = &ProcessData->HandleTable[Index])->Object == NULL) 1022 { 1023 Status = STATUS_INVALID_HANDLE; 1024 goto Quit; 1025 } 1026 1027 /* 1028 * Modify the handle information flags. The console server 1029 * doesn't support HANDLE_FLAG_PROTECT_FROM_CLOSE. 1030 */ 1031 if (SetHandleInfoRequest->Mask & HANDLE_FLAG_INHERIT) 1032 { 1033 Entry->Inheritable = ((SetHandleInfoRequest->Flags & HANDLE_FLAG_INHERIT) != 0); 1034 } 1035 1036 Status = STATUS_SUCCESS; 1037 1038 Quit: 1039 RtlLeaveCriticalSection(&ProcessData->HandleTableLock); 1040 1041 ConSrvReleaseConsole(Console, TRUE); 1042 return Status; 1043 } 1044 1045 CSR_API(SrvCloseHandle) 1046 { 1047 NTSTATUS Status; 1048 PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest; 1049 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); 1050 PCONSOLE Console; 1051 1052 Status = ConSrvGetConsole(ProcessData, &Console, TRUE); 1053 if (!NT_SUCCESS(Status)) 1054 { 1055 DPRINT1("Can't get console, status %lx\n", Status); 1056 return Status; 1057 } 1058 1059 Status = ConSrvRemoveObject(ProcessData, CloseHandleRequest->Handle); 1060 1061 ConSrvReleaseConsole(Console, TRUE); 1062 return Status; 1063 } 1064 1065 CSR_API(SrvVerifyConsoleIoHandle) 1066 { 1067 NTSTATUS Status; 1068 PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest; 1069 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); 1070 PCONSOLE Console; 1071 1072 HANDLE IoHandle = VerifyHandleRequest->Handle; 1073 ULONG Index = HandleToULong(IoHandle) >> 2; 1074 1075 VerifyHandleRequest->IsValid = FALSE; 1076 1077 Status = ConSrvGetConsole(ProcessData, &Console, TRUE); 1078 if (!NT_SUCCESS(Status)) 1079 { 1080 DPRINT1("Can't get console, status %lx\n", Status); 1081 return Status; 1082 } 1083 1084 RtlEnterCriticalSection(&ProcessData->HandleTableLock); 1085 1086 // ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) || 1087 // (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) ); 1088 1089 if (!IsConsoleHandle(IoHandle) || 1090 Index >= ProcessData->HandleTableSize || 1091 ProcessData->HandleTable[Index].Object == NULL) 1092 { 1093 DPRINT("SrvVerifyConsoleIoHandle failed\n"); 1094 } 1095 else 1096 { 1097 VerifyHandleRequest->IsValid = TRUE; 1098 } 1099 1100 RtlLeaveCriticalSection(&ProcessData->HandleTableLock); 1101 1102 ConSrvReleaseConsole(Console, TRUE); 1103 return STATUS_SUCCESS; 1104 } 1105 1106 /* EOF */ 1107