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