Source code of Windows XP (NT5)
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.

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