|
|
1.1 ! root 1: /****************************** Module Header ******************************\ ! 2: * Module Name: session.c ! 3: * ! 4: * Copyright (c) 1991, Microsoft Corporation ! 5: * ! 6: * Remote shell session module ! 7: * ! 8: * History: ! 9: * 06-28-92 Davidc Created. ! 10: \***************************************************************************/ ! 11: ! 12: #include "rcmdsrv.h" ! 13: ! 14: #include <io.h> ! 15: ! 16: // ! 17: // Global pointer to generate console ctrl event fn ! 18: // Dynamically link to this api so exe will run ! 19: // on pre build-304 systems. ! 20: // ! 21: ! 22: typedef BOOL (APIENTRY * GENERATE_CONSOLE_CTRL_EVENT_FN)(DWORD dwCtrlEvent, ! 23: DWORD dwProcessGroupId); ! 24: ! 25: static GENERATE_CONSOLE_CTRL_EVENT_FN GenerateConsoleCtrlEventfn = NULL; ! 26: ! 27: #define GENERATE_CONSOLE_CTRL_EVENT_MODULE TEXT("kernel32.dll") ! 28: #define GENERATE_CONSOLE_CTRL_EVENT_NAME "GenerateConsoleCtrlEvent" ! 29: ! 30: // ! 31: // Define standard handles ! 32: // ! 33: ! 34: #define STDIN 0 ! 35: #define STDOUT 1 ! 36: #define STDERROR 2 ! 37: ! 38: // ! 39: // Define shell command line ! 40: // ! 41: ! 42: #define SHELL_COMMAND_LINE TEXT("cmd /q") ! 43: ! 44: // ! 45: // Define buffer size for reads/writes to/from shell ! 46: // ! 47: ! 48: #define SHELL_BUFFER_SIZE 1000 ! 49: ! 50: ! 51: // ! 52: // Define the structure used to describe each session ! 53: // ! 54: ! 55: typedef struct { ! 56: ! 57: // ! 58: // These fields are filled in at session creation time ! 59: // ! 60: ! 61: HANDLE ShellReadPipeHandle; // Handle to shell stdout pipe ! 62: HANDLE ShellWritePipeHandle; // Handle to shell stdin pipe ! 63: HANDLE ShellProcessHandle; // Handle to shell process ! 64: ! 65: // ! 66: // These fields maintain the state of asynchronouse reads/writes ! 67: // to the shell process across client disconnections. They ! 68: // are initialized at session creation. ! 69: // ! 70: ! 71: BYTE ShellReadBuffer[SHELL_BUFFER_SIZE]; // Data for shell reads goes here ! 72: HANDLE ShellReadAsyncHandle; // Object used for async reads from shell ! 73: BOOL ShellReadPending; ! 74: ! 75: BYTE ShellWriteBuffer[SHELL_BUFFER_SIZE]; // Data for shell writes goes here ! 76: HANDLE ShellWriteAsyncHandle; // Object used for async writes to shell ! 77: BOOL ShellWritePending; ! 78: ! 79: // ! 80: // These fields are filled in at session connect time and are only ! 81: // valid when the session is connected ! 82: // ! 83: ! 84: HANDLE ClientPipeHandle; // Handle to client pipe ! 85: HANDLE SessionThreadHandle; // Handle to session thread ! 86: HANDLE SessionThreadSignalEventHandle; // Handle to event used to signal thread ! 87: ! 88: ! 89: } SESSION_DATA, *PSESSION_DATA; ! 90: ! 91: ! 92: ! 93: ! 94: // ! 95: // Private prototypes ! 96: // ! 97: ! 98: HANDLE ! 99: StartShell( ! 100: int StdinCrtHandle, ! 101: int StdoutCrtHandle ! 102: ); ! 103: ! 104: DWORD ! 105: SessionThreadFn( ! 106: LPVOID Parameter ! 107: ); ! 108: ! 109: ! 110: // ! 111: // Useful macros ! 112: // ! 113: ! 114: #define SESSION_CONNECTED(Session) ((Session)->ClientPipeHandle != NULL) ! 115: ! 116: ! 117: ! 118: ! 119: ///////////////////////////////////////////////////////////////////////////// ! 120: // ! 121: // CreateSession ! 122: // ! 123: // Creates a new session. Involves creating the shell process and establishing ! 124: // pipes for communication with it. ! 125: // ! 126: // Returns a handle to the session or NULL on failure. ! 127: // ! 128: ///////////////////////////////////////////////////////////////////////////// ! 129: ! 130: HANDLE ! 131: CreateSession( ! 132: VOID ! 133: ) ! 134: { ! 135: PSESSION_DATA Session = NULL; ! 136: BOOL Result; ! 137: SECURITY_ATTRIBUTES SecurityAttributes; ! 138: HANDLE ShellStdinPipe = NULL; ! 139: HANDLE ShellStdoutPipe = NULL; ! 140: int ShellStdinCrtHandle; ! 141: int ShellStdoutCrtHandle; ! 142: ! 143: // ! 144: // Allocate space for the session data ! 145: // ! 146: ! 147: Session = (PSESSION_DATA)Alloc(sizeof(SESSION_DATA)); ! 148: if (Session == NULL) { ! 149: return(NULL); ! 150: } ! 151: ! 152: // ! 153: // Reset fields in preparation for failure ! 154: // ! 155: ! 156: Session->ShellReadPipeHandle = NULL; ! 157: Session->ShellWritePipeHandle = NULL; ! 158: Session->ShellReadAsyncHandle = NULL; ! 159: Session->ShellWriteAsyncHandle = NULL; ! 160: ! 161: ! 162: // ! 163: // Create the I/O pipes for the shell ! 164: // ! 165: ! 166: SecurityAttributes.nLength = sizeof(SecurityAttributes); ! 167: SecurityAttributes.lpSecurityDescriptor = NULL; // Use default ACL ! 168: SecurityAttributes.bInheritHandle = TRUE; // Shell will inherit handles ! 169: ! 170: Result = MyCreatePipe(&Session->ShellReadPipeHandle, ! 171: &ShellStdoutPipe, ! 172: &SecurityAttributes, ! 173: 0, // Default pipe size ! 174: 0, // Default timeout ! 175: FILE_FLAG_OVERLAPPED, // shell read flags ! 176: 0 // shell stdout flags ! 177: ); ! 178: if (!Result) { ! 179: DbgPrint("Failed to create shell stdout pipe, error = %d\n", GetLastError()); ! 180: goto Failure; ! 181: } ! 182: ! 183: Result = MyCreatePipe(&ShellStdinPipe, ! 184: &Session->ShellWritePipeHandle, ! 185: &SecurityAttributes, ! 186: 0, // Default pipe size ! 187: 0, // Default timeout ! 188: 0, // shell stdin flags ! 189: FILE_FLAG_OVERLAPPED // shell write flags ! 190: ); ! 191: if (!Result) { ! 192: DbgPrint("Failed to create shell stdin pipe, error = %d\n", GetLastError()); ! 193: goto Failure; ! 194: } ! 195: ! 196: ! 197: // ! 198: // Initialize async objects ! 199: // ! 200: ! 201: Session->ShellReadAsyncHandle = CreateAsync(FALSE); ! 202: if (Session->ShellReadAsyncHandle == NULL) { ! 203: DbgPrint("Failed to create shell read async object, error = %d\n", GetLastError()); ! 204: goto Failure; ! 205: } ! 206: ! 207: Session->ShellWriteAsyncHandle = CreateAsync(FALSE); ! 208: if (Session->ShellWriteAsyncHandle == NULL) { ! 209: DbgPrint("Failed to create shell write async object, error = %d\n", GetLastError()); ! 210: goto Failure; ! 211: } ! 212: ! 213: Session->ShellReadPending = FALSE; ! 214: Session->ShellWritePending = FALSE; ! 215: ! 216: ! 217: // ! 218: // Create a runtime handle for shell pipes ! 219: // ! 220: ! 221: ShellStdinCrtHandle = _open_osfhandle((long)ShellStdinPipe, 0); ! 222: assert(ShellStdinCrtHandle != -1); ! 223: ShellStdoutCrtHandle = _open_osfhandle((long)ShellStdoutPipe, 0); ! 224: assert(ShellStdoutCrtHandle != -1); ! 225: ! 226: ! 227: // ! 228: // Start the shell ! 229: // ! 230: ! 231: Session->ShellProcessHandle = StartShell(ShellStdinCrtHandle, ShellStdoutCrtHandle); ! 232: ! 233: // ! 234: // We're finished with our copy of the shell pipe handles ! 235: // Closing the runtime handles will close the pipe handles for us. ! 236: // ! 237: ! 238: close(ShellStdinCrtHandle); ! 239: ShellStdinPipe = NULL; ! 240: close(ShellStdoutCrtHandle); ! 241: ShellStdoutPipe = NULL; ! 242: ! 243: // ! 244: // Check result of shell start ! 245: // ! 246: ! 247: if (Session->ShellProcessHandle == NULL) { ! 248: DbgPrint("Failed to execute shell\n"); ! 249: goto Failure; ! 250: } ! 251: ! 252: ! 253: // ! 254: // Get the address of the GenerateConsoleCtrlEvent function ! 255: // if it's available ! 256: // ! 257: ! 258: if (GenerateConsoleCtrlEventfn == NULL) { ! 259: ! 260: HANDLE hMod = LoadLibrary(GENERATE_CONSOLE_CTRL_EVENT_MODULE); ! 261: ! 262: if (hMod != NULL) { ! 263: ! 264: GenerateConsoleCtrlEventfn = (GENERATE_CONSOLE_CTRL_EVENT_FN) ! 265: GetProcAddress(hMod, GENERATE_CONSOLE_CTRL_EVENT_NAME); ! 266: ! 267: if (GenerateConsoleCtrlEventfn == NULL) { ! 268: DbgPrint("Failed to get address of %s function\n", GENERATE_CONSOLE_CTRL_EVENT_NAME); ! 269: } ! 270: ! 271: FreeLibrary(hMod); ! 272: ! 273: } else { ! 274: DbgPrint("Load library failed on kernel32.dll!, error = %d\n", GetLastError()); ! 275: } ! 276: } ! 277: ! 278: ! 279: // ! 280: // If any code is added here, remember to cleanup process handle ! 281: // in failure code ! 282: // ! 283: ! 284: ! 285: // ! 286: // The session is not connected, initialize variables to indicate that ! 287: // ! 288: ! 289: Session->ClientPipeHandle = NULL; ! 290: ! 291: ! 292: // ! 293: // Success, return the session pointer as a handle ! 294: // ! 295: ! 296: return((HANDLE)Session); ! 297: ! 298: ! 299: ! 300: Failure: ! 301: ! 302: // ! 303: // We get here for any failure case. ! 304: // Free up any resources and exit ! 305: // ! 306: ! 307: ! 308: // ! 309: // Cleanup shell pipe handles ! 310: // ! 311: ! 312: if (ShellStdinPipe != NULL) { ! 313: MyCloseHandle(ShellStdinPipe, "shell stdin pipe (shell side)"); ! 314: } ! 315: ! 316: if (ShellStdoutPipe != NULL) { ! 317: MyCloseHandle(ShellStdoutPipe, "shell stdout pipe (shell side)"); ! 318: } ! 319: ! 320: if (Session->ShellReadPipeHandle != NULL) { ! 321: MyCloseHandle(Session->ShellReadPipeHandle, "shell read pipe (session side)"); ! 322: } ! 323: ! 324: if (Session->ShellWritePipeHandle != NULL) { ! 325: MyCloseHandle(Session->ShellWritePipeHandle, "shell write pipe (session side)"); ! 326: } ! 327: ! 328: ! 329: // ! 330: // Cleanup async data ! 331: // ! 332: ! 333: if (Session->ShellReadAsyncHandle != NULL) { ! 334: DeleteAsync(Session->ShellReadAsyncHandle); ! 335: } ! 336: ! 337: if (Session->ShellWriteAsyncHandle != NULL) { ! 338: DeleteAsync(Session->ShellWriteAsyncHandle); ! 339: } ! 340: ! 341: ! 342: // ! 343: // Free up our session data ! 344: // ! 345: ! 346: Free(Session); ! 347: ! 348: return(NULL); ! 349: } ! 350: ! 351: ! 352: ! 353: ! 354: ///////////////////////////////////////////////////////////////////////////// ! 355: // ! 356: // DeleteSession ! 357: // ! 358: // Deletes the session specified by SessionHandle. ! 359: // ! 360: // Returns nothing ! 361: // ! 362: ///////////////////////////////////////////////////////////////////////////// ! 363: ! 364: VOID ! 365: DeleteSession( ! 366: HANDLE SessionHandle ! 367: ) ! 368: { ! 369: PSESSION_DATA Session = (PSESSION_DATA)SessionHandle; ! 370: BOOL Result; ! 371: ! 372: // ! 373: // Disconnect session first ! 374: // ! 375: ! 376: if (SESSION_CONNECTED(Session)) { ! 377: DisconnectSession(SessionHandle); ! 378: } ! 379: ! 380: ! 381: // ! 382: // Kill off the shell process ! 383: // ! 384: ! 385: Result = TerminateProcess(Session->ShellProcessHandle, 1); ! 386: if (!Result) { ! 387: DbgPrint("Failed to terminate shell, error = %d\n", GetLastError()); ! 388: } ! 389: ! 390: MyCloseHandle(Session->ShellProcessHandle, "shell process"); ! 391: ! 392: ! 393: // ! 394: // Close the shell pipe handles ! 395: // ! 396: ! 397: MyCloseHandle(Session->ShellReadPipeHandle, "shell read pipe (session side)"); ! 398: MyCloseHandle(Session->ShellWritePipeHandle, "shell write pipe (session side)"); ! 399: ! 400: ! 401: // ! 402: // Cleanup async data ! 403: // ! 404: ! 405: DeleteAsync(Session->ShellReadAsyncHandle); ! 406: DeleteAsync(Session->ShellWriteAsyncHandle); ! 407: ! 408: ! 409: // ! 410: // Free up the session structure ! 411: // ! 412: ! 413: Free(Session); ! 414: ! 415: // ! 416: // We're done ! 417: // ! 418: ! 419: return; ! 420: } ! 421: ! 422: ! 423: ! 424: ! 425: ///////////////////////////////////////////////////////////////////////////// ! 426: // ! 427: // ConnectSession ! 428: // ! 429: // Connects the session specified by SessionHandle to a client ! 430: // on the other end of the pipe specified by PipeHandle ! 431: // ! 432: // Returns a session disconnect notification handle or NULL on failure. ! 433: // The returned handle will be signalled if the client disconnects or the ! 434: // shell terminates. ! 435: // Calling DisconnectSession will return the disconnect notification code. ! 436: // ! 437: ///////////////////////////////////////////////////////////////////////////// ! 438: ! 439: HANDLE ! 440: ConnectSession( ! 441: HANDLE SessionHandle, ! 442: HANDLE ClientPipeHandle ! 443: ) ! 444: { ! 445: PSESSION_DATA Session = (PSESSION_DATA)SessionHandle; ! 446: SECURITY_ATTRIBUTES SecurityAttributes; ! 447: DWORD ThreadId; ! 448: ! 449: assert(ClientPipeHandle != NULL); ! 450: ! 451: // ! 452: // Fail if the session is already connected ! 453: // ! 454: ! 455: if (SESSION_CONNECTED(Session)) { ! 456: DbgPrint("Attempted to connect session already connected\n"); ! 457: return(NULL); ! 458: } ! 459: ! 460: // ! 461: // Create the thread signal event. We'll use this to tell the ! 462: // thread to exit during disconnection. ! 463: // ! 464: ! 465: SecurityAttributes.nLength = sizeof(SecurityAttributes); ! 466: SecurityAttributes.lpSecurityDescriptor = NULL; // Use default ACL ! 467: SecurityAttributes.bInheritHandle = FALSE; // No inheritance ! 468: ! 469: Session->SessionThreadSignalEventHandle = CreateEvent(&SecurityAttributes, ! 470: TRUE, // Manual reset ! 471: FALSE, // Initially clear ! 472: NULL); // No name ! 473: if (Session->SessionThreadSignalEventHandle == NULL) { ! 474: DbgPrint("Failed to create thread signal event, error = %d\n", GetLastError()); ! 475: return(NULL); ! 476: } ! 477: ! 478: ! 479: // ! 480: // Store the client pipe handle in the session structure so the thread ! 481: // can get at it. This also signals that the session is connected. ! 482: // ! 483: ! 484: Session->ClientPipeHandle = ClientPipeHandle; ! 485: ! 486: ! 487: // ! 488: // Create the session thread ! 489: // ! 490: ! 491: Session->SessionThreadHandle = CreateThread( ! 492: &SecurityAttributes, ! 493: 0, // Default stack size ! 494: (LPTHREAD_START_ROUTINE)SessionThreadFn, // Start address ! 495: (LPVOID)Session, // Parameter ! 496: 0, // Creation flags ! 497: &ThreadId // Thread id ! 498: ); ! 499: if (Session->SessionThreadHandle == NULL) { ! 500: ! 501: DbgPrint("Failed to create session thread, error = %d\n", GetLastError()); ! 502: ! 503: // ! 504: // Close the thread signal event ! 505: // ! 506: ! 507: MyCloseHandle(Session->SessionThreadSignalEventHandle, "thread signal event"); ! 508: ! 509: // ! 510: // Reset the client pipe handle to indicate this session is disconnected ! 511: // ! 512: ! 513: Session->ClientPipeHandle = NULL; ! 514: } ! 515: ! 516: ! 517: return(Session->SessionThreadHandle); ! 518: } ! 519: ! 520: ! 521: ! 522: ! 523: ///////////////////////////////////////////////////////////////////////////// ! 524: // ! 525: // DisconnectSession ! 526: // ! 527: // Disconnects the session specified by SessionHandle for its client. ! 528: // ! 529: // Returns a disconnect notification code (DisconnectError on failure) ! 530: // ! 531: ///////////////////////////////////////////////////////////////////////////// ! 532: ! 533: SESSION_DISCONNECT_CODE ! 534: DisconnectSession( ! 535: HANDLE SessionHandle ! 536: ) ! 537: { ! 538: PSESSION_DATA Session = (PSESSION_DATA)SessionHandle; ! 539: DWORD TerminationCode; ! 540: SESSION_DISCONNECT_CODE DisconnectCode; ! 541: BOOL Result; ! 542: DWORD WaitResult; ! 543: ! 544: // ! 545: // Signal the thread to terminate (if it hasn't already) ! 546: // ! 547: ! 548: Result = SetEvent(Session->SessionThreadSignalEventHandle); ! 549: if (!Result) { ! 550: DbgPrint("Failed to set thread signal event, error = %d\n", GetLastError()); ! 551: } ! 552: ! 553: // ! 554: // Wait for the thread to terminate ! 555: // ! 556: ! 557: DbgPrint("Waiting for session thread to terminate..."); ! 558: ! 559: WaitResult = WaitForSingleObject(Session->SessionThreadHandle, INFINITE); ! 560: if (WaitResult != 0) { ! 561: DbgPrint("Unexpected result from infinite wait on thread handle, result = %d\n", WaitResult); ! 562: } ! 563: ! 564: DbgPrint("done\n"); ! 565: ! 566: ! 567: // ! 568: // Get the thread termination code ! 569: // ! 570: ! 571: Result = GetExitCodeThread(Session->SessionThreadHandle, &TerminationCode); ! 572: if (!Result) { ! 573: DbgPrint("Failed to get termination code for thread, error = %d\n", GetLastError()); ! 574: TerminationCode = (DWORD)DisconnectError; ! 575: } else { ! 576: if (TerminationCode == STILL_ACTIVE) { ! 577: DbgPrint("Got termination code for thread, it's still active!\n"); ! 578: TerminationCode = (DWORD)DisconnectError; ! 579: } ! 580: } ! 581: ! 582: DisconnectCode = (SESSION_DISCONNECT_CODE)TerminationCode; ! 583: ! 584: ! 585: ! 586: // ! 587: // Close the thread handle and thread signal event handle ! 588: // ! 589: ! 590: MyCloseHandle(Session->SessionThreadHandle, "session thread"); ! 591: MyCloseHandle(Session->SessionThreadSignalEventHandle, "thread signal event"); ! 592: ! 593: ! 594: // ! 595: // Reset the client pipe handle to signal that this session is disconnected ! 596: // The pipe handle will have been closed by the session thread on exit ! 597: // ! 598: ! 599: Session->ClientPipeHandle = NULL; ! 600: ! 601: ! 602: // ! 603: // We're done ! 604: // ! 605: ! 606: return(DisconnectCode); ! 607: } ! 608: ! 609: ! 610: ! 611: ! 612: ! 613: ! 614: ! 615: ! 616: ///////////////////////////////////////////////////////////////////////////// ! 617: // ! 618: // StartShell ! 619: // ! 620: // Execs the shell with the specified handle as stdin, stdout/err ! 621: // ! 622: // Returns process handle or NULL on failure ! 623: // ! 624: ///////////////////////////////////////////////////////////////////////////// ! 625: ! 626: HANDLE ! 627: StartShell( ! 628: int ShellStdinCrtHandle, ! 629: int ShellStdoutCrtHandle ! 630: ) ! 631: { ! 632: int StdInputHandle; ! 633: int StdOutputHandle; ! 634: int StdErrorHandle; ! 635: int crtResult; ! 636: PROCESS_INFORMATION ProcessInformation; ! 637: STARTUPINFO si; ! 638: HANDLE ProcessHandle = NULL; ! 639: ! 640: ! 641: // ! 642: // Replace std handles with appropriate pipe handles and exec the ! 643: // shell process. It will inherit our std handles and we can then ! 644: // reset them to normal ! 645: // ! 646: ! 647: ! 648: // ! 649: // Store away our normal i/o handles ! 650: // ! 651: ! 652: StdInputHandle = dup(STDIN); ! 653: assert(StdInputHandle != -1); ! 654: StdOutputHandle = dup(STDOUT); ! 655: assert(StdOutputHandle != -1); ! 656: StdErrorHandle = dup(STDERROR); ! 657: assert(StdErrorHandle != -1); ! 658: ! 659: // ! 660: // Replace std handles with pipe handle. ! 661: // ! 662: ! 663: crtResult = dup2(ShellStdinCrtHandle, STDIN); ! 664: assert(crtResult == 0); ! 665: crtResult = dup2(ShellStdoutCrtHandle, STDOUT); ! 666: assert(crtResult == 0); ! 667: crtResult = dup2(ShellStdoutCrtHandle, STDERROR); ! 668: assert(crtResult == 0); ! 669: ! 670: // ! 671: // Initialize process startup info ! 672: // ! 673: ! 674: si.cb = sizeof(STARTUPINFO); ! 675: si.lpReserved = NULL; ! 676: si.lpTitle = NULL; ! 677: si.lpDesktop = NULL; ! 678: si.dwX = si.dwY = si.dwXSize = si.dwYSize = si.dwFlags = 0L; ! 679: si.wShowWindow = SW_SHOW; ! 680: si.lpReserved2 = NULL; ! 681: si.cbReserved2 = 0; ! 682: ! 683: if (CreateProcess(NULL, ! 684: SHELL_COMMAND_LINE, ! 685: NULL, ! 686: NULL, ! 687: TRUE, // Inherit handles ! 688: 0, ! 689: NULL, ! 690: NULL, ! 691: &si, ! 692: &ProcessInformation)) { ! 693: ! 694: ProcessHandle = ProcessInformation.hProcess; ! 695: MyCloseHandle(ProcessInformation.hThread, "process thread"); ! 696: ! 697: } else { ! 698: DbgPrint("Failed to execute shell, error = %d\n", GetLastError()); ! 699: } ! 700: ! 701: ! 702: ! 703: // ! 704: // Restore std handles to normal ! 705: // ! 706: ! 707: crtResult = dup2(StdInputHandle, STDIN); ! 708: assert(crtResult == 0); ! 709: crtResult = dup2(StdOutputHandle, STDOUT); ! 710: assert(crtResult == 0); ! 711: crtResult = dup2(StdErrorHandle, STDERROR); ! 712: assert(crtResult == 0); ! 713: ! 714: // ! 715: // Close any handles we created ! 716: // ! 717: ! 718: crtResult = close(StdInputHandle); ! 719: assert(crtResult == 0); ! 720: crtResult = close(StdOutputHandle); ! 721: assert(crtResult == 0); ! 722: crtResult = close(StdErrorHandle); ! 723: assert(crtResult == 0); ! 724: ! 725: ! 726: return(ProcessHandle); ! 727: } ! 728: ! 729: ! 730: ! 731: ! 732: ! 733: ! 734: ! 735: ! 736: ///////////////////////////////////////////////////////////////////////////// ! 737: // ! 738: // SessionThreadFn ! 739: // ! 740: // This is the code executed by the session thread ! 741: // ! 742: // Waits for read or write from/to shell or client pipe and termination ! 743: // event. Handles reads or writes by passing data to either client or ! 744: // shell as appropriate. Any error or termination event being signalled ! 745: // causes the thread to exit with an appropriate exit code. ! 746: // ! 747: ///////////////////////////////////////////////////////////////////////////// ! 748: ! 749: DWORD ! 750: SessionThreadFn( ! 751: LPVOID Parameter ! 752: ) ! 753: { ! 754: PSESSION_DATA Session = (PSESSION_DATA)Parameter; ! 755: HANDLE ClientReadAsyncHandle; ! 756: HANDLE ClientWriteAsyncHandle; ! 757: DWORD BytesTransferred; ! 758: DWORD CompletionCode; ! 759: BOOL Result; ! 760: DWORD WaitResult; ! 761: DWORD ExitCode; ! 762: HANDLE WaitHandles[5]; ! 763: BOOL Done; ! 764: DWORD i; ! 765: ! 766: if (Session->ShellWritePending) { ! 767: printf("SessionThread started - SHELL-WRITE-PENDING\n"); ! 768: } ! 769: if (Session->ShellReadPending) { ! 770: printf("SessionThread started - SHELL-READ-PENDING\n"); ! 771: } ! 772: ! 773: // ! 774: // Initialize the client async structures ! 775: // ! 776: ! 777: ClientReadAsyncHandle = CreateAsync(!Session->ShellWritePending); ! 778: if (ClientReadAsyncHandle == NULL) { ! 779: DbgPrint("Failed to create client read async object, error = %d\n", GetLastError()); ! 780: return((DWORD)ConnectError); ! 781: } ! 782: ! 783: ClientWriteAsyncHandle = CreateAsync(!Session->ShellReadPending); ! 784: if (ClientWriteAsyncHandle == NULL) { ! 785: DbgPrint("Failed to create client write async object, error = %d\n", GetLastError()); ! 786: DeleteAsync(ClientReadAsyncHandle); ! 787: return((DWORD)ConnectError); ! 788: } ! 789: ! 790: ! 791: ! 792: // ! 793: // Initialize the handle array we'll wait on ! 794: // ! 795: ! 796: WaitHandles[0] = Session->SessionThreadSignalEventHandle; ! 797: WaitHandles[1] = GetAsyncCompletionHandle(Session->ShellReadAsyncHandle); ! 798: WaitHandles[2] = GetAsyncCompletionHandle(Session->ShellWriteAsyncHandle); ! 799: WaitHandles[3] = GetAsyncCompletionHandle(ClientReadAsyncHandle); ! 800: WaitHandles[4] = GetAsyncCompletionHandle(ClientWriteAsyncHandle); ! 801: ! 802: // ! 803: // Wait on our handle array in a loop until an error occurs or ! 804: // we're signalled to exit. ! 805: // ! 806: ! 807: Done = FALSE; ! 808: ! 809: while (!Done) { ! 810: ! 811: // ! 812: // Wait for one of our objects to be signalled. ! 813: // ! 814: ! 815: WaitResult = WaitForMultipleObjects(5, WaitHandles, FALSE, INFINITE); ! 816: ! 817: if (WaitResult == 0xffffffff) { ! 818: DbgPrint("Session thread wait failed, error = %d\n", GetLastError()); ! 819: ExitCode = (DWORD)ConnectError; ! 820: break; // out of while ! 821: } ! 822: ! 823: ! 824: switch (WaitResult) { ! 825: case 0: ! 826: ! 827: // ! 828: // Our thread was signalled ! 829: // ! 830: ExitCode = (DWORD)ClientDisconnected; ! 831: Done = TRUE; ! 832: break; // out of switch ! 833: ! 834: case 1: ! 835: ! 836: // ! 837: // Shell read completed ! 838: // ! 839: ! 840: Session->ShellReadPending = FALSE; ! 841: ! 842: CompletionCode = GetAsyncResult(Session->ShellReadAsyncHandle, ! 843: &BytesTransferred); ! 844: ! 845: if (CompletionCode != ERROR_SUCCESS) { ! 846: DbgPrint("Async read from shell returned error, completion code = %d\n", CompletionCode); ! 847: ExitCode = (DWORD)ShellEnded; ! 848: Done = TRUE; ! 849: break; // out of switch ! 850: } ! 851: ! 852: // ! 853: // Start an async write to client pipe ! 854: // ! 855: ! 856: Result = WriteFileAsync(Session->ClientPipeHandle, ! 857: Session->ShellReadBuffer, ! 858: BytesTransferred, ! 859: ClientWriteAsyncHandle); ! 860: if (!Result) { ! 861: DbgPrint("Async write to client pipe failed, error = %d\n", GetLastError()); ! 862: ExitCode = (DWORD)ClientDisconnected; ! 863: Done = TRUE; ! 864: } ! 865: ! 866: break; // out of switch ! 867: ! 868: ! 869: case 4: ! 870: ! 871: // ! 872: // Client write completed ! 873: // ! 874: ! 875: CompletionCode = GetAsyncResult(ClientWriteAsyncHandle, ! 876: &BytesTransferred); ! 877: ! 878: if (CompletionCode != ERROR_SUCCESS) { ! 879: DbgPrint("Async write to client returned error, completion code = %d\n", CompletionCode); ! 880: ExitCode = (DWORD)ClientDisconnected; ! 881: Done = TRUE; ! 882: break; // out of switch ! 883: } ! 884: ! 885: // ! 886: // Start an async read from shell ! 887: // ! 888: ! 889: Result = ReadFileAsync(Session->ShellReadPipeHandle, ! 890: Session->ShellReadBuffer, ! 891: sizeof(Session->ShellReadBuffer), ! 892: Session->ShellReadAsyncHandle); ! 893: if (!Result) { ! 894: DbgPrint("Async read from shell failed, error = %d\n", GetLastError()); ! 895: ExitCode = (DWORD)ShellEnded; ! 896: Done = TRUE; ! 897: } else { ! 898: Session->ShellReadPending = TRUE; ! 899: } ! 900: ! 901: break; // out of switch ! 902: ! 903: ! 904: case 3: ! 905: ! 906: // ! 907: // Client read completed ! 908: // ! 909: ! 910: CompletionCode = GetAsyncResult(ClientReadAsyncHandle, ! 911: &BytesTransferred); ! 912: ! 913: if (CompletionCode != ERROR_SUCCESS) { ! 914: DbgPrint("Async read from client returned error, completion code = %d\n", CompletionCode); ! 915: ExitCode = (DWORD)ClientDisconnected; ! 916: Done = TRUE; ! 917: break; // out of switch ! 918: } ! 919: ! 920: // ! 921: // Check for Ctrl-C from the client ! 922: // ! 923: ! 924: for (i=0; i < BytesTransferred; i++) { ! 925: if (Session->ShellWriteBuffer[i] == '\003') { ! 926: ! 927: // ! 928: // Generate a Ctrl-C if we have the technology ! 929: // ! 930: ! 931: if (GenerateConsoleCtrlEventfn != NULL) { ! 932: (*GenerateConsoleCtrlEventfn)(CTRL_C_EVENT, 0); ! 933: } ! 934: ! 935: // ! 936: // Remove the Ctrl-C from the buffer ! 937: // ! 938: ! 939: BytesTransferred --; ! 940: ! 941: for (; i < BytesTransferred; i++) { ! 942: Session->ShellWriteBuffer[i] = Session->ShellWriteBuffer[i+1]; ! 943: } ! 944: } ! 945: } ! 946: ! 947: // ! 948: // Start an async write to shell ! 949: // ! 950: ! 951: Result = WriteFileAsync(Session->ShellWritePipeHandle, ! 952: Session->ShellWriteBuffer, ! 953: BytesTransferred, ! 954: Session->ShellWriteAsyncHandle); ! 955: if (!Result) { ! 956: DbgPrint("Async write to shell failed, error = %d\n", GetLastError()); ! 957: ExitCode = (DWORD)ShellEnded; ! 958: Done = TRUE; ! 959: } else { ! 960: Session->ShellWritePending = TRUE; ! 961: } ! 962: ! 963: break; // out of switch ! 964: ! 965: ! 966: ! 967: case 2: ! 968: ! 969: // ! 970: // Shell write completed ! 971: // ! 972: ! 973: Session->ShellWritePending = FALSE; ! 974: ! 975: CompletionCode = GetAsyncResult(Session->ShellWriteAsyncHandle, ! 976: &BytesTransferred); ! 977: ! 978: if (CompletionCode != ERROR_SUCCESS) { ! 979: DbgPrint("Async write to shell returned error, completion code = %d\n", CompletionCode); ! 980: ExitCode = (DWORD)ShellEnded; ! 981: Done = TRUE; ! 982: break; // out of switch ! 983: } ! 984: ! 985: // ! 986: // Start an async read from client ! 987: // ! 988: ! 989: Result = ReadFileAsync(Session->ClientPipeHandle, ! 990: Session->ShellWriteBuffer, ! 991: sizeof(Session->ShellWriteBuffer), ! 992: ClientReadAsyncHandle); ! 993: if (!Result) { ! 994: DbgPrint("Async read from client failed, error = %d\n", GetLastError()); ! 995: ExitCode = (DWORD)ClientDisconnected; ! 996: Done = TRUE; ! 997: } ! 998: ! 999: break; // out of switch ! 1000: ! 1001: ! 1002: default: ! 1003: ! 1004: DbgPrint("Session thread, unexpected result from wait, result = %d\n", WaitResult); ! 1005: ExitCode = (DWORD)ConnectError; ! 1006: Done = TRUE; ! 1007: break; ! 1008: ! 1009: } ! 1010: } ! 1011: ! 1012: ! 1013: ! 1014: // ! 1015: // Cleanup and exit ! 1016: // ! 1017: ! 1018: // ! 1019: // Closing the client pipe should interrupt any pending I/O so ! 1020: // we should then be safe to close the event handles in the client ! 1021: // overlapped structs ! 1022: // ! 1023: ! 1024: Result = DisconnectNamedPipe(Session->ClientPipeHandle); ! 1025: if (!Result) { ! 1026: DbgPrint("Session thread: disconnect client named pipe failed, error = %d\n", GetLastError()); ! 1027: } ! 1028: ! 1029: MyCloseHandle(Session->ClientPipeHandle, "client pipe"); ! 1030: Session->ClientPipeHandle = NULL; ! 1031: ! 1032: ! 1033: DeleteAsync(ClientReadAsyncHandle); ! 1034: DeleteAsync(ClientWriteAsyncHandle); ! 1035: ! 1036: ! 1037: // ! 1038: // Return the appropriate exit code ! 1039: // ! 1040: ! 1041: ExitThread(ExitCode); ! 1042: ! 1043: assert(FALSE); ! 1044: return(ExitCode); // keep compiler happy ! 1045: } ! 1046:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.