Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1171 lines
27 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: rcmd.c
  3. *
  4. * Copyright (c) 1991, Microsoft Corporation
  5. *
  6. * Remote shell NT client main module
  7. *
  8. * History:
  9. * 05-20-92 Davidc Created.
  10. * 05-01-94 DaveTh Modified for remote command service (single cmd mode)
  11. \***************************************************************************/
  12. // #define UNICODE // BUGBUG - Unicode support not complete
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <windef.h>
  16. #include <nturtl.h>
  17. #include <windows.h>
  18. #include <stdio.h>
  19. #include <stdarg.h>
  20. #include <stdlib.h>
  21. #include <assert.h>
  22. #include <conio.h>
  23. #include <rcmd.h>
  24. #define PIPE_NAME TEXT("%hs\\pipe\\rcmdsvc")
  25. #define BUFFER_SIZE 1000
  26. #define MAX_SERVER_NAME_LENGTH 15
  27. //
  28. // Globals
  29. //
  30. HANDLE PipeHandle = NULL; // These are used by Ctrl-C handler
  31. BOOLEAN SessionConnected = FALSE;
  32. BOOLEAN MultiServerMode = FALSE;
  33. HANDLE ReadThreadHandle;
  34. HANDLE WriteThreadHandle;
  35. BOOLEAN RcDbgPrintEnable = FALSE; // If TRUE, enables DbgPrint
  36. LPTSTR ServerName = NULL; // Name of remote server, for messages
  37. //
  38. // Private prototypes
  39. //
  40. DWORD
  41. ReadThreadProc(
  42. LPVOID Parameter
  43. );
  44. DWORD
  45. WriteThreadProc(
  46. LPVOID Parameter
  47. );
  48. BOOL
  49. CtrlHandler(
  50. DWORD CtrlType
  51. );
  52. int RcPrintf (
  53. const char *format,
  54. ...
  55. );
  56. int RcDbgPrint (
  57. const char *format,
  58. ...
  59. );
  60. void Usage(
  61. void
  62. );
  63. long ParseCommandLine(
  64. LPTSTR lpszServer,
  65. COMMAND_HEADER *chCommandHeader,
  66. LPTSTR *aszArgv,
  67. int iArgc
  68. );
  69. void
  70. Usage(
  71. void
  72. )
  73. /*++
  74. Routine Description:
  75. Prints a usage message and exits the program
  76. Arguments:
  77. None
  78. Return Value:
  79. void
  80. --*/
  81. {
  82. RcPrintf("\nUsage: rcmd [server_name [command] ]\n\n");
  83. RcPrintf("Prompts for server_name if not supplied. Session is\n");
  84. RcPrintf("interactive and is terminated by ctrl-Break or Exit of\n");
  85. RcPrintf("remote shell. Program is terminated by ctrl-Break or\n");
  86. RcPrintf("ctrl-C when no session is in progress.\n\n");
  87. RcPrintf("If no command supplied, session is interactive and is\n");
  88. RcPrintf("terminated by ctrl-Break or Exit of remote cmd shell\n\n");
  89. RcPrintf("If command is supplied, remote shell executes single\n");
  90. RcPrintf("command on specified server and exits.\n\n");
  91. RcPrintf("Note : Command line server_name requires leading '\\\\'s\n");
  92. exit(0);
  93. }
  94. LONG ParseCommandLine(
  95. LPTSTR lpszServer,
  96. COMMAND_HEADER *chCommandHeader,
  97. LPTSTR *aszArgv,
  98. int iArgc
  99. )
  100. /*++
  101. Routine Description:
  102. Parses command line of the form:
  103. rcmd [server_name [[command] | ["command"]]
  104. Arguments:
  105. lpszServer - on exit gets the name of the server from the command line
  106. chCommandHeader - information to pass to rcmdsvc on exit
  107. aszArgv - array of zero terminated strings (passed in from command line)
  108. iArgc - number of strings in argv (passed in from command line)
  109. Return Value:
  110. LONG
  111. --*/
  112. {
  113. LPTSTR buf = NULL;
  114. LONG nChars = 0;
  115. int i;
  116. //
  117. // get the first argument (either the server name or a [-/][?hH])
  118. //
  119. if (iArgc > 1)
  120. {
  121. //
  122. // convert argument to lower case
  123. //
  124. CharLowerBuff(aszArgv[1], lstrlen(aszArgv[1]));
  125. //
  126. // check for switch (only ?Hh are valid)
  127. //
  128. if ((*aszArgv[1] == TEXT('-')) ||
  129. (*aszArgv[1] == TEXT('/'))) {
  130. //
  131. // check the switch
  132. //
  133. if ( (aszArgv[1][1] == TEXT('h')) ||
  134. (aszArgv[1][1] == TEXT('?')) ) {
  135. Usage();
  136. }
  137. else {
  138. RcPrintf(TEXT("Unknown switch %s\n"), aszArgv[1]);
  139. Usage();
  140. }
  141. }
  142. else if ( (*aszArgv[1] == TEXT('\\')) && (aszArgv[1][1] == TEXT('\\'))) {
  143. //
  144. // first argument is a server name
  145. //
  146. lstrcpy(lpszServer, aszArgv[1]);
  147. }
  148. else {
  149. //
  150. // usage error
  151. //
  152. Usage();
  153. }
  154. }
  155. else {
  156. //
  157. // user failed to enter a server name
  158. // default to local machine
  159. //
  160. lstrcpy(lpszServer, "\\\\.");
  161. }
  162. //
  163. // If user entered anything beyond the server name, save it for passing to
  164. // to rcmdsvc.
  165. //
  166. // init
  167. chCommandHeader->CommandFixedHeader.CommandLength = 0;
  168. buf = chCommandHeader->Command;
  169. buf[0] = TEXT('\0');
  170. for (i = 2; i < iArgc; i++) {
  171. //
  172. // append each argument to saved command line
  173. //
  174. if (NULL != strchr(aszArgv[i], ' '))
  175. {
  176. nChars = wsprintf(buf, "\"%s\" ", aszArgv[i]);
  177. }
  178. else
  179. {
  180. nChars = wsprintf(buf, "%s ", aszArgv[i]);
  181. }
  182. buf += nChars;
  183. chCommandHeader->CommandFixedHeader.CommandLength += nChars;
  184. }
  185. //
  186. // in case we went too far, truncate the string
  187. //
  188. chCommandHeader->Command[MAX_CMD_LENGTH] = TEXT('\0');
  189. return (long)iArgc;
  190. }
  191. /***************************************************************************\
  192. * FUNCTION: Main
  193. *
  194. * PURPOSE: Main entry point.
  195. *
  196. * RETURNS: 0 on success, 1 on failure
  197. *
  198. * HISTORY:
  199. *
  200. * 07-10-92 Davidc Created.
  201. *
  202. \***************************************************************************/
  203. int
  204. __cdecl main(
  205. int argc,
  206. char **argv
  207. )
  208. {
  209. SECURITY_ATTRIBUTES SecurityAttributes;
  210. HANDLE StdInputHandle;
  211. HANDLE StdOutputHandle;
  212. HANDLE StdErrorHandle;
  213. CHAR PipeName[MAX_PATH];
  214. //WCHAR PipeName[MAX_PATH];
  215. DWORD ThreadId;
  216. HANDLE HandleArray[2];
  217. COMMAND_HEADER CommandHeader;
  218. RESPONSE_HEADER ResponseHeader;
  219. DWORD BytesWritten, BytesRead;
  220. DWORD Result;
  221. CHAR ServerNameBuffer[MAX_SERVER_NAME_LENGTH+3]; // +3 for gets counts, null
  222. CHAR FullServerNameBuffer[MAX_SERVER_NAME_LENGTH+3]; // +3 for "\\", null
  223. LONG nArgs = 0;
  224. BOOLEAN bBadServerName = TRUE;
  225. //
  226. // Install a handler for Ctrl-C
  227. //
  228. if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) &CtrlHandler, TRUE)) {
  229. RcPrintf("Error:1 - Internal error = %d\n", GetLastError());
  230. return(1);
  231. }
  232. //
  233. // Command line parsing
  234. //
  235. nArgs = ParseCommandLine(FullServerNameBuffer, &CommandHeader, argv, argc);
  236. ServerName = FullServerNameBuffer;
  237. if (nArgs == 1) {
  238. MultiServerMode = TRUE;
  239. ServerNameBuffer[0] = MAX_SERVER_NAME_LENGTH;
  240. FullServerNameBuffer[0] = '\\';
  241. FullServerNameBuffer[1] = '\\';
  242. }
  243. //
  244. // Loop for MultServerMode case (will return appropriately if not)
  245. //
  246. while (TRUE) {
  247. //
  248. // If MultiServerMode, prompt for server name until it's right (enough)
  249. //
  250. while (MultiServerMode) {
  251. //
  252. // BUGBUG - call netapi to validate server name
  253. //
  254. RcPrintf("\nEnter Server Name : ");
  255. FullServerNameBuffer[2] = '\0'; // re-terminate "\\" string
  256. ServerNameBuffer[0] = MAX_SERVER_NAME_LENGTH;
  257. ServerName = strcat(FullServerNameBuffer, _cgets(ServerNameBuffer));
  258. if (strlen(ServerName) < 3) {
  259. RcPrintf("\nError - Invalid Server Name\n");
  260. } else {
  261. break; // valid name, go on
  262. }
  263. }
  264. //
  265. // Construct server pipe name
  266. //
  267. wsprintf(PipeName, PIPE_NAME, ServerName);
  268. //
  269. // Store away our normal i/o handles
  270. //
  271. if (((StdInputHandle = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) ||
  272. ((StdOutputHandle = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) ||
  273. ((StdErrorHandle = GetStdHandle(STD_ERROR_HANDLE)) == INVALID_HANDLE_VALUE)) {
  274. RcPrintf("Error:2 - Internal error = %d\n", GetLastError());
  275. return(1); // catastrophic error - exit
  276. }
  277. //
  278. // Open the named pipe - need security flags to pass all privileges, not
  279. // just effective during impersonation
  280. //
  281. SecurityAttributes.nLength = sizeof(SecurityAttributes);
  282. SecurityAttributes.lpSecurityDescriptor = NULL; // Use default SD
  283. SecurityAttributes.bInheritHandle = FALSE;
  284. PipeHandle = CreateFile(PipeName, // pipe to server
  285. GENERIC_READ | GENERIC_WRITE, // read/write
  286. 0, // No sharing
  287. &SecurityAttributes, // default Security Descriptor
  288. OPEN_EXISTING, // open existing pipe if it exists
  289. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED |
  290. SECURITY_SQOS_PRESENT |
  291. SECURITY_IMPERSONATION | SECURITY_CONTEXT_TRACKING,
  292. NULL // Template file
  293. );
  294. if (PipeHandle == INVALID_HANDLE_VALUE ) {
  295. Result = GetLastError();
  296. RcDbgPrint("Failed to open named pipe, error = %d\n", Result);
  297. switch (Result) {
  298. case ERROR_FILE_NOT_FOUND:
  299. RcPrintf("Error - Failed to connect to <%s>, system not found or service not active\n", ServerName);
  300. break;
  301. case ERROR_PIPE_BUSY:
  302. RcPrintf("Error - Failed to connect to <%s>, remote command server busy\n", ServerName);
  303. break;
  304. default:
  305. RcPrintf("Error - Failed to connect to <%s>, Error = %d\n", ServerName, GetLastError());
  306. }
  307. goto ServerError;
  308. }
  309. //
  310. // Send command header - if single command mode, send command for
  311. // excecute and return. else 0 length indicates no command present
  312. // Specify BASIC level support desired.
  313. //
  314. CommandHeader.CommandFixedHeader.Signature = RCMD_SIGNATURE;
  315. CommandHeader.CommandFixedHeader.RequestedLevel =
  316. RC_LEVEL_REQUEST | RC_LEVEL_BASIC;
  317. if (!WriteFile(
  318. PipeHandle,
  319. &CommandHeader,
  320. sizeof(CommandHeader.CommandFixedHeader) +
  321. CommandHeader.CommandFixedHeader.CommandLength,
  322. &BytesWritten,
  323. NULL )) {
  324. RcPrintf("Error - Failed to send to remote command server, Error = %ld\n", GetLastError());
  325. goto ServerError;
  326. }
  327. //
  328. // Get response header. Will specify reported level or any error.
  329. //
  330. if ((!ReadFile(
  331. PipeHandle,
  332. &ResponseHeader,
  333. sizeof(ResponseHeader),
  334. &BytesRead,
  335. NULL)) || (BytesRead != sizeof(ResponseHeader))) {
  336. RcPrintf("Error - Remote command server failed to respond, Error = %ld\n", GetLastError());
  337. goto ServerError;
  338. }
  339. if (ResponseHeader.Signature != RCMD_SIGNATURE) {
  340. RcPrintf("Error - Incompatible remote command server\n");
  341. goto ServerError;
  342. }
  343. //
  344. // Check for returned errors or supported level
  345. //
  346. if (!(ResponseHeader.SupportedLevel ==
  347. (RC_LEVEL_RESPONSE | RC_LEVEL_BASIC))) {
  348. if (ResponseHeader.SupportedLevel & RC_ERROR_RESPONSE) {
  349. //
  350. // Error returned
  351. //
  352. switch (ResponseHeader.SupportedLevel & ~RC_ERROR_RESPONSE) {
  353. case ERROR_ACCESS_DENIED:
  354. RcPrintf("Error - You have insufficient access on the remote system\n");
  355. break;
  356. default:
  357. RcPrintf("Error - Failed to establish remote session, Error = %d\n",
  358. (ResponseHeader.SupportedLevel & ~RC_ERROR_RESPONSE));
  359. break;
  360. } //switch
  361. goto ServerError;
  362. } else if (ResponseHeader.SupportedLevel & RC_LEVEL_RESPONSE) {
  363. //
  364. // Supported level returned - but not a valid value (not BASIC)
  365. //
  366. RcPrintf("Error - Invalid support level returned\n");
  367. goto ServerError;
  368. } else {
  369. //
  370. // Neither error nor supported level returned
  371. //
  372. RcPrintf("Error - Invalid response from remote server\n");
  373. goto ServerError;
  374. }
  375. }
  376. //
  377. // All is well - Session is connected
  378. //
  379. SessionConnected = TRUE;
  380. if (CommandHeader.CommandFixedHeader.CommandLength == 0) {
  381. RcPrintf("Connected to %s\n\n", ServerName);
  382. } else {
  383. RcPrintf("Executing on %s: %s\n\n", ServerName, CommandHeader.Command);
  384. }
  385. //
  386. // Exec 2 threads - 1 copies data from stdin to pipe, the other
  387. // copies data from the pipe to stdout.
  388. //
  389. ReadThreadHandle = CreateThread(
  390. NULL, // Default security
  391. 0, // Default Stack size
  392. (LPTHREAD_START_ROUTINE) ReadThreadProc,
  393. (PVOID)PipeHandle,
  394. 0,
  395. &ThreadId);
  396. if (ReadThreadHandle == NULL) {
  397. RcPrintf("Error:3 - Internal error = %ld\n", GetLastError());
  398. return(1); // catastrophic error - exit
  399. }
  400. //
  401. // Create the write thread
  402. //
  403. WriteThreadHandle = CreateThread(
  404. NULL, // Default security
  405. 0, // Default Stack size
  406. (LPTHREAD_START_ROUTINE) WriteThreadProc,
  407. (PVOID)PipeHandle,
  408. 0,
  409. &ThreadId);
  410. if (WriteThreadHandle == NULL) {
  411. RcPrintf("Error:4 - Internal error = %ld\n", GetLastError());
  412. TerminateThread(ReadThreadHandle, 0);
  413. CloseHandle(ReadThreadHandle);
  414. return(1); // catastrophic error, exit
  415. }
  416. //
  417. // Wait for either thread to finish
  418. //
  419. HandleArray[0] = ReadThreadHandle;
  420. HandleArray[1] = WriteThreadHandle;
  421. Result = WaitForMultipleObjects(
  422. 2,
  423. HandleArray,
  424. FALSE, // Wait for either to finish
  425. 0xffffffff
  426. ); // Wait forever
  427. //
  428. // Finished - terminate other thread and close pipe handle
  429. //
  430. if (Result == (WAIT_OBJECT_0 + 0)) { // Read thread finished - terminate write
  431. TerminateThread(WriteThreadHandle, 0);
  432. }
  433. if (Result == (WAIT_OBJECT_0 + 1)) { // Write thread finished - terminate read
  434. TerminateThread(ReadThreadHandle, 0);
  435. }
  436. RcDbgPrint("Read or write thread terminated\n");
  437. //
  438. // Close our pipe handle
  439. //
  440. CloseHandle(PipeHandle);
  441. PipeHandle = NULL;
  442. //
  443. // Re-enable normal ctrl-C processing
  444. //
  445. SessionConnected = FALSE;
  446. //
  447. // Normal completion - return if not MultServerMode
  448. //
  449. if (!MultiServerMode) {
  450. //
  451. // return - process exit will terminate threads and close thread handles
  452. //
  453. return(1);
  454. }
  455. ServerError:
  456. if (PipeHandle != NULL) {
  457. CloseHandle(PipeHandle);
  458. }
  459. if (!MultiServerMode) {
  460. //
  461. // return false on error - process exit terminates threads/closes handles
  462. //
  463. return(0);
  464. }
  465. //
  466. // Multi-service mode exits occurs with ctrl-C/break only
  467. //
  468. }
  469. }
  470. /***************************************************************************\
  471. * FUNCTION: ReadPipe
  472. *
  473. * PURPOSE: Implements an overlapped read such that read and write operations
  474. * to the same pipe handle don't deadlock.
  475. *
  476. * RETURNS: TRUE on success, FALSE on failure (GetLastError() has error)
  477. *
  478. * HISTORY:
  479. *
  480. * 05-27-92 Davidc Created.
  481. *
  482. \***************************************************************************/
  483. BOOL
  484. ReadPipe(
  485. HANDLE PipeHandle,
  486. LPVOID lpBuffer,
  487. DWORD nNumberOfBytesToRead,
  488. LPDWORD lpNumberOfBytesRead
  489. )
  490. {
  491. DWORD Result;
  492. OVERLAPPED Overlapped;
  493. HANDLE EventHandle;
  494. DWORD Error;
  495. //
  496. // Create an event for the overlapped operation
  497. //
  498. EventHandle = CreateEvent(
  499. NULL, // no security
  500. TRUE, // Manual reset
  501. FALSE, // Initial state
  502. NULL // Name
  503. );
  504. if (EventHandle == NULL) {
  505. RcDbgPrint("ReadPipe: CreateEvent failed, error = %d\n", GetLastError());
  506. return(FALSE);
  507. }
  508. Overlapped.hEvent = EventHandle;
  509. Overlapped.Internal = 0;
  510. Overlapped.InternalHigh = 0;
  511. Overlapped.Offset = 0;
  512. Overlapped.OffsetHigh = 0;
  513. Result = ReadFile(
  514. PipeHandle,
  515. lpBuffer,
  516. nNumberOfBytesToRead,
  517. lpNumberOfBytesRead,
  518. &Overlapped
  519. );
  520. if (Result) {
  521. //
  522. // Success without waiting - it's too easy !
  523. //
  524. CloseHandle(EventHandle);
  525. } else {
  526. //
  527. // Read failed, if it's overlapped io, go wait for it
  528. // If failure due to server, print appropriate message.
  529. //
  530. Error = GetLastError();
  531. switch (Error) {
  532. case ERROR_IO_PENDING:
  533. break;
  534. case ERROR_PIPE_NOT_CONNECTED:
  535. case ERROR_BROKEN_PIPE:
  536. RcPrintf("\nRemote server %s disconnected\n", ServerName);
  537. CloseHandle(EventHandle);
  538. return(FALSE);
  539. default:
  540. RcPrintf("Error:5 - Internal error = %d\n", Error);
  541. RcDbgPrint("ReadPipe: ReadFile failed, error = %d\n", Error);
  542. CloseHandle(EventHandle);
  543. return(FALSE);
  544. }
  545. //
  546. // Wait for the I/O to complete
  547. //
  548. Result = WaitForSingleObject(EventHandle, (DWORD)-1);
  549. if (Result != 0) {
  550. RcDbgPrint("ReadPipe: event wait failed, result = %d, last error = %d\n", Result, GetLastError());
  551. CloseHandle(EventHandle);
  552. return(FALSE);
  553. }
  554. //
  555. // Go get the I/O result
  556. //
  557. Result = GetOverlappedResult( PipeHandle,
  558. &Overlapped,
  559. lpNumberOfBytesRead,
  560. FALSE
  561. );
  562. //
  563. // We're finished with the event handle
  564. //
  565. CloseHandle(EventHandle);
  566. //
  567. // Check result of GetOverlappedResult
  568. //
  569. if (!Result) {
  570. Error = GetLastError();
  571. switch (Error) {
  572. case ERROR_PIPE_NOT_CONNECTED:
  573. case ERROR_BROKEN_PIPE:
  574. RcPrintf("\nRemote server %s disconnected\n", ServerName);
  575. return(FALSE);
  576. default:
  577. RcPrintf("Error:9 - Internal error = %d\n", Error);
  578. RcDbgPrint("ReadPipe: GetOverLappedRsult failed, error = %d\n", Error);
  579. return(FALSE);
  580. }
  581. }
  582. }
  583. return(TRUE);
  584. }
  585. /***************************************************************************\
  586. * FUNCTION: WritePipe
  587. *
  588. * PURPOSE: Implements an overlapped write such that read and write operations
  589. * to the same pipe handle don't deadlock.
  590. *
  591. * RETURNS: TRUE on success, FALSE on failure (GetLastError() has error)
  592. *
  593. * HISTORY:
  594. *
  595. * 05-27-92 Davidc Created.
  596. *
  597. \***************************************************************************/
  598. BOOL
  599. WritePipe(
  600. HANDLE PipeHandle,
  601. CONST VOID *lpBuffer,
  602. DWORD nNumberOfBytesToWrite,
  603. LPDWORD lpNumberOfBytesWritten
  604. )
  605. {
  606. DWORD Result;
  607. OVERLAPPED Overlapped;
  608. HANDLE EventHandle;
  609. DWORD Error;
  610. //
  611. // Create an event for the overlapped operation
  612. //
  613. EventHandle = CreateEvent(
  614. NULL, // no security
  615. TRUE, // Manual reset
  616. FALSE, // Initial state
  617. NULL // Name
  618. );
  619. if (EventHandle == NULL) {
  620. RcDbgPrint("WritePipe: CreateEvent failed, error = %d\n", GetLastError());
  621. return(FALSE);
  622. }
  623. Overlapped.hEvent = EventHandle;
  624. Overlapped.Internal = 0;
  625. Overlapped.InternalHigh = 0;
  626. Overlapped.Offset = 0;
  627. Overlapped.OffsetHigh = 0;
  628. Result = WriteFile(
  629. PipeHandle,
  630. lpBuffer,
  631. nNumberOfBytesToWrite,
  632. lpNumberOfBytesWritten,
  633. &Overlapped
  634. );
  635. if (Result) {
  636. //
  637. // Success without waiting - it's too easy !
  638. //
  639. CloseHandle(EventHandle);
  640. } else {
  641. //
  642. // Write failed, if it's overlapped io, go wait for it
  643. // If failure due to server, print appropriate message.
  644. //
  645. Error = GetLastError();
  646. switch (Error) {
  647. case ERROR_IO_PENDING:
  648. break;
  649. case ERROR_PIPE_NOT_CONNECTED:
  650. case ERROR_BROKEN_PIPE:
  651. RcPrintf("\nRemote server %s disconnected\n", ServerName);
  652. CloseHandle(EventHandle);
  653. return(FALSE);
  654. default:
  655. RcPrintf("Error:6 - Internal error = %d\n", Error);
  656. RcDbgPrint("WritePipe: WriteFile failed, error = %d\n", Error);
  657. CloseHandle(EventHandle);
  658. return(FALSE);
  659. }
  660. //
  661. // Wait for the I/O to complete
  662. //
  663. Result = WaitForSingleObject(EventHandle, (DWORD)-1);
  664. if (Result != 0) {
  665. RcDbgPrint("WritePipe: event wait failed, result = %d, last error = %d\n", Result, GetLastError());
  666. CloseHandle(EventHandle);
  667. return(FALSE);
  668. }
  669. //
  670. // Go get the I/O result
  671. //
  672. Result = GetOverlappedResult( PipeHandle,
  673. &Overlapped,
  674. lpNumberOfBytesWritten,
  675. FALSE
  676. );
  677. //
  678. // We're finished with the event handle
  679. //
  680. CloseHandle(EventHandle);
  681. //
  682. // Check result of GetOverlappedResult
  683. //
  684. if (!Result) {
  685. Error = GetLastError();
  686. switch (Error) {
  687. case ERROR_PIPE_NOT_CONNECTED:
  688. case ERROR_BROKEN_PIPE:
  689. RcPrintf("\nRemote server %s disconnected\n", ServerName);
  690. return(FALSE);
  691. default:
  692. RcPrintf("Error:10 - Internal error = %d\n", Error);
  693. RcDbgPrint("WritePipe: GetOverLappedRsult failed, error = %d\n", Error);
  694. return(FALSE);
  695. }
  696. }
  697. }
  698. return(TRUE);
  699. }
  700. /***************************************************************************\
  701. * FUNCTION: ReadThreadProc
  702. *
  703. * PURPOSE: The read thread procedure. Reads from pipe and writes to STD_OUT
  704. *
  705. * RETURNS: Nothing
  706. *
  707. * HISTORY:
  708. *
  709. * 05-21-92 Davidc Created.
  710. *
  711. \***************************************************************************/
  712. DWORD
  713. ReadThreadProc(
  714. LPVOID Parameter
  715. )
  716. {
  717. HANDLE PipeHandle = Parameter;
  718. BYTE Buffer[BUFFER_SIZE];
  719. DWORD BytesRead;
  720. DWORD BytesWritten;
  721. while (ReadPipe(PipeHandle, Buffer, sizeof(Buffer), &BytesRead)) {
  722. if (!WriteFile(
  723. GetStdHandle(STD_OUTPUT_HANDLE),
  724. Buffer,
  725. BytesRead,
  726. &BytesWritten,
  727. NULL
  728. )) {
  729. RcPrintf("Error:7 - Internal error = %d\n", GetLastError());
  730. RcDbgPrint("ReadThreadProc exitting, WriteFile error = %d\n",
  731. GetLastError());
  732. ExitThread((DWORD)0);
  733. assert(FALSE); // Should never get here
  734. break;
  735. }
  736. }
  737. //
  738. // ReadPipe issues more error information to user, debugger
  739. // falls through here on read error
  740. //
  741. RcDbgPrint("WriteThreadProc exitting, ReadPipe failed\n");
  742. ExitThread((DWORD)0);
  743. return(0);
  744. }
  745. /***************************************************************************\
  746. * FUNCTION: WriteThreadProc
  747. *
  748. * PURPOSE: The write thread procedure. Reads from STD_INPUT and writes to pipe
  749. *
  750. * RETURNS: Nothing
  751. *
  752. * HISTORY:
  753. *
  754. * 05-21-92 Davidc Created.
  755. *
  756. \***************************************************************************/
  757. DWORD
  758. WriteThreadProc(
  759. LPVOID Parameter
  760. )
  761. {
  762. HANDLE PipeHandle = Parameter;
  763. BYTE Buffer[BUFFER_SIZE];
  764. DWORD BytesRead;
  765. DWORD BytesWritten;
  766. DWORD Result;
  767. while (ReadFile(
  768. GetStdHandle(STD_INPUT_HANDLE),
  769. Buffer,
  770. sizeof(Buffer),
  771. &BytesRead,
  772. NULL
  773. )) {
  774. if ((DWORD)Buffer[0] == 0x0A0D0A0D) {
  775. RcPrintf("\nDouble crlf sent\n");
  776. }
  777. if (!WritePipe(
  778. PipeHandle,
  779. Buffer,
  780. BytesRead,
  781. &BytesWritten
  782. )) {
  783. //
  784. // WritePipe issues more error information to user, debugger
  785. //
  786. RcDbgPrint("WriteThreadProc exitted due to WritePipe\n");
  787. ExitThread((DWORD)0);
  788. break;
  789. }
  790. }
  791. //
  792. // Falls out if read fails
  793. //
  794. RcDbgPrint("WriteThreadProc, ReadFile error = %d\n", GetLastError());
  795. RcPrintf("Error:8 - Internal error = %d\n", GetLastError());
  796. ExitThread((DWORD)0);
  797. return(0);
  798. }
  799. /***************************************************************************\
  800. * FUNCTION: CtrlHandler
  801. *
  802. * PURPOSE: Handles console event notifications.
  803. *
  804. * RETURNS: TRUE if the event has been handled, otherwise FALSE.
  805. *
  806. * HISTORY:
  807. *
  808. * 05-21-92 Davidc Created.
  809. *
  810. \***************************************************************************/
  811. BOOL
  812. CtrlHandler(
  813. DWORD CtrlType
  814. )
  815. {
  816. //
  817. // We'll handle Ctrl-C, Ctl-Break events if session is connected
  818. //
  819. if (SessionConnected) {
  820. if (CtrlType == CTRL_C_EVENT) {
  821. //
  822. // Session established - pass ctl-C to remote server
  823. //
  824. if (PipeHandle != NULL) {
  825. //
  826. // Send a Ctrl-C to the server, don't care if it fails
  827. //
  828. CHAR CtrlC = '\003';
  829. DWORD BytesWritten;
  830. WriteFile(PipeHandle,
  831. &CtrlC,
  832. sizeof(CtrlC),
  833. &BytesWritten,
  834. NULL
  835. );
  836. return(TRUE); // we handled it
  837. }
  838. return(FALSE); // no pipe - not handled (when in doubt, bail out)
  839. } else if (CtrlType == CTRL_BREAK_EVENT) {
  840. if (MultiServerMode) {
  841. //
  842. // If ctl-Break in session w/MultiServerMode, break session
  843. // BUGBUG - eliminate terminate thread
  844. //
  845. TerminateThread(ReadThreadHandle, 0);
  846. CloseHandle(ReadThreadHandle);
  847. TerminateThread(WriteThreadHandle, 0);
  848. CloseHandle(WriteThreadHandle);
  849. return(TRUE); // we handled it
  850. } else {
  851. //
  852. // Not MultiServer mode - handle normally
  853. //
  854. return(FALSE);
  855. }
  856. } else {
  857. return(FALSE); // not ctl-c or break - we didn't handle it
  858. }
  859. }
  860. //
  861. // Not connected - we didn't handle it
  862. //
  863. return(FALSE);
  864. }
  865. /***************************************************************************\
  866. * FUNCTION: RcPrintf
  867. *
  868. * PURPOSE: Printf that uses low-level io.
  869. *
  870. * HISTORY:
  871. *
  872. * 07-15-92 Davidc Created.
  873. *
  874. \***************************************************************************/
  875. int RcPrintf (
  876. const char *format,
  877. ...
  878. )
  879. {
  880. CHAR Buffer[MAX_PATH];
  881. va_list argpointer;
  882. int Result;
  883. DWORD BytesWritten;
  884. va_start(argpointer, format);
  885. Result = vsprintf(Buffer, format, argpointer);
  886. if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), Buffer, Result, &BytesWritten, NULL)) {
  887. RcDbgPrint("RcPrintf : Write file to stdout failed, error = %d\n", GetLastError());
  888. Result = 0;
  889. }
  890. va_end(argpointer);
  891. return(Result);
  892. }
  893. /***************************************************************************\
  894. * FUNCTION: RcDbgPrint
  895. *
  896. * PURPOSE: DbgPrint enabled at runtime by setting RcDbgPrintEnable
  897. *
  898. * HISTORY:
  899. *
  900. * 05-22-92 DaveTh Created.
  901. *
  902. \***************************************************************************/
  903. int RcDbgPrint (
  904. const char *format,
  905. ...
  906. )
  907. {
  908. CHAR Buffer[MAX_PATH];
  909. va_list argpointer;
  910. int iRetval = 0;
  911. if (RcDbgPrintEnable) {
  912. va_start(argpointer, format);
  913. iRetval = vsprintf(Buffer, format, argpointer);
  914. assert (iRetval >= 0);
  915. va_end(argpointer);
  916. OutputDebugString(Buffer);
  917. }
  918. return(0);
  919. }