Annotation of mstools/samples/sdktools/rshell/server/session.c, revision 1.1.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.