Annotation of mstools/samples/sdktools/rshell/server/session.c, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.