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.

1255 lines
37 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. Copyright (c) 1997 Microsoft Corporation
  12. Module Name:
  13. SrvUtil.c
  14. Abstract:
  15. The server component of Remote. It spawns a child process
  16. and redirects the stdin/stdout/stderr of child to itself.
  17. Waits for connections from clients - passing the
  18. output of child process to client and the input from clients
  19. to child process.
  20. Author:
  21. Rajivendra Nath 2-Jan-1992
  22. Dave Hart 30 May 1997 split from Server.c
  23. Environment:
  24. Console App. User mode.
  25. Revision History:
  26. --*/
  27. #include <precomp.h>
  28. #include "Remote.h"
  29. #include "Server.h"
  30. #include <sddl.h>
  31. #define DEFAULT_SECURITY_DESCRIPTOR L"D:(A;;FA;;;BA)(A;;FA;;;CO)(A;;0x1301bf;;;WD)"
  32. #define REGISTRY_PATH L"Software\\Microsoft\\Remote"
  33. #define REGISTRY_VALUE L"DefaultSecurity"
  34. #define COMMANDFORMAT "%c%-20s [%-12s %s]\n%08x%c"
  35. #define CMDSTRING(OutBuff,OutSize,InpBuff,Client,szTime,ForceShow) \
  36. { \
  37. char *pch; \
  38. \
  39. for (pch = InpBuff; \
  40. *pch; \
  41. pch++) { \
  42. \
  43. if (ENDMARK == *pch || \
  44. BEGINMARK == *pch) { \
  45. \
  46. *pch = '`'; \
  47. } \
  48. } \
  49. \
  50. OutSize = \
  51. sprintf( \
  52. (OutBuff), \
  53. COMMANDFORMAT, \
  54. BEGINMARK, \
  55. (InpBuff), \
  56. (Client)->Name, \
  57. (szTime), \
  58. (ForceShow) ? 0 : (Client)->dwID, \
  59. ENDMARK \
  60. ); \
  61. }
  62. /*************************************************************/
  63. // GetFormattedTime -- returns pointer to formatted time
  64. //
  65. // returns pointer to static buffer, only the main thread
  66. // should use this.
  67. //
  68. PCHAR
  69. GetFormattedTime(
  70. BOOL bDateToo
  71. )
  72. {
  73. static char szTime[64];
  74. int cch = 0;
  75. if (bDateToo) {
  76. cch =
  77. GetDateFormat(
  78. LOCALE_USER_DEFAULT,
  79. 0,
  80. NULL, // current date
  81. "ddd", // short day of week
  82. szTime,
  83. sizeof szTime
  84. );
  85. // cch includes null terminator, change it to
  86. // a space to separate from time.
  87. szTime[ cch - 1 ] = ' ';
  88. }
  89. //
  90. // Get time and format to characters
  91. //
  92. GetTimeFormat(
  93. LOCALE_USER_DEFAULT,
  94. TIME_NOSECONDS,
  95. NULL, // use current time
  96. NULL, // use default format
  97. szTime + cch,
  98. (sizeof szTime) - cch );
  99. return szTime;
  100. }
  101. /*************************************************************/
  102. BOOL
  103. FilterCommand(
  104. REMOTE_CLIENT *cl,
  105. char *buff,
  106. int dread
  107. )
  108. {
  109. char tmpchar;
  110. DWORD tmp;
  111. int len, i;
  112. DWORD ThreadID;
  113. char inp_buff[2048];
  114. char ch[3];
  115. if (dread==0)
  116. return(FALSE);
  117. buff[dread]=0;
  118. if (buff[0]==COMMANDCHAR)
  119. {
  120. switch(buff[1]) {
  121. case 'k':
  122. case 'K':
  123. if (INVALID_HANDLE_VALUE != hWriteChildStdIn) {
  124. printf("Remote: killing child softly, @K again to be more convincing.\n");
  125. CancelIo( hWriteChildStdIn );
  126. CloseHandle( hWriteChildStdIn );
  127. hWriteChildStdIn = INVALID_HANDLE_VALUE;
  128. GenerateConsoleCtrlEvent(CTRL_CLOSE_EVENT, 0);
  129. SleepEx(200, TRUE);
  130. cPendingCtrlCEvents++;
  131. GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
  132. SleepEx(20, TRUE);
  133. GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);
  134. } else {
  135. printf("Remote: Resorting to TerminateProcess.\n");
  136. TerminateProcess(ChldProc, ERROR_PROCESS_ABORTED);
  137. }
  138. break;
  139. case 's':
  140. case 'S':
  141. CloseHandle( (HANDLE)
  142. _beginthreadex(
  143. NULL, // security
  144. 0, // default stack size
  145. SendStatus,
  146. (void *) cl->PipeWriteH,
  147. 0, // not suspended
  148. &ThreadID
  149. ));
  150. break;
  151. case 'p':
  152. case 'P':
  153. {
  154. char *msg;
  155. msg = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 4096 );
  156. if ( ! msg) {
  157. break;
  158. }
  159. sprintf(msg,"From %s %s [%s]\n\n%s\n",cl->Name,cl->UserName,GetFormattedTime(TRUE),&buff[2]);
  160. if (WriteFileSynch(hWriteTempFile,msg,strlen(msg),&tmp,dwWriteFilePointer,&olMainThread)) {
  161. dwWriteFilePointer += tmp;
  162. StartServerToClientFlow();
  163. }
  164. CloseHandle( (HANDLE)
  165. CreateThread( // no CRT for ShowPopup
  166. NULL, // security
  167. 0, // default stack size
  168. ShowPopup,
  169. (void *) msg,
  170. 0, // not suspended
  171. &ThreadID
  172. ));
  173. break;
  174. }
  175. case 'm':
  176. case 'M':
  177. buff[dread-2]=0;
  178. CMDSTRING(inp_buff,len,buff,cl,GetFormattedTime(TRUE),TRUE);
  179. if (WriteFileSynch(hWriteTempFile,inp_buff,len,&tmp,dwWriteFilePointer,&olMainThread)) {
  180. dwWriteFilePointer += tmp;
  181. StartServerToClientFlow();
  182. }
  183. break;
  184. case '@':
  185. buff[dread-2]=0;
  186. CMDSTRING(inp_buff,len,&buff[1],cl,GetFormattedTime(FALSE),FALSE);
  187. if (WriteFileSynch(hWriteTempFile,inp_buff,len,&tmp,dwWriteFilePointer,&olMainThread)) {
  188. dwWriteFilePointer += tmp;
  189. StartServerToClientFlow();
  190. }
  191. //
  192. // Remove the first @ sign
  193. //
  194. MoveMemory(buff,&buff[1],dread-1);
  195. buff[dread-1]=' ';
  196. return(FALSE); //Send it it to the chile process
  197. default :
  198. ZeroMemory(inp_buff, sizeof(inp_buff));
  199. strncpy(inp_buff, "** Unknown Command **\n", sizeof(inp_buff)-1);
  200. if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
  201. dwWriteFilePointer += tmp;
  202. // we do this below // StartServerToClientFlow();
  203. }
  204. case 'h':
  205. case 'H':
  206. _snprintf(inp_buff,sizeof(inp_buff), "%cM: To Send Message\n",COMMANDCHAR);
  207. if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
  208. dwWriteFilePointer += tmp;
  209. }
  210. _snprintf(inp_buff,sizeof(inp_buff), "%cP: To Generate popup\n",COMMANDCHAR);
  211. if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
  212. dwWriteFilePointer += tmp;
  213. }
  214. _snprintf(inp_buff,sizeof(inp_buff), "%cK: To kill the server\n",COMMANDCHAR);
  215. if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
  216. dwWriteFilePointer += tmp;
  217. }
  218. _snprintf(inp_buff,sizeof(inp_buff), "%cQ: To Quit client\n",COMMANDCHAR);
  219. if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
  220. dwWriteFilePointer += tmp;
  221. }
  222. _snprintf(inp_buff,sizeof(inp_buff), "%cH: This Help\n",COMMANDCHAR);
  223. if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
  224. dwWriteFilePointer += tmp;
  225. }
  226. StartServerToClientFlow();
  227. break;
  228. }
  229. return(TRUE);
  230. }
  231. if ((buff[0]<26)) {
  232. BOOL ret=FALSE;
  233. _snprintf(ch, sizeof(ch), "^%c", buff[0] + 'A' - 1);
  234. if (buff[0]==CTRLC) {
  235. // show this even to this client
  236. CMDSTRING(inp_buff,len,ch,cl,GetFormattedTime(FALSE),TRUE);
  237. cPendingCtrlCEvents++;
  238. GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
  239. ret = TRUE; // Already sent to child
  240. } else {
  241. CMDSTRING(inp_buff,len,ch,cl,GetFormattedTime(FALSE),FALSE);
  242. }
  243. if (WriteFileSynch(hWriteTempFile,inp_buff,len,&tmp,dwWriteFilePointer,&olMainThread)) {
  244. dwWriteFilePointer += tmp;
  245. StartServerToClientFlow();
  246. }
  247. return(ret); //FALSE:send it to child StdIn
  248. }
  249. // options here are CRLF(\r\n) or just LF(\n)
  250. if (buff[dread-2] == 13) {
  251. i = 2; // 13 is CR
  252. } else {
  253. i = 1;
  254. }
  255. tmpchar=buff[dread-i];
  256. buff[dread-i]=0;
  257. CMDSTRING(inp_buff,len,buff,cl,GetFormattedTime(FALSE),FALSE);
  258. buff[dread-i]=tmpchar;
  259. if (WriteFileSynch(hWriteTempFile,inp_buff,len,&tmp,dwWriteFilePointer,&olMainThread)) {
  260. dwWriteFilePointer += tmp;
  261. StartServerToClientFlow();
  262. }
  263. return(FALSE);
  264. }
  265. /*************************************************************/
  266. HANDLE
  267. ForkChildProcess( // Creates a new process
  268. char *cmd, // Redirects its stdin,stdout
  269. PHANDLE inH, // and stderr - returns the
  270. PHANDLE outH // corresponding pipe ends.
  271. )
  272. {
  273. SECURITY_ATTRIBUTES lsa;
  274. STARTUPINFO si;
  275. PROCESS_INFORMATION pi;
  276. HANDLE ChildIn;
  277. HANDLE ChildOut, ChildOutDup;
  278. HANDLE hWriteChild;
  279. HANDLE hReadChild;
  280. BOOL Success;
  281. BOOL // pipeex.c
  282. APIENTRY
  283. MyCreatePipeEx(
  284. OUT LPHANDLE lpReadPipe,
  285. OUT LPHANDLE lpWritePipe,
  286. IN LPSECURITY_ATTRIBUTES lpPipeAttributes,
  287. IN DWORD nSize,
  288. DWORD dwReadMode,
  289. DWORD dwWriteMode
  290. );
  291. lsa.nLength=sizeof(SECURITY_ATTRIBUTES);
  292. lsa.lpSecurityDescriptor=NULL;
  293. lsa.bInheritHandle=TRUE;
  294. //
  295. // Create Parent_Write to ChildStdIn Pipe. Then
  296. // duplicate the parent copy to a noninheritable
  297. // handle and close the inheritable one so that
  298. // the child won't be holding open a handle to
  299. // the server end of its stdin pipe when we try
  300. // to nuke that pipe to close the child.
  301. //
  302. Success = MyCreatePipeEx(
  303. &ChildIn,
  304. &hWriteChild,
  305. &lsa,
  306. 0,
  307. 0,
  308. FILE_FLAG_OVERLAPPED) &&
  309. DuplicateHandle(
  310. GetCurrentProcess(),
  311. hWriteChild,
  312. GetCurrentProcess(),
  313. inH,
  314. 0, // ignored b/c SAME_ACCESS
  315. FALSE, // not inheritable
  316. DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE
  317. );
  318. if (!Success) {
  319. ErrorExit("Could Not Create Parent-->Child Pipe");
  320. }
  321. //
  322. //Create ChildStdOut/stderr to Parent_Read pipe
  323. //
  324. Success = MyCreatePipeEx(
  325. &hReadChild,
  326. &ChildOut,
  327. &lsa,
  328. 0,
  329. FILE_FLAG_OVERLAPPED,
  330. 0) &&
  331. DuplicateHandle(
  332. GetCurrentProcess(),
  333. hReadChild,
  334. GetCurrentProcess(),
  335. outH,
  336. 0, // ignored b/c SAME_ACCESS
  337. FALSE, // not inheritable
  338. DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE
  339. ) &&
  340. DuplicateHandle(
  341. GetCurrentProcess(),
  342. ChildOut,
  343. GetCurrentProcess(),
  344. &ChildOutDup,
  345. 0, // ignored b/c SAME_ACCESS
  346. TRUE, // inheritable
  347. DUPLICATE_SAME_ACCESS
  348. );
  349. if (!Success) {
  350. ErrorExit("Could Not Create Child-->Parent Pipe");
  351. }
  352. ZeroMemory(&si, sizeof(si));
  353. si.cb = sizeof(STARTUPINFO);
  354. si.dwFlags = STARTF_USESTDHANDLES;
  355. si.hStdInput = ChildIn;
  356. si.hStdOutput = ChildOut;
  357. si.hStdError = ChildOutDup;
  358. si.wShowWindow = SW_SHOW;
  359. //
  360. // Create Child Process
  361. //
  362. if ( ! CreateProcess(
  363. NULL,
  364. cmd,
  365. NULL,
  366. NULL,
  367. TRUE,
  368. GetPriorityClass( GetCurrentProcess() ),
  369. NULL,
  370. NULL,
  371. &si,
  372. &pi)) {
  373. if (GetLastError()==2) {
  374. printf("Executable %s not found\n",cmd);
  375. } else {
  376. printf("CreateProcess(%s) failed, error %d.\n", cmd, GetLastError());
  377. }
  378. ErrorExit("Could Not Create Child Process");
  379. }
  380. //
  381. // Close unneccesary Handles
  382. //
  383. CloseHandle(ChildIn);
  384. CloseHandle(ChildOut);
  385. CloseHandle(ChildOutDup);
  386. CloseHandle(pi.hThread);
  387. pidChild = pi.dwProcessId;
  388. return(pi.hProcess);
  389. }
  390. //
  391. // SendStatus runs as its own thread, with C runtime available.
  392. //
  393. DWORD
  394. WINAPI
  395. SendStatus(
  396. LPVOID lpSendStatusParm
  397. )
  398. {
  399. HANDLE hClientPipe = (HANDLE) lpSendStatusParm;
  400. char *pch;
  401. DWORD tmp;
  402. PREMOTE_CLIENT pClient;
  403. OVERLAPPED ol;
  404. char buff[2048];
  405. char szSep[] = " ------------------------------\n";
  406. //
  407. // Since we're in our own thread we need our own
  408. // overlapped structure for our client pipe writes.
  409. //
  410. ZeroMemory(&ol, sizeof(ol));
  411. ol.hEvent = CreateEvent(
  412. NULL, // security
  413. TRUE, // auto-reset
  414. FALSE, // initially nonsignaled
  415. NULL // unnamed
  416. );
  417. //
  418. // Dump the closing client list
  419. //
  420. pch = buff;
  421. EnterCriticalSection(&csClosingClientList);
  422. for (pClient = (PREMOTE_CLIENT) ClosingClientListHead.Flink;
  423. pClient != (PREMOTE_CLIENT) &ClosingClientListHead;
  424. pClient = (PREMOTE_CLIENT) pClient->Links.Flink ) {
  425. if (pch + 60 > buff + sizeof(buff)) {
  426. break;
  427. }
  428. pch += sprintf(pch, "%d: %s %s (Disconnected)\n", pClient->dwID, pClient->Name, pClient->UserName);
  429. }
  430. LeaveCriticalSection(&csClosingClientList);
  431. WriteFileSynch(hClientPipe, buff, (DWORD)(pch - buff), &tmp, 0, &ol);
  432. WriteFileSynch(hClientPipe, szSep, sizeof(szSep) - 1, &tmp, 0, &ol);
  433. //
  434. // Dump the normal client list
  435. //
  436. pch = buff;
  437. EnterCriticalSection(&csClientList);
  438. for (pClient = (PREMOTE_CLIENT) ClientListHead.Flink;
  439. pClient != (PREMOTE_CLIENT) &ClientListHead;
  440. pClient = (PREMOTE_CLIENT) pClient->Links.Flink ) {
  441. if (pch + 60 > buff + sizeof(buff)) {
  442. break;
  443. }
  444. pch += sprintf(pch, "%d: %s %s\n", pClient->dwID, pClient->Name, pClient->UserName);
  445. }
  446. LeaveCriticalSection(&csClientList);
  447. WriteFileSynch(hClientPipe, buff, (DWORD)(pch - buff), &tmp, 0, &ol);
  448. WriteFileSynch(hClientPipe, szSep, sizeof(szSep) - 1, &tmp, 0, &ol);
  449. //
  450. // Dump the handshaking client list
  451. //
  452. pch = buff;
  453. EnterCriticalSection(&csHandshakingList);
  454. for (pClient = (PREMOTE_CLIENT) HandshakingListHead.Flink;
  455. pClient != (PREMOTE_CLIENT) &HandshakingListHead;
  456. pClient = (PREMOTE_CLIENT) pClient->Links.Flink ) {
  457. if (pch + 60 > buff + sizeof(buff)) {
  458. break;
  459. }
  460. pch += sprintf(pch, "%d: %s %s (Connecting)\n", pClient->dwID, pClient->Name, pClient->UserName);
  461. }
  462. LeaveCriticalSection(&csHandshakingList);
  463. WriteFileSynch(hClientPipe, buff, (DWORD)(pch - buff), &tmp, 0, &ol);
  464. WriteFileSynch(hClientPipe, szSep, sizeof(szSep) - 1, &tmp, 0, &ol);
  465. //
  466. // Dump summary information.
  467. //
  468. pch = buff;
  469. pch += sprintf(pch, "REMOTE /C %s \"%s\"\n", HostName, PipeName);
  470. pch += sprintf(pch, "Command: %s\n", ChildCmd);
  471. pch += sprintf(pch, "Windows NT %d.%d build %d \n",
  472. OsVersionInfo.dwMajorVersion,
  473. OsVersionInfo.dwMinorVersion,
  474. OsVersionInfo.dwBuildNumber);
  475. WriteFileSynch(hClientPipe, buff, (DWORD)(pch - buff), &tmp, 0, &ol);
  476. WriteFileSynch(hClientPipe, szSep, sizeof(szSep) - 1, &tmp, 0, &ol);
  477. CloseHandle(ol.hEvent);
  478. return 0;
  479. }
  480. /*************************************************************/
  481. DWORD // NO CRT for ShowPopup
  482. WINAPI
  483. ShowPopup(
  484. void *vpArg
  485. )
  486. {
  487. char *msg = (char *) vpArg;
  488. MessageBox(GetActiveWindow(),msg,"** REMOTE.EXE **",MB_OK|MB_SETFOREGROUND);
  489. HeapFree(hHeap, 0, msg);
  490. return(0);
  491. }
  492. /*************************************************************/
  493. //
  494. // SrvCtrlHand is the console event handler for the server side
  495. // of remote. If our stdin is a console handle, we've disabled
  496. // generation of ^C events by the console code. Therefore
  497. // any we see are either generated by us for the benefit of
  498. // our child processes sharing the console, or generated by
  499. // some other process. We want to ignore the ones we generate
  500. // (since we're already done with everything that needs to be
  501. // done at that point), and also ignore ^C's generated by
  502. // other processes since we don't need to do anything with those.
  503. // For example if someone runs:
  504. //
  505. // remote /s "remote /s cmd inner" outer
  506. //
  507. // Then local keyboard ^C's will be read by the outer remote.exe
  508. // from its stdin handle, then it will generate a CTRL_C_EVENT that
  509. // all processes in the console will see, including both remote.exe's
  510. // and the child cmd.exe. So the handler needs do nothing but indicate
  511. // the event was handled by returning TRUE so the default handler
  512. // won't kill us. For ^BREAK we want to specifically kill our child
  513. // process so that cmd.exe and others that ignore ^BREAK will go away.
  514. // Of course this won't kill our grandchildren and so on. Oh well.
  515. //
  516. // For all other events we return FALSE and let the default handler
  517. // have it.
  518. //
  519. BOOL
  520. WINAPI
  521. SrvCtrlHand(
  522. DWORD event
  523. )
  524. {
  525. BOOL bRet = FALSE;
  526. DWORD cb;
  527. DWORD dwTempFileOffset;
  528. OVERLAPPED ol;
  529. char szTime[64];
  530. char szCmd[128];
  531. if (event == CTRL_BREAK_EVENT) {
  532. TerminateProcess(ChldProc, 3);
  533. bRet = TRUE;
  534. } else if (event == CTRL_C_EVENT) {
  535. if ( ! cPendingCtrlCEvents ) {
  536. //
  537. // This came from the local keyboard or
  538. // was generated by another process in
  539. // this console. Echo it as a local
  540. // command. We have use GetTimeFormat
  541. // here not our GetFormattedTime since
  542. // the latter is for the use of the
  543. // main thread only.
  544. //
  545. GetTimeFormat(
  546. LOCALE_USER_DEFAULT,
  547. TIME_NOSECONDS,
  548. NULL, // use current time
  549. NULL, // use default format
  550. szTime,
  551. sizeof(szTime)
  552. );
  553. CMDSTRING(szCmd, cb, "^C", pLocalClient, szTime, TRUE);
  554. ZeroMemory(&ol, sizeof(ol));
  555. ol.hEvent =
  556. CreateEvent(
  557. NULL, // security
  558. TRUE, // auto-reset
  559. FALSE, // initially nonsignaled
  560. NULL // unnamed
  561. );
  562. //
  563. // Practically all writes to the tempfile are happening on
  564. // the primary server thread. We're on a Ctrl-C thread.
  565. // We can't start the server to client I/O going after
  566. // writing because we're on the wrong thread, so we
  567. // punt. To fix this we need an event we can signal
  568. // that causes the main thread to call StartServerToClientFlow.
  569. //
  570. dwTempFileOffset = dwWriteFilePointer;
  571. dwWriteFilePointer += cb;
  572. WriteFileSynch(hWriteTempFile, szCmd, cb, &cb, dwTempFileOffset, &ol);
  573. // wrong thread // StartServerToClientFlow();
  574. CloseHandle(ol.hEvent);
  575. } else {
  576. //
  577. // We generated this event in response to a ^C received from
  578. // a client, it's already been displayed to all clients.
  579. //
  580. cPendingCtrlCEvents--;
  581. }
  582. bRet = TRUE;
  583. }
  584. return bRet;
  585. }
  586. /*************************************************************/
  587. typedef BOOL (STRINGSDTOSDW)(
  588. LPWSTR String,
  589. DWORD Version,
  590. PSECURITY_DESCRIPTOR * pSD,
  591. PULONG SDSize
  592. );
  593. typedef STRINGSDTOSDW * PSTRINGSDTOSDW ;
  594. typedef BOOL (SDTOSTRINGSDW)(
  595. PSECURITY_DESCRIPTOR SD,
  596. DWORD StringVersion,
  597. SECURITY_INFORMATION SecInfo,
  598. LPWSTR * StringDescriptor,
  599. PULONG Size
  600. );
  601. typedef SDTOSTRINGSDW * PSDTOSTRINGSDW ;
  602. BOOL
  603. SddlToSecurityDescriptor(
  604. LPWSTR String,
  605. DWORD Version,
  606. PSECURITY_DESCRIPTOR * pSD,
  607. PULONG SDSize
  608. )
  609. {
  610. HMODULE hModule ;
  611. PSTRINGSDTOSDW pStringSecurityDescriptorToSecurityDescriptor ;
  612. BOOL Success = FALSE ;
  613. PSECURITY_DESCRIPTOR sd ;
  614. hModule = GetModuleHandle( "advapi32.dll" );
  615. if ( hModule )
  616. {
  617. pStringSecurityDescriptorToSecurityDescriptor = (PSTRINGSDTOSDW) GetProcAddress(
  618. hModule, "ConvertStringSecurityDescriptorToSecurityDescriptorW" );
  619. if ( pStringSecurityDescriptorToSecurityDescriptor )
  620. {
  621. Success = pStringSecurityDescriptorToSecurityDescriptor( String, Version, pSD, SDSize);
  622. return Success ;
  623. }
  624. }
  625. sd = LocalAlloc( LMEM_FIXED, sizeof( SECURITY_DESCRIPTOR ) );
  626. if ( sd )
  627. {
  628. InitializeSecurityDescriptor(
  629. sd,
  630. SECURITY_DESCRIPTOR_REVISION
  631. );
  632. SetSecurityDescriptorDacl(
  633. sd,
  634. TRUE,
  635. NULL,
  636. FALSE
  637. );
  638. *pSD = sd ;
  639. if ( SDSize )
  640. {
  641. *SDSize = sizeof( SECURITY_DESCRIPTOR );
  642. }
  643. return TRUE ;
  644. }
  645. return FALSE ;
  646. }
  647. /*************************************************************/
  648. BOOL
  649. SDtoStringSD(
  650. PSECURITY_DESCRIPTOR pSD,
  651. DWORD Version,
  652. SECURITY_INFORMATION SecInfo,
  653. LPWSTR * StringSD,
  654. PULONG StringSize
  655. )
  656. {
  657. HMODULE hModule ;
  658. PSDTOSTRINGSDW pSDtoStringSD ;
  659. BOOL Success = FALSE ;
  660. hModule = GetModuleHandle( "advapi32.dll" );
  661. if ( hModule )
  662. {
  663. pSDtoStringSD = (PSDTOSTRINGSDW) GetProcAddress(
  664. hModule, "ConvertSecurityDescriptorToStringSecurityDescriptorW" );
  665. if ( pSDtoStringSD )
  666. {
  667. Success = pSDtoStringSD(pSD, Version, SecInfo, StringSD, StringSize );
  668. FreeLibrary( hModule );
  669. return Success ;
  670. }
  671. }
  672. return FALSE ;
  673. }
  674. /*************************************************************/
  675. PSECURITY_DESCRIPTOR
  676. FormatSecurityDescriptor(
  677. CHAR * * DenyNames,
  678. DWORD DenyCount,
  679. CHAR * * Names,
  680. DWORD Count)
  681. {
  682. PSECURITY_DESCRIPTOR Sd;
  683. PACL Acl;
  684. DWORD i;
  685. PSID Sids;
  686. DWORD SidLength ;
  687. CHAR ReferencedDomain[ MAX_PATH ];
  688. UCHAR SidBuffer[ 8 * sizeof(DWORD) + 8 ];
  689. DWORD DomainLen ;
  690. SID_NAME_USE Use;
  691. DWORD SdLen;
  692. SdLen = sizeof(SECURITY_DESCRIPTOR) +
  693. DenyCount * (sizeof( ACCESS_DENIED_ACE ) ) +
  694. DenyCount * GetSidLengthRequired( 8 ) +
  695. Count * (sizeof( ACCESS_ALLOWED_ACE ) ) + sizeof(ACL) +
  696. (Count * GetSidLengthRequired( 8 ) );
  697. Sd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SdLen );
  698. if ( !Sd ) {
  699. ErrorExit("Could not allocate SD");
  700. }
  701. InitializeSecurityDescriptor( Sd, SECURITY_DESCRIPTOR_REVISION );
  702. Acl = (PACL)( (PUCHAR) Sd + sizeof( SECURITY_DESCRIPTOR) );
  703. InitializeAcl( Acl, SdLen - sizeof( SECURITY_DESCRIPTOR) ,
  704. ACL_REVISION );
  705. Sids = SidBuffer;
  706. for (i = 0 ; i < DenyCount ; i ++ ) {
  707. SidLength = sizeof( SidBuffer );
  708. DomainLen = MAX_PATH ;
  709. if (! LookupAccountName(NULL,
  710. DenyNames[ i ],
  711. Sids,
  712. &SidLength,
  713. ReferencedDomain,
  714. &DomainLen,
  715. &Use ) )
  716. {
  717. _snprintf( ReferencedDomain, MAX_PATH, "Unable to find account %s", DenyNames[ i ]);
  718. ErrorExit( ReferencedDomain );
  719. }
  720. //
  721. // Got the sid. Now, add it as an access denied ace:
  722. //
  723. AddAccessDeniedAce( Acl,
  724. ACL_REVISION,
  725. FILE_GENERIC_READ |
  726. FILE_GENERIC_WRITE |
  727. FILE_CREATE_PIPE_INSTANCE,
  728. Sids );
  729. }
  730. for (i = 0 ; i < Count ; i ++ ) {
  731. SidLength = sizeof( SidBuffer );
  732. DomainLen = MAX_PATH ;
  733. if (! LookupAccountName(NULL,
  734. Names[ i ],
  735. Sids,
  736. &SidLength,
  737. ReferencedDomain,
  738. &DomainLen,
  739. &Use ) )
  740. {
  741. _snprintf( ReferencedDomain, MAX_PATH, "Unable to find account %s", Names[ i ]);
  742. ErrorExit( ReferencedDomain );
  743. }
  744. //
  745. // Got the sid. Now, add it as an access allowed ace:
  746. //
  747. AddAccessAllowedAce(Acl,
  748. ACL_REVISION,
  749. FILE_GENERIC_READ |
  750. FILE_GENERIC_WRITE |
  751. FILE_CREATE_PIPE_INSTANCE,
  752. Sids );
  753. }
  754. //
  755. // Now the ACL should be complete, so set it into the SD and return:
  756. //
  757. SetSecurityDescriptorDacl( Sd, TRUE, Acl, FALSE );
  758. return Sd ;
  759. }
  760. /*************************************************************/
  761. VOID
  762. CloseClient(
  763. REMOTE_CLIENT *pClient
  764. )
  765. {
  766. DWORD tmp;
  767. char Buf[200];
  768. #if DBG
  769. if (pClient->ServerFlags & ~SFLG_VALID) {
  770. printf("pClient %p looks nasty in CloseClient.\n", pClient);
  771. ErrorExit("REMOTE_CLIENT structure corrupt.");
  772. }
  773. #endif
  774. //
  775. // If we're still active (on the normal client list)
  776. // start tearing things down and move to the closing
  777. // list.
  778. //
  779. if (pClient->ServerFlags & SFLG_CLOSING) {
  780. return;
  781. }
  782. if (pClient->ServerFlags & SFLG_HANDSHAKING) {
  783. MoveClientToNormalList(pClient);
  784. }
  785. MoveClientToClosingList(pClient);
  786. pClient->ServerFlags |= SFLG_CLOSING;
  787. if (pClient->PipeWriteH != INVALID_HANDLE_VALUE) {
  788. TRACE(CONNECT, ("Disconnecting %d PipeWriteH (%p).\n", pClient->dwID, pClient->PipeWriteH));
  789. CancelIo(pClient->PipeWriteH);
  790. DisconnectNamedPipe(pClient->PipeWriteH);
  791. CloseHandle(pClient->PipeWriteH);
  792. }
  793. if (pClient->PipeReadH != INVALID_HANDLE_VALUE &&
  794. pClient->PipeReadH != pClient->PipeWriteH) {
  795. TRACE(CONNECT, ("Disconnecting %d PipeReadH (%p).\n", pClient->dwID, pClient->PipeReadH));
  796. CancelIo(pClient->PipeReadH);
  797. DisconnectNamedPipe(pClient->PipeReadH);
  798. CloseHandle(pClient->PipeReadH);
  799. }
  800. if (pClient->rSaveFile != INVALID_HANDLE_VALUE) {
  801. CancelIo(pClient->rSaveFile);
  802. CloseHandle(pClient->rSaveFile);
  803. }
  804. pClient->rSaveFile =
  805. pClient->PipeWriteH =
  806. pClient->PipeReadH =
  807. INVALID_HANDLE_VALUE;
  808. if ( ! bShuttingDownServer ) {
  809. ZeroMemory(Buf, sizeof(Buf));
  810. _snprintf(Buf, sizeof(Buf)-1, "\n**Remote: Disconnected from %s %s [%s]\n", pClient->Name, pClient->UserName, GetFormattedTime(TRUE));
  811. if (WriteFileSynch(hWriteTempFile,Buf,strlen(Buf),&tmp,dwWriteFilePointer,&olMainThread)) {
  812. dwWriteFilePointer += tmp;
  813. StartServerToClientFlow();
  814. }
  815. }
  816. return;
  817. }
  818. BOOL
  819. FASTCALL
  820. HandleSessionError(
  821. PREMOTE_CLIENT pClient,
  822. DWORD dwError
  823. )
  824. {
  825. if (pClient->ServerFlags & SFLG_CLOSING) {
  826. return TRUE;
  827. }
  828. if (dwError) {
  829. if (ERROR_BROKEN_PIPE == dwError ||
  830. ERROR_OPERATION_ABORTED == dwError ||
  831. ERROR_NO_DATA == dwError )
  832. {
  833. CloseClient(pClient);
  834. return TRUE;
  835. }
  836. SetLastError(dwError);
  837. ErrorExit("Unhandled session error.");
  838. }
  839. return FALSE;
  840. }
  841. VOID
  842. FASTCALL
  843. CleanupTempFiles(
  844. PSZ pszTempDir
  845. )
  846. {
  847. HANDLE hSearch;
  848. WIN32_FIND_DATA FindData;
  849. char szPath[MAX_PATH + 1] = {0};
  850. char szFile[MAX_PATH + 1];
  851. //
  852. // pszTempDir, from GetTempPath, has a trailing backslash.
  853. //
  854. _snprintf(szPath, sizeof(szPath)-1, "%sREM*.tmp", pszTempDir);
  855. hSearch = FindFirstFile(szPath, &FindData);
  856. if (INVALID_HANDLE_VALUE != hSearch) {
  857. do {
  858. ZeroMemory(szFile, sizeof(szFile));
  859. _snprintf(szFile, sizeof(szFile)-1, "%s%s", pszTempDir, FindData.cFileName);
  860. DeleteFile(szFile);
  861. } while (FindNextFile(hSearch, &FindData));
  862. FindClose(hSearch);
  863. }
  864. }
  865. VOID
  866. SaveDacl(
  867. PSECURITY_DESCRIPTOR psd
  868. )
  869. {
  870. HKEY hKey ;
  871. int err ;
  872. DWORD disp ;
  873. LPWSTR StringSD ;
  874. DWORD StringLen;
  875. err = RegCreateKeyExW(
  876. HKEY_LOCAL_MACHINE,
  877. REGISTRY_PATH,
  878. 0,
  879. NULL,
  880. REG_OPTION_NON_VOLATILE,
  881. KEY_WRITE,
  882. NULL,
  883. &hKey,
  884. &disp );
  885. if ( err == 0 ) {
  886. if ( SDtoStringSD(sdPublic, 1, DACL_SECURITY_INFORMATION, &StringSD, &StringLen ) ) {
  887. err = RegSetValueExW(
  888. hKey,
  889. REGISTRY_VALUE,
  890. 0,
  891. REG_SZ,
  892. (LPBYTE) StringSD,
  893. StringLen * sizeof(WCHAR) );
  894. }
  895. RegCloseKey( hKey );
  896. }
  897. }
  898. #pragma prefast(push)
  899. #pragma prefast(disable: 248) // NULL dacl is by design here, really
  900. VOID
  901. FASTCALL
  902. SetupSecurityDescriptors(
  903. VOID
  904. )
  905. {
  906. int i;
  907. int err ;
  908. HKEY hKey ;
  909. PWSTR TextSD ;
  910. DWORD Type ;
  911. DWORD Size ;
  912. PSID Everyone ;
  913. PACL pDacl ;
  914. SID_IDENTIFIER_AUTHORITY World = SECURITY_WORLD_SID_AUTHORITY ;
  915. PSECURITY_DESCRIPTOR psd ;
  916. pDacl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 12 + sizeof( ACCESS_ALLOWED_ACE ) + sizeof( ACL ));
  917. psd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( SECURITY_DESCRIPTOR ));
  918. //
  919. // initialize the struct
  920. //
  921. saLocalNamedObjects.nLength = sizeof( SECURITY_ATTRIBUTES );
  922. if ( (pDacl != NULL) && (psd != NULL ) ) {
  923. if ( AllocateAndInitializeSid(&World, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &Everyone) ) {
  924. InitializeAcl(pDacl, 12 + sizeof( ACCESS_ALLOWED_ACE ) + sizeof( ACL ), ACL_REVISION);
  925. AddAccessAllowedAce(pDacl, ACL_REVISION,
  926. EVENT_ALL_ACCESS | MUTEX_ALL_ACCESS | SYNCHRONIZE, Everyone );
  927. InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION );
  928. SetSecurityDescriptorDacl( psd, TRUE, pDacl, FALSE );
  929. saLocalNamedObjects.bInheritHandle = FALSE ;
  930. saLocalNamedObjects.lpSecurityDescriptor = psd ;
  931. HeapFree(GetProcessHeap(), 0, Everyone );
  932. }
  933. }
  934. //
  935. // Initialize the wide-open security descriptor.
  936. //
  937. if ( !SddlToSecurityDescriptor(DEFAULT_SECURITY_DESCRIPTOR, 1, &sdPublic, NULL ) ) {
  938. sdPublic = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( SECURITY_DESCRIPTOR ) );
  939. if ( sdPublic ) {
  940. InitializeSecurityDescriptor( sdPublic, SECURITY_DESCRIPTOR_REVISION );
  941. SetSecurityDescriptorDacl( sdPublic, TRUE, NULL, FALSE );
  942. }
  943. }
  944. saPublic.nLength = sizeof(saPublic);
  945. saPublic.lpSecurityDescriptor = sdPublic;
  946. //
  947. // if /u was specified once or more, build the security descriptor to
  948. // enforce it.
  949. //
  950. saPipe.nLength = sizeof(saPipe);
  951. if ( DaclNameCount || DaclDenyNameCount ) {
  952. saPipe.lpSecurityDescriptor =
  953. FormatSecurityDescriptor( DaclDenyNames, DaclDenyNameCount, DaclNames, DaclNameCount );
  954. if ( SaveDaclToRegistry ) {
  955. SaveDacl( saPipe.lpSecurityDescriptor );
  956. }
  957. if (DaclNameCount) {
  958. fputs( "\nProtected Server! Only the following users or groups can connect:\n", stdout );
  959. for (i = 0 ; i < (int) DaclNameCount ; i++) {
  960. printf( " %s\n", DaclNames[i] );
  961. }
  962. }
  963. if (DaclDenyNameCount) {
  964. fputs("The following users or groups explicitly cannot connect:\n", stdout );
  965. for (i = 0 ; i < (int) DaclDenyNameCount ; i++) {
  966. printf(" %s\n", DaclDenyNames[i] );
  967. }
  968. }
  969. } else {
  970. saPipe.lpSecurityDescriptor = sdPublic;
  971. err = RegOpenKeyExW(
  972. HKEY_LOCAL_MACHINE,
  973. REGISTRY_PATH,
  974. 0,
  975. KEY_READ,
  976. &hKey );
  977. if ( err == 0 ) {
  978. err = RegQueryValueExW(
  979. hKey,
  980. REGISTRY_VALUE,
  981. 0,
  982. &Type,
  983. NULL,
  984. &Size );
  985. if ( err != ERROR_FILE_NOT_FOUND ) {
  986. TextSD = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size );
  987. if ( TextSD ) {
  988. err = RegQueryValueExW(
  989. hKey,
  990. REGISTRY_VALUE,
  991. 0,
  992. &Type,
  993. (LPBYTE) TextSD,
  994. &Size );
  995. if ( err == 0 ) {
  996. SddlToSecurityDescriptor(
  997. TextSD, 1, &saPipe.lpSecurityDescriptor, NULL );
  998. }
  999. }
  1000. }
  1001. RegCloseKey( hKey );
  1002. }
  1003. }
  1004. }
  1005. #pragma prefast(pop)