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.

580 lines
15 KiB

  1. /******************************************************************************\
  2. * This is a part of the Microsoft Source Code Samples.
  3. * Copyright 1995 - 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. // remoteds.c, a "directory service" for the limited job of
  12. // finding remote.exe servers on the same domain/workgroup.
  13. //
  14. // Dave Hart written summer 1997.
  15. //
  16. // Copyright 1997 Microsoft Corp.
  17. //
  18. //
  19. // A handy way to use this program is under remote on a single
  20. // or a few machines:
  21. //
  22. // remote /s remoteds FindRemote
  23. //
  24. // Clients connect with remote /c machinename FindRemote
  25. //
  26. // Only remote.exe's running debuggers or with /V+ are visible
  27. // via remoteds, as with remote /q.
  28. //
  29. // Remote clients notify remoteds using mailslots, see srvad.c.
  30. //
  31. //
  32. #include <precomp.h>
  33. typedef char RECEIVEBUF[1024];
  34. typedef struct tagSERVERENTRY {
  35. int nPID; // zero PID means unused slot
  36. union {
  37. FILETIME FileTime;
  38. LARGE_INTEGER liTime;
  39. };
  40. char *pszMachine;
  41. char *pszPipe;
  42. char *pszChildCmd;
  43. } SERVERENTRY;
  44. #define TABLE_INITIAL_ALLOC 1 // 128 // beginning table size
  45. #define TABLE_ALLOC_DELTA 1 // 16 // grows by this many units
  46. HANDLE hTableHeap;
  47. SERVERENTRY *Table;
  48. int nTableSize;
  49. int nTableHiWater; // highest used slot so far
  50. CRITICAL_SECTION csTable;
  51. const char szPrompt[] = "remote server search> ";
  52. unsigned WINAPI InteractThread(void * UnusedParm);
  53. unsigned WINAPI CleanupThread(void * UnusedParm);
  54. VOID __fastcall UpdateTimeStamp(LPFILETIME lpFileTime);
  55. VOID __fastcall ReallocTable(int nNewTableSize);
  56. int
  57. __cdecl
  58. main(
  59. int argc,
  60. char **argv
  61. )
  62. {
  63. char * pszMailslot = "\\\\.\\MAILSLOT\\REMOTE\\DEBUGGERS";
  64. HANDLE hMailslot;
  65. BOOL b;
  66. HANDLE hThread;
  67. DWORD dwTID;
  68. char * pszMachine;
  69. int cchMachine;
  70. char * pszPID;
  71. int nPID;
  72. char * pszPipe;
  73. int cchPipe;
  74. char * pszChildCmd;
  75. int i;
  76. int nFirstAvailable;
  77. BOOL fStopping;
  78. BOOL fFound;
  79. int cb;
  80. char * pchStrings;
  81. char * pch;
  82. DWORD cbRead;
  83. DWORD iBuf;
  84. DWORD rgcbBuf[2];
  85. RECEIVEBUF rgBuf[2];
  86. RECEIVEBUF szBuf;
  87. char szRemoteCmd[512];
  88. InitializeCriticalSection(&csTable);
  89. ReallocTable(TABLE_INITIAL_ALLOC);
  90. hMailslot =
  91. CreateMailslot(
  92. pszMailslot,
  93. 0,
  94. MAILSLOT_WAIT_FOREVER,
  95. NULL
  96. );
  97. if (INVALID_HANDLE_VALUE == hMailslot) {
  98. DWORD dwErr = GetLastError();
  99. if (ERROR_ALREADY_EXISTS == dwErr) {
  100. printf("Cannot receive on %s,\n"
  101. "is remoteds or rdsrelay already running on this machine?\n",
  102. pszMailslot);
  103. } else {
  104. printf("CreateMailslot(%s) failed error %d\n",
  105. pszMailslot,
  106. dwErr);
  107. }
  108. return 2;
  109. }
  110. hThread = (HANDLE) _beginthreadex(
  111. NULL,
  112. 0,
  113. InteractThread,
  114. NULL,
  115. 0,
  116. &dwTID
  117. );
  118. if ( ! hThread) {
  119. printf("Can't start InteractThread %d\n", GetLastError());
  120. return 3;
  121. }
  122. CloseHandle(hThread);
  123. hThread = (HANDLE) _beginthreadex(
  124. NULL,
  125. 0,
  126. CleanupThread,
  127. NULL,
  128. 0,
  129. &dwTID
  130. );
  131. if ( ! hThread) {
  132. printf("Can't start CleanupThread %d\n", GetLastError());
  133. return 3;
  134. }
  135. CloseHandle(hThread);
  136. //
  137. // loop reading and processing mailslot messsages
  138. //
  139. iBuf = 0;
  140. ZeroMemory(rgcbBuf, sizeof(rgcbBuf));
  141. ZeroMemory(rgBuf, sizeof(rgBuf));
  142. while(TRUE)
  143. {
  144. b = ReadFile(
  145. hMailslot,
  146. rgBuf[ iBuf ],
  147. sizeof(rgBuf[ iBuf ]) - 1, // so I can null terminate if needed
  148. &rgcbBuf[ iBuf ],
  149. NULL
  150. );
  151. if ( ! b) {
  152. printf("ReadFile(hMailslot) failed error %d\n", GetLastError());
  153. return 4;
  154. }
  155. //
  156. // It's the nature of mailslots and multiple transports
  157. // that we'll get the identical message several times in
  158. // quick succession. Don't waste time searching the table
  159. // for these duplicates.
  160. //
  161. if ( rgcbBuf[0] == rgcbBuf[1] &&
  162. ! memcmp(rgBuf[0], rgBuf[1], rgcbBuf[0])) {
  163. continue; // duplicate
  164. }
  165. //
  166. // Make a working copy into szBuf/cbRead that we can
  167. // modify so the original buffer is available for
  168. // detecting received duplicates.
  169. //
  170. cbRead = rgcbBuf[ iBuf ];
  171. CopyMemory(szBuf, rgBuf[ iBuf ], cbRead);
  172. //
  173. // Toggle buffers for the next read.
  174. //
  175. iBuf = !iBuf;
  176. if (szBuf[ cbRead - 1 ]) {
  177. fputs("Received string not null terminated.\n", stdout);
  178. szBuf[cbRead] = 0;
  179. }
  180. pszMachine = szBuf;
  181. pch = strchr(szBuf, '\t');
  182. if (!pch) {
  183. fputs("Received string no 1st tab\n", stdout);
  184. continue;
  185. }
  186. *pch = '\0';
  187. pszPID = ++pch;
  188. pch = strchr(pch, '\t');
  189. if (!pch) {
  190. fputs("Received string no 2nd tab\n", stdout);
  191. continue;
  192. }
  193. *pch = '\0';
  194. pszPipe = ++pch;
  195. pch = strchr(pch, '\t');
  196. if (!pch) {
  197. fputs("Received string no 3nd tab\n", stdout);
  198. continue;
  199. }
  200. *pch = '\0';
  201. pszChildCmd = ++pch;
  202. //
  203. // If it ends with ^B it's going away.
  204. //
  205. pch = strchr(pch, '\x2');
  206. if (pch) {
  207. *pch = 0;
  208. fStopping = TRUE;
  209. } else {
  210. fStopping = FALSE;
  211. }
  212. nPID = strtol(pszPID, NULL, 10);
  213. _strlwr(pszMachine);
  214. _strlwr(pszPipe);
  215. if (fStopping) {
  216. //
  217. // display the ending remote's info
  218. //
  219. ZeroMemory(szRemoteCmd, sizeof(szRemoteCmd));
  220. _snprintf(szRemoteCmd, sizeof(szRemoteCmd), "remote /c %s %s", pszMachine, pszPipe);
  221. printf("\r%-36s %-20s [stop]\n%s", szRemoteCmd, pszChildCmd, szPrompt);
  222. fflush(stdout);
  223. }
  224. EnterCriticalSection(&csTable);
  225. nFirstAvailable = -1;
  226. for (i = 0, fFound = FALSE;
  227. i <= nTableHiWater;
  228. i++) {
  229. if (-1 == nFirstAvailable && 0 == Table[i].nPID) {
  230. nFirstAvailable = i;
  231. }
  232. if (Table[i].nPID == nPID &&
  233. ! strcmp(Table[i].pszMachine, pszMachine) &&
  234. ! strcmp(Table[i].pszPipe, pszPipe)) {
  235. fFound = TRUE;
  236. break;
  237. }
  238. }
  239. if (fFound) {
  240. if (fStopping) {
  241. //
  242. // Remove it from the table
  243. //
  244. free(Table[i].pszMachine);
  245. ZeroMemory(&Table[i], sizeof(Table[i]));
  246. if (nTableHiWater == i) {
  247. nTableHiWater--;
  248. }
  249. } else { // starting
  250. // printf("Found at slot %d\n", i);
  251. // timestamp is updated below
  252. }
  253. } else if ( ! fStopping) {
  254. //
  255. // we have a new entry, display it
  256. //
  257. ZeroMemory(szRemoteCmd, sizeof(szRemoteCmd));
  258. _snprintf(szRemoteCmd, sizeof(szRemoteCmd), "remote /c %s %s", pszMachine, pszPipe);
  259. printf("\r%-36s %-20s [start]\n%s", szRemoteCmd, pszChildCmd, szPrompt);
  260. fflush(stdout);
  261. //
  262. // Does it fit in the table or do we need to grow it?
  263. //
  264. if (-1 == nFirstAvailable) {
  265. if (++nTableHiWater >= nTableSize) {
  266. ReallocTable(nTableSize + TABLE_ALLOC_DELTA);
  267. }
  268. i = nTableHiWater;
  269. } else {
  270. i = nFirstAvailable;
  271. }
  272. //
  273. // Fill in a server entry in table, if we can
  274. // allocate memory for the strings.
  275. //
  276. cb = (cchMachine = strlen(pszMachine) + 1) +
  277. (cchPipe = strlen(pszPipe) + 1) +
  278. ( strlen(pszChildCmd) + 1);
  279. pchStrings = malloc(cb);
  280. if (pchStrings) {
  281. Table[i].nPID = nPID;
  282. UpdateTimeStamp(&Table[i].FileTime);
  283. Table[i].pszMachine = pchStrings;
  284. strcpy(Table[i].pszMachine, pszMachine);
  285. Table[i].pszPipe = Table[i].pszMachine + cchMachine;
  286. strcpy(Table[i].pszPipe, pszPipe);
  287. Table[i].pszChildCmd = Table[i].pszPipe + cchPipe;
  288. strcpy(Table[i].pszChildCmd, pszChildCmd);
  289. }
  290. }
  291. UpdateTimeStamp(&Table[i].FileTime);
  292. LeaveCriticalSection(&csTable);
  293. } // while (TRUE)
  294. return 0; // never executed
  295. }
  296. //
  297. // InteractThread lets the user query the list of remote servers.
  298. //
  299. unsigned WINAPI InteractThread(void * UnusedParm)
  300. {
  301. char szQuery[1024] = {0};
  302. char szLowerQuery[1024] = {0};
  303. char szRemoteCmd[400];
  304. int i;
  305. BOOL fAll;
  306. while (TRUE) {
  307. fputs(szPrompt, stdout);
  308. fflush(stdout);
  309. if (!fgets(szQuery, sizeof(szQuery), stdin))
  310. continue;
  311. _strlwr( strcpy(szLowerQuery, szQuery) );
  312. if (!strlen(szLowerQuery) ||
  313. !strcmp(szLowerQuery, "?") ||
  314. !strcmp(szLowerQuery, "h") ||
  315. !strcmp(szLowerQuery, "help")) {
  316. fputs("Enter a string to search for, a machine or pipe name or command.\n"
  317. "Enter * to list all remote servers.\n"
  318. "Exit with ^B.\n",
  319. stdout);
  320. continue;
  321. }
  322. if (2 == szLowerQuery[0]) { // ^B
  323. ExitProcess(0);
  324. }
  325. fAll = ! strcmp(szLowerQuery, "*");
  326. EnterCriticalSection(&csTable);
  327. for (i = 0; i <= nTableHiWater; i++) {
  328. if (Table[i].nPID) {
  329. if (fAll ||
  330. strstr(Table[i].pszMachine, szLowerQuery) ||
  331. strstr(Table[i].pszPipe, szLowerQuery) ||
  332. strstr(Table[i].pszChildCmd, szLowerQuery)) {
  333. ZeroMemory(szRemoteCmd, sizeof(szRemoteCmd));
  334. _snprintf(szRemoteCmd, sizeof(szRemoteCmd), "remote /c %s %s", Table[i].pszMachine, Table[i].pszPipe);
  335. printf("%-40s %s\n", szRemoteCmd, Table[i].pszChildCmd);
  336. }
  337. }
  338. }
  339. LeaveCriticalSection(&csTable);
  340. }
  341. return 0; // never executed
  342. }
  343. #if _MSC_FULL_VER >= 13008827
  344. #pragma warning(push)
  345. #pragma warning(disable:4715) // Not all control paths return (due to infinite loop)
  346. #endif
  347. //
  348. // CleanupThread scavenges for old entries and frees them.
  349. // remote /s sends a broadcast at least every 2 hours.
  350. // We get some of them. Age out entries after 12 hours.
  351. //
  352. unsigned WINAPI CleanupThread(void * UnusedParm)
  353. {
  354. LARGE_INTEGER liNow;
  355. LARGE_INTEGER liTimeout;
  356. int i;
  357. char szRemoteCmd[400];
  358. liTimeout.QuadPart = (LONGLONG)10000000 * 60 * 60 * 12; // 12 hours
  359. while (TRUE) {
  360. Sleep(15 * 60 * 1000); // 10 minutes
  361. UpdateTimeStamp((LPFILETIME)&liNow);
  362. EnterCriticalSection(&csTable);
  363. for (i = nTableHiWater; i >= 0; i--) {
  364. if (Table[i].nPID) {
  365. if (liNow.QuadPart - Table[i].liTime.QuadPart > liTimeout.QuadPart) {
  366. //
  367. // display the ending remote's info
  368. //
  369. ZeroMemory(szRemoteCmd, sizeof(szRemoteCmd));
  370. _snprintf(szRemoteCmd, sizeof(szRemoteCmd), "remote /c %s %s", Table[i].pszMachine, Table[i].pszPipe);
  371. printf("\r%-36s %-20s [aged out]\n%s", szRemoteCmd, Table[i].pszChildCmd, szPrompt);
  372. fflush(stdout);
  373. free(Table[i].pszMachine);
  374. ZeroMemory(&Table[i], sizeof(Table[i]));
  375. if (nTableHiWater == i) {
  376. nTableHiWater--;
  377. }
  378. }
  379. }
  380. }
  381. LeaveCriticalSection(&csTable);
  382. }
  383. return 0; // never executed
  384. }
  385. #if _MSC_FULL_VER >= 13008827
  386. #pragma warning(pop)
  387. #endif
  388. VOID __fastcall UpdateTimeStamp(LPFILETIME lpFileTime)
  389. {
  390. SYSTEMTIME SystemTime;
  391. GetSystemTime(&SystemTime);
  392. SystemTimeToFileTime(&SystemTime, lpFileTime);
  393. }
  394. VOID __fastcall ReallocTable(int nNewTableSize)
  395. {
  396. SERVERENTRY *pTableSave = Table;
  397. EnterCriticalSection(&csTable);
  398. nTableSize = nNewTableSize;
  399. if ( ! hTableHeap) {
  400. hTableHeap = HeapCreate(
  401. HEAP_NO_SERIALIZE,
  402. (TABLE_INITIAL_ALLOC + 1) * sizeof(Table[0]), // size
  403. 50000 * sizeof(Table[0]) // max
  404. );
  405. if (hTableHeap)
  406. Table = HeapAlloc(
  407. hTableHeap,
  408. HEAP_ZERO_MEMORY,
  409. nTableSize * sizeof(Table[0])
  410. );
  411. else
  412. Table = NULL;
  413. if (!Table) {
  414. fputs("\nremoteds: Out of memory allocating remote server table\n", stdout);
  415. exit(ERROR_NOT_ENOUGH_MEMORY);
  416. }
  417. } else {
  418. void *pv = HeapReAlloc(
  419. hTableHeap,
  420. HEAP_ZERO_MEMORY,
  421. Table,
  422. nTableSize * sizeof(Table[0])
  423. );
  424. if (!pv) {
  425. fputs("\nremoteds: Out of memory allocating remote server table\n", stdout);
  426. exit(ERROR_NOT_ENOUGH_MEMORY);
  427. } else {
  428. Table = pv;
  429. }
  430. }
  431. LeaveCriticalSection(&csTable);
  432. if (Table != pTableSave && pTableSave) {
  433. printf("\nremoteds: remote server table moved in HeapRealloc from %p to %p.\n", pTableSave, Table);
  434. fflush(stdout);
  435. }
  436. }