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.

788 lines
18 KiB

  1. /******************************************************************************\
  2. * This is a part of the Microsoft Source Code Samples.
  3. * Copyright 1992 - 1997 Microsoft Corporation.
  4. * All rights reserved.
  5. * This source code is only intended as a supplement to
  6. * Microsoft Development Tools and/or WinHelp documentation.
  7. * See these sources for detailed information regarding the
  8. * Microsoft samples programs.
  9. \******************************************************************************/
  10. /*++
  11. Copyright 1992 - 1997 Microsoft Corporation
  12. Module Name:
  13. Client.c
  14. Abstract:
  15. The Client component of Remote. Connects to the remote
  16. server using named pipes. It sends its stdin to
  17. the server and output everything from server to
  18. its stdout.
  19. Author:
  20. Rajivendra Nath 2-Jan-1992
  21. Dave Hart Summer 1997 single-pipe operation
  22. Environment:
  23. Console App. User mode.
  24. Revision History:
  25. --*/
  26. #include <precomp.h>
  27. #include "Remote.h"
  28. BOOL fAsyncPipe = TRUE; // need this so server has it TRUE
  29. HANDLE*
  30. EstablishSession(
  31. char *server,
  32. char *pipe
  33. );
  34. DWORD
  35. WINAPI
  36. SendServerInp(
  37. LPVOID pvParam
  38. );
  39. BOOL
  40. FilterClientInp(
  41. char *buff,
  42. int count
  43. );
  44. BOOL
  45. Mych(
  46. DWORD ctrlT
  47. );
  48. VOID
  49. SendMyInfo(
  50. PHANDLE Pipes
  51. );
  52. #define ZERO_LENGTH_READ_LIMIT 200
  53. HANDLE MyStdInp;
  54. HANDLE MyStdOut;
  55. //
  56. // ReadPipe and WritePipe are referenced by multiple
  57. // threads so need to be volatile.
  58. //
  59. volatile HANDLE ReadPipe;
  60. volatile HANDLE WritePipe;
  61. CONSOLE_SCREEN_BUFFER_INFO csbi;
  62. char MyEchoStr[30];
  63. BOOL CmdSent;
  64. DWORD LinesToSend=LINESTOSEND;
  65. int
  66. Client(
  67. char* Server,
  68. char* Pipe
  69. )
  70. {
  71. HANDLE *Connection;
  72. DWORD dwThreadID;
  73. HANDLE hThread;
  74. DWORD cb;
  75. OVERLAPPED ol;
  76. char rgchBuf[1024];
  77. DWORD dwZeroCount = 0;
  78. CWCDATA cwcData = {NULL};
  79. int rc = 0;
  80. MyStdInp=GetStdHandle(STD_INPUT_HANDLE);
  81. MyStdOut=GetStdHandle(STD_OUTPUT_HANDLE);
  82. fputs("**************************************\n"
  83. "*********** REMOTE ************\n"
  84. "*********** CLIENT ************\n"
  85. "**************************************\n",
  86. stdout);
  87. if ((Connection=EstablishSession(Server,Pipe))==NULL)
  88. return 1;
  89. ReadPipe=Connection[0];
  90. WritePipe=Connection[1];
  91. SetConsoleCtrlHandler((PHANDLER_ROUTINE)Mych,TRUE);
  92. // Start Thread For Client --> Server Flow
  93. hThread = (HANDLE)
  94. _beginthreadex(
  95. NULL, // security
  96. 0, // default stack size
  97. SendServerInp, // thread proc
  98. NULL, // parm
  99. 0, // not suspended
  100. &dwThreadID
  101. );
  102. if ( !hThread)
  103. {
  104. Errormsg("REMOTE /C Could Not Create Thread.");
  105. return 1;
  106. }
  107. // We don't need the thread handle - it lives to the process exits
  108. CloseHandle(hThread);
  109. ZeroMemory(&ol, sizeof(ol));
  110. ol.hEvent =
  111. CreateEvent(
  112. NULL, // security
  113. TRUE, // auto-reset
  114. FALSE, // initially nonsignaled
  115. NULL // unnamed
  116. );
  117. while (ReadFileSynch(ReadPipe, rgchBuf, sizeof rgchBuf, &cb, 0, &ol)) {
  118. if (cb) {
  119. // If we are interested in colors, do special output
  120. if ( pWantColorLines() )
  121. {
  122. if ( !WriteConsoleWithColor( MyStdOut,
  123. rgchBuf,
  124. cb,
  125. &cwcData ) )
  126. {
  127. rc = 1;
  128. break;
  129. }
  130. }
  131. else
  132. {
  133. if ( ! WriteFile(MyStdOut, rgchBuf, cb, &cb, NULL)) {
  134. rc = 1;
  135. break;
  136. }
  137. }
  138. dwZeroCount = 0;
  139. } else {
  140. if (++dwZeroCount > ZERO_LENGTH_READ_LIMIT) {
  141. //
  142. // If we get a bunch of zero length reads in a row,
  143. // something's broken, don't loop forever.
  144. // (bug #115866).
  145. //
  146. fputs("\nREMOTE: bailing out, server must have gone away.\n", stdout);
  147. rc = 1;
  148. break;
  149. }
  150. }
  151. }
  152. CloseHandle(ol.hEvent);
  153. fputs("*** SESSION OVER ***", stdout);
  154. fflush(stdout);
  155. CloseClientPipes();
  156. fputs("\n", stdout);
  157. fflush(stdout);
  158. return rc;
  159. }
  160. DWORD
  161. WINAPI
  162. SendServerInp(
  163. LPVOID pvParam
  164. )
  165. {
  166. DWORD dread,dwrote;
  167. OVERLAPPED ol;
  168. char buff[512];
  169. UNREFERENCED_PARAMETER(pvParam);
  170. ZeroMemory(&ol, sizeof(ol));
  171. ol.hEvent =
  172. CreateEvent(
  173. NULL, // security
  174. TRUE, // auto-reset
  175. FALSE, // initially nonsignaled
  176. NULL // unnamed
  177. );
  178. while(ReadFile(MyStdInp,buff,sizeof buff,&dread,NULL))
  179. {
  180. if (FilterClientInp(buff,dread))
  181. continue;
  182. if (!WriteFileSynch(WritePipe,buff,dread,&dwrote,0,&ol))
  183. break;
  184. }
  185. CloseClientPipes();
  186. return 0;
  187. }
  188. BOOL
  189. FilterClientInp(
  190. char *buff,
  191. int count
  192. )
  193. {
  194. if (count==0)
  195. return(TRUE);
  196. if (buff[0]==2) // Adhoc screening of ^B so that i386kd/mipskd
  197. return(TRUE); // do not terminate.
  198. if (buff[0]==COMMANDCHAR)
  199. {
  200. switch (buff[1])
  201. {
  202. case 'k':
  203. case 'K':
  204. case 'q':
  205. case 'Q':
  206. CloseClientPipes();
  207. return(FALSE);
  208. case 'h':
  209. case 'H':
  210. printf("%cM : Send Message\n",COMMANDCHAR);
  211. printf("%cP : Show Popup on Server\n",COMMANDCHAR);
  212. printf("%cS : Status of Server\n",COMMANDCHAR);
  213. printf("%cQ : Quit client\n",COMMANDCHAR);
  214. printf("%cH : This Help\n",COMMANDCHAR);
  215. return(TRUE);
  216. default:
  217. return(FALSE);
  218. }
  219. }
  220. return(FALSE);
  221. }
  222. BOOL
  223. Mych(
  224. DWORD ctrlT
  225. )
  226. {
  227. char c[2];
  228. DWORD tmp;
  229. OVERLAPPED ol;
  230. c[0]=CTRLC;
  231. if (ctrlT==CTRL_C_EVENT)
  232. {
  233. ZeroMemory(&ol, sizeof(ol));
  234. ol.hEvent =
  235. CreateEvent(
  236. NULL, // security
  237. TRUE, // auto-reset
  238. FALSE, // initially nonsignaled
  239. NULL // unnamed
  240. );
  241. if (INVALID_HANDLE_VALUE != WritePipe &&
  242. !WriteFileSynch(WritePipe,c,1,&tmp,0,&ol))
  243. {
  244. CloseHandle(ol.hEvent);
  245. Errormsg("Error Sending ^c");
  246. return(FALSE);
  247. }
  248. CloseHandle(ol.hEvent);
  249. return(TRUE);
  250. }
  251. if ((ctrlT==CTRL_BREAK_EVENT)||
  252. (ctrlT==CTRL_CLOSE_EVENT)||
  253. (ctrlT==CTRL_LOGOFF_EVENT)||
  254. (ctrlT==CTRL_SHUTDOWN_EVENT)
  255. ) {
  256. CloseClientPipes();
  257. }
  258. return(FALSE);
  259. }
  260. VOID
  261. CloseClientPipes(
  262. VOID
  263. )
  264. {
  265. HANDLE WriteHandle, ReadHandle;
  266. WriteHandle = (HANDLE) InterlockedExchangePointer(
  267. (PVOID *) &WritePipe,
  268. INVALID_HANDLE_VALUE
  269. );
  270. if (INVALID_HANDLE_VALUE != WriteHandle) {
  271. CloseHandle(WriteHandle);
  272. ReadHandle = (HANDLE) InterlockedExchangePointer(
  273. (PVOID *) &ReadPipe,
  274. INVALID_HANDLE_VALUE
  275. );
  276. if (INVALID_HANDLE_VALUE != ReadHandle &&
  277. WriteHandle != ReadHandle) {
  278. CloseHandle(ReadHandle);
  279. }
  280. }
  281. }
  282. VOID
  283. HandleConnectError(
  284. char *server,
  285. char *srvpipename
  286. )
  287. {
  288. DWORD Err = GetLastError();
  289. char msg[128];
  290. Errormsg("*** Unable to Connect ***");
  291. //
  292. // Print a helpful message
  293. //
  294. switch(Err)
  295. {
  296. case ERROR_FILE_NOT_FOUND:
  297. sprintf(msg,"invalid pipe name \"%s\"", srvpipename);
  298. break;
  299. case ERROR_BAD_NETPATH:
  300. sprintf(msg,"\\\\%s not found", server);
  301. break;
  302. default:
  303. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|
  304. FORMAT_MESSAGE_IGNORE_INSERTS,
  305. NULL, Err, 0, msg, sizeof(msg), NULL);
  306. break;
  307. }
  308. printf("Diagnosis: %s\n",msg);
  309. //
  310. // If the machine exists but the pipe doesn't do an
  311. // automatic remote /q to list pipes available on
  312. // that machine.
  313. //
  314. if (ERROR_FILE_NOT_FOUND == Err) {
  315. printf("\nREMOTE /Q %s\n", server);
  316. fflush(stdout);
  317. QueryRemotePipes(server);
  318. }
  319. }
  320. HANDLE*
  321. EstablishSession(
  322. char *server,
  323. char *srvpipename
  324. )
  325. {
  326. extern BOOL bForceTwoPipes;
  327. static HANDLE PipeH[2];
  328. char pipenameSrvIn[200];
  329. char pipenameSrvOut[200];
  330. BOOL fOldServer;
  331. DWORD dwError;
  332. DWORD RetryCount = 0;
  333. //
  334. // Since in single-pipe operation we'll be using the same
  335. // pipe in two threads, we have to open the handles for
  336. // overlapped operation, even though we always want
  337. // synchronous operation.
  338. //
  339. sprintf(pipenameSrvIn ,SERVER_READ_PIPE ,server,srvpipename);
  340. sprintf(pipenameSrvOut,SERVER_WRITE_PIPE,server,srvpipename);
  341. if (bForceTwoPipes) {
  342. dwError = ERROR_NOT_SUPPORTED;
  343. } else {
  344. RetrySrvBidi:
  345. if (INVALID_HANDLE_VALUE ==
  346. (PipeH[1] =
  347. CreateFile(
  348. pipenameSrvIn,
  349. GENERIC_READ | GENERIC_WRITE,
  350. 0,
  351. NULL,
  352. OPEN_EXISTING,
  353. FILE_FLAG_OVERLAPPED,
  354. NULL
  355. ))) {
  356. dwError = GetLastError();
  357. if (ERROR_PIPE_BUSY == dwError) {
  358. fputs( "All pipe instances busy, waiting for another...\n", stdout);
  359. WaitNamedPipe(
  360. pipenameSrvIn,
  361. 15000
  362. );
  363. if (RetryCount++ < 6) {
  364. goto RetrySrvBidi;
  365. }
  366. }
  367. if (ERROR_ACCESS_DENIED != dwError &&
  368. ERROR_NOT_SUPPORTED != dwError) {
  369. HandleConnectError(server, srvpipename);
  370. return NULL;
  371. }
  372. } else {
  373. PipeH[0] = PipeH[1];
  374. fAsyncPipe = TRUE;
  375. fputs("Connected...\n\n", stdout);
  376. SendMyInfo(PipeH);
  377. return PipeH;
  378. }
  379. }
  380. //
  381. // Old remote servers don't allow you to open the
  382. // server IN pipe for READ access, so go down the
  383. // old path, notably opening OUT first so the
  384. // server knows we'll be using both pipes. We'll
  385. // also come down this path on Win95 because
  386. // it doesn't allow you to open an overlapped
  387. // pipe handle. Or if remote /c mach pipe /2 is used.
  388. //
  389. fOldServer = (ERROR_ACCESS_DENIED == dwError);
  390. RetrySrvOut:
  391. if (INVALID_HANDLE_VALUE ==
  392. (PipeH[0] =
  393. CreateFile(
  394. pipenameSrvOut,
  395. GENERIC_READ,
  396. 0,
  397. NULL,
  398. OPEN_EXISTING,
  399. 0,
  400. NULL
  401. ))) {
  402. if (ERROR_PIPE_BUSY == GetLastError()) {
  403. fputs( "All OUT pipe instances busy, waiting for another...\n", stdout);
  404. WaitNamedPipe(
  405. pipenameSrvOut,
  406. 32000 // server recycles abandoned
  407. ); // OUT pipe after two minutes
  408. if (RetryCount++ < 6) {
  409. goto RetrySrvOut;
  410. }
  411. }
  412. HandleConnectError(server, srvpipename);
  413. return NULL;
  414. }
  415. RetrySrvIn:
  416. if (INVALID_HANDLE_VALUE ==
  417. (PipeH[1] =
  418. CreateFile(
  419. pipenameSrvIn,
  420. GENERIC_WRITE,
  421. 0,
  422. NULL,
  423. OPEN_EXISTING,
  424. 0,
  425. NULL
  426. ))) {
  427. dwError = GetLastError();
  428. if (ERROR_PIPE_BUSY == dwError) {
  429. fputs( "All IN pipe instances busy, waiting for another...\n", stdout);
  430. WaitNamedPipe(
  431. pipenameSrvIn,
  432. 15000
  433. );
  434. if (RetryCount++ < 6) {
  435. goto RetrySrvIn;
  436. }
  437. }
  438. HandleConnectError(server, srvpipename);
  439. return NULL;
  440. }
  441. fAsyncPipe = FALSE;
  442. printf("Connected... %s\n\n",
  443. fOldServer
  444. ? "to two-pipe remote server."
  445. : "using two pipes."
  446. );
  447. SendMyInfo(PipeH);
  448. return PipeH;
  449. }
  450. VOID
  451. SendMyInfo(
  452. PHANDLE pipeH
  453. )
  454. {
  455. HANDLE rPipe=pipeH[0];
  456. HANDLE wPipe=pipeH[1];
  457. DWORD hostlen;
  458. WORD BytesToSend=sizeof(SESSION_STARTUPINFO);
  459. DWORD tmp;
  460. OVERLAPPED ol;
  461. SESSION_STARTUPINFO ssi;
  462. SESSION_STARTREPLY ssr;
  463. ol.hEvent =
  464. CreateEvent(
  465. NULL, // security
  466. TRUE, // auto-reset
  467. FALSE, // initially nonsignaled
  468. NULL // unnamed
  469. );
  470. ssi.Size=BytesToSend;
  471. ssi.Version=VERSION;
  472. hostlen = sizeof(ssi.ClientName) / sizeof(ssi.ClientName[0]);
  473. GetComputerName(ssi.ClientName, &hostlen);
  474. ssi.LinesToSend=LinesToSend;
  475. ssi.Flag=ClientToServerFlag;
  476. {
  477. DWORD NewCode=MAGICNUMBER;
  478. char Name[MAX_COMPUTERNAME_LENGTH+1];
  479. strcpy(Name,(char *)ssi.ClientName);
  480. memcpy(&Name[11],(char *)&NewCode,sizeof(NewCode));
  481. //
  482. // The server needs to know if we're doing single-pipe
  483. // operation so it can complete the connection properly.
  484. // So if we are, change the first byte of the first
  485. // send (the computername, which is later superceded
  486. // by the one in the SESSION_STARTUPINFO structure)
  487. // to an illegal computername character, question mark.
  488. //
  489. if (wPipe == rPipe) {
  490. Name[0] = '?';
  491. }
  492. WriteFileSynch(wPipe,(char *)Name,HOSTNAMELEN-1,&tmp,0,&ol);
  493. ReadFileSynch(rPipe ,(char *)&ssr.MagicNumber,sizeof(ssr.MagicNumber),&tmp,0,&ol);
  494. if (ssr.MagicNumber!=MAGICNUMBER)
  495. {
  496. SetLastError(ERROR_INVALID_PARAMETER);
  497. ErrorExit("Pipe connected but server not recognized.\n");
  498. }
  499. //Get Rest of the info-its not the old server
  500. ReadFileSynch(
  501. rPipe,
  502. (char *)&ssr + sizeof(ssr.MagicNumber),
  503. sizeof(ssr)-sizeof(ssr.MagicNumber),
  504. &tmp,
  505. 0,
  506. &ol
  507. );
  508. }
  509. if (!WriteFileSynch(wPipe,(char *)&ssi,BytesToSend,&tmp,0,&ol))
  510. {
  511. Errormsg("INFO Send Error");
  512. }
  513. CloseHandle(ol.hEvent);
  514. }
  515. VOID
  516. QueryRemotePipes(
  517. char* pszServer
  518. )
  519. {
  520. HANDLE hQPipe;
  521. DWORD dwRead;
  522. DWORD dwError;
  523. char fullname[400] = {0};
  524. char* msg;
  525. int msgLen;
  526. if (pszServer[0] == '\\' && pszServer[1] == '\\') {
  527. pszServer += 2;
  528. }
  529. printf("Querying server \\\\%s\n", pszServer);
  530. _snprintf(fullname, sizeof(fullname)-1, QUERY_DEBUGGERS_PIPE, pszServer);
  531. //
  532. // Send request and display the query result
  533. //
  534. hQPipe = CreateFile(fullname,
  535. GENERIC_READ | GENERIC_WRITE,
  536. 0,
  537. NULL,
  538. OPEN_EXISTING,
  539. FILE_ATTRIBUTE_NORMAL,
  540. NULL);
  541. if(hQPipe == INVALID_HANDLE_VALUE) {
  542. dwError = GetLastError();
  543. if (ERROR_FILE_NOT_FOUND == dwError) {
  544. printf("No Remote servers running on \\\\%s\n", pszServer);
  545. } else if (ERROR_BAD_NETPATH == dwError) {
  546. printf("\\\\%s not found on the network\n", pszServer);
  547. } else {
  548. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
  549. FORMAT_MESSAGE_IGNORE_INSERTS,
  550. NULL, dwError, 0,
  551. fullname, sizeof(fullname), NULL);
  552. printf("Can't query server %s: %s\n", pszServer, fullname);
  553. }
  554. return;
  555. }
  556. // Send Query Command
  557. if(!WriteFile(hQPipe, "q", 1, &dwRead, NULL) || (dwRead != 1))
  558. {
  559. fputs("\nError: Can't send command\n", stdout);
  560. goto failure;
  561. }
  562. // read msg dimension
  563. if(!ReadFile(hQPipe, &msgLen, sizeof(int), &dwRead, NULL) || (dwRead != sizeof(int)))
  564. {
  565. fputs("\nError: Can't read message\n", stdout);
  566. goto failure;
  567. }
  568. if(!msgLen)
  569. {
  570. printf("\nNo visible sessions on server %s", pszServer);
  571. goto failure;
  572. }
  573. if(msgLen > 65535) // error
  574. {
  575. printf("Error querying server %s, got %d for msg length, 65535 max.\n",
  576. pszServer,
  577. msgLen
  578. );
  579. goto failure;
  580. }
  581. // +1 for null terminator
  582. if((msg = (char*)malloc( (msgLen +1) *sizeof(char))) == NULL)
  583. {
  584. fputs("\nOut of memory\n", stdout);
  585. goto failure;
  586. }
  587. if (!ReadFile(hQPipe, msg, msgLen * sizeof(char), &dwRead, NULL)) {
  588. fputs("\nUnable to read from pipe\n", stdout);
  589. goto failure;
  590. }
  591. // Make sure the string is terminated
  592. msg[dwRead] = 0;
  593. printf("\nVisible sessions on server %s:\n\n", pszServer);
  594. fputs(msg, stdout);
  595. fputs("\n",stdout);
  596. free(msg);
  597. failure:
  598. CloseHandle(hQPipe);
  599. }