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.

1229 lines
37 KiB

  1. /*************************************************************************
  2. *
  3. * execsvr.c
  4. *
  5. * Remote CreateProcess server to allow programs to be started on a given
  6. * Session. Needed for OLE2 support.
  7. *
  8. * NOTE: Maybe this should be converted to RPC in the future when we
  9. * have more time so that it can be a more general facility.
  10. *
  11. * copyright notice: Microsoft, 1997
  12. *
  13. * Author:
  14. *
  15. *
  16. *************************************************************************/
  17. #define UNICODE 1
  18. #include "precomp.h"
  19. #pragma hdrstop
  20. #include <execsrv.h>
  21. #include <wincrypt.h>
  22. HANDLE ExecThreadHandle = NULL;
  23. HANDLE ExecServerPipe = NULL;
  24. static HANDLE ghUserToken = NULL;
  25. extern CRITICAL_SECTION GlobalsLock;
  26. DWORD
  27. ExecServerThread(
  28. LPVOID lpThreadParameter
  29. );
  30. BOOLEAN
  31. ProcessExecRequest(
  32. HANDLE hPipe,
  33. PCHAR pBuf,
  34. DWORD AmountRead
  35. );
  36. HANDLE
  37. ImpersonateUser(
  38. HANDLE UserToken,
  39. HANDLE ThreadHandle
  40. );
  41. BOOL
  42. StopImpersonating(
  43. HANDLE ThreadHandle
  44. );
  45. HANDLE
  46. CreateExecSrvPipe(
  47. LPCTSTR lpPipeName
  48. );
  49. /*****************************************************************************
  50. *
  51. * CtxExecServerLogon
  52. *
  53. * Notify the Exec Server service that a user has logged on
  54. *
  55. * ENTRY:
  56. * Param1 (input/output)
  57. * Comments
  58. *
  59. * EXIT:
  60. * STATUS_SUCCESS - no error
  61. *
  62. ****************************************************************************/
  63. VOID
  64. CtxExecServerLogon(
  65. HANDLE hToken
  66. )
  67. {
  68. EnterCriticalSection( &GlobalsLock );
  69. //
  70. // Store information about the current user
  71. // so we can create processes under their account
  72. // as needed.
  73. //
  74. ghUserToken = hToken;
  75. LeaveCriticalSection( &GlobalsLock );
  76. }
  77. /*****************************************************************************
  78. *
  79. * CtxExecServerLogoff
  80. *
  81. * Notify the Exec Server service that a user has logged off
  82. *
  83. * ENTRY:
  84. * Param1 (input/output)
  85. * Comments
  86. *
  87. * EXIT:
  88. * STATUS_SUCCESS - no error
  89. *
  90. ****************************************************************************/
  91. VOID
  92. CtxExecServerLogoff()
  93. {
  94. EnterCriticalSection( &GlobalsLock );
  95. //
  96. // Release information stored about the current logged
  97. // on user.
  98. //
  99. ghUserToken = NULL;
  100. LeaveCriticalSection( &GlobalsLock );
  101. }
  102. //-----------------------------------------------------
  103. // Helper functions copied from SALEM
  104. // (nt\termsrv\remdsk\server\sessmgr\helper.cpp)
  105. //-----------------------------------------------------
  106. DWORD
  107. GenerateRandomBytes(
  108. IN DWORD dwSize,
  109. IN OUT LPBYTE pbBuffer
  110. )
  111. /*++
  112. Description:
  113. Generate fill buffer with random bytes.
  114. Parameters:
  115. dwSize : Size of buffer pbBuffer point to.
  116. pbBuffer : Pointer to buffer to hold the random bytes.
  117. Returns:
  118. TRUE/FALSE
  119. --*/
  120. {
  121. HCRYPTPROV hProv = (HCRYPTPROV)NULL;
  122. DWORD dwStatus = ERROR_SUCCESS;
  123. //
  124. // Create a Crypto Provider to generate random number
  125. //
  126. if( !CryptAcquireContext(
  127. &hProv,
  128. NULL,
  129. NULL,
  130. PROV_RSA_FULL,
  131. CRYPT_VERIFYCONTEXT
  132. ) )
  133. {
  134. dwStatus = GetLastError();
  135. goto CLEANUPANDEXIT;
  136. }
  137. if( !CryptGenRandom(hProv, dwSize, pbBuffer) )
  138. {
  139. dwStatus = GetLastError();
  140. }
  141. CLEANUPANDEXIT:
  142. if( (HCRYPTPROV)NULL != hProv )
  143. {
  144. CryptReleaseContext( hProv, 0 );
  145. }
  146. return dwStatus;
  147. }
  148. DWORD
  149. GenerateRandomString(
  150. IN DWORD dwSizeRandomSeed,
  151. IN OUT LPTSTR* pszRandomString
  152. )
  153. /*++
  154. --*/
  155. {
  156. PBYTE lpBuffer = NULL;
  157. DWORD dwStatus = ERROR_SUCCESS;
  158. BOOL bSuccess;
  159. DWORD cbConvertString = 0;
  160. if( 0 == dwSizeRandomSeed || NULL == pszRandomString )
  161. {
  162. dwStatus = ERROR_INVALID_PARAMETER;
  163. ASSERT(FALSE);
  164. goto CLEANUPANDEXIT;
  165. }
  166. *pszRandomString = NULL;
  167. lpBuffer = (PBYTE)LocalAlloc( LPTR, dwSizeRandomSeed );
  168. if( NULL == lpBuffer )
  169. {
  170. dwStatus = GetLastError();
  171. goto CLEANUPANDEXIT;
  172. }
  173. dwStatus = GenerateRandomBytes( dwSizeRandomSeed, lpBuffer );
  174. if( ERROR_SUCCESS != dwStatus )
  175. {
  176. goto CLEANUPANDEXIT;
  177. }
  178. // Convert to string
  179. // cbConvertString will include the NULL character
  180. bSuccess = CryptBinaryToString(
  181. lpBuffer,
  182. dwSizeRandomSeed,
  183. CRYPT_STRING_BASE64,
  184. NULL,
  185. &cbConvertString
  186. );
  187. if( FALSE == bSuccess )
  188. {
  189. dwStatus = GetLastError();
  190. goto CLEANUPANDEXIT;
  191. }
  192. *pszRandomString = (LPTSTR)LocalAlloc( LPTR, cbConvertString*sizeof(TCHAR) );
  193. if( NULL == *pszRandomString )
  194. {
  195. dwStatus = GetLastError();
  196. goto CLEANUPANDEXIT;
  197. }
  198. bSuccess = CryptBinaryToString(
  199. lpBuffer,
  200. dwSizeRandomSeed,
  201. CRYPT_STRING_BASE64,
  202. *pszRandomString,
  203. &cbConvertString
  204. );
  205. if( FALSE == bSuccess )
  206. {
  207. dwStatus = GetLastError();
  208. }
  209. else
  210. {
  211. if( (*pszRandomString)[cbConvertString - 1] == '\n' &&
  212. (*pszRandomString)[cbConvertString - 2] == '\r' )
  213. {
  214. (*pszRandomString)[cbConvertString - 2] = 0;
  215. }
  216. }
  217. CLEANUPANDEXIT:
  218. if( ERROR_SUCCESS != dwStatus )
  219. {
  220. if( NULL != *pszRandomString )
  221. {
  222. LocalFree(*pszRandomString);
  223. *pszRandomString = NULL;
  224. }
  225. }
  226. if( NULL != lpBuffer )
  227. {
  228. LocalFree(lpBuffer);
  229. }
  230. return dwStatus;
  231. }
  232. /*****************************************************************************
  233. *
  234. * StartExecServerThread
  235. *
  236. * Start the remote exec server thread.
  237. *
  238. * ENTRY:
  239. * Param1 (input/output)
  240. * Comments
  241. *
  242. * EXIT:
  243. * STATUS_SUCCESS - no error
  244. *
  245. ****************************************************************************/
  246. BOOLEAN
  247. StartExecServerThread()
  248. {
  249. DWORD ThreadId;
  250. BOOL Result;
  251. WCHAR szPipeName[EXECSRVPIPENAMELEN];
  252. SECURITY_ATTRIBUTES SecurityAttributes;
  253. PSECURITY_ATTRIBUTES pSecurityAttributes = NULL;
  254. PSECURITY_DESCRIPTOR lpSecurityDescriptor = NULL;
  255. LPTSTR pszRandomString = NULL;
  256. ULONG RandomLen;
  257. DWORD dwStatus = ERROR_SUCCESS;
  258. #if DBG
  259. OutputDebugString (TEXT("EXECSERVERSYSTEM: Starting ExecServerThread\n"));
  260. #endif
  261. RandomLen = sizeof(szPipeName)/sizeof(WCHAR) - 30;
  262. dwStatus = GenerateRandomString( RandomLen, &pszRandomString );
  263. if( ERROR_SUCCESS != dwStatus ) {
  264. return FALSE;
  265. }
  266. // the string generated is always greater than what we ask
  267. pszRandomString[RandomLen] = L'\0';
  268. _snwprintf(&szPipeName[0], EXECSRVPIPENAMELEN, L"\\\\.\\Pipe\\TerminalServer\\%ws\\%d", pszRandomString, NtCurrentPeb()->SessionId);
  269. szPipeName[EXECSRVPIPENAMELEN-1] = L'\0';
  270. ExecServerPipe = CreateExecSrvPipe( &szPipeName[0] );
  271. if( ExecServerPipe == (HANDLE)-1 ) {
  272. OutputDebugString (TEXT("EXECSRV: Could not get pipe for ExecSrvr\n"));
  273. return( FALSE );
  274. }
  275. WinStationSetInformation( SERVERNAME_CURRENT, NtCurrentPeb()->SessionId, WinStationExecSrvSystemPipe, &szPipeName[0], sizeof(szPipeName) );
  276. ExecThreadHandle = CreateThread(
  277. NULL, // Use default ACL
  278. 0, // Same stack size
  279. ExecServerThread, // Start address
  280. (LPVOID)ExecServerPipe, // Parameter
  281. 0, // Creation flags
  282. &ThreadId // Get the id back here
  283. );
  284. if( ExecThreadHandle == NULL ) {
  285. OutputDebugString (TEXT("WLEXECSERVER: Could not create server thread Error\n"));
  286. return(FALSE);
  287. }
  288. return(TRUE);
  289. }
  290. /*****************************************************************************
  291. *
  292. * ExecServerThread
  293. *
  294. * Thread that listens on the named pipe for remote exec service
  295. * requests and executes them. Passes the results back to the caller.
  296. *
  297. * ENTRY:
  298. * lpThreadParameter (input)
  299. * Handle to exec server pipe
  300. *
  301. * EXIT:
  302. * STATUS_SUCCESS - no error
  303. *
  304. ****************************************************************************/
  305. DWORD
  306. ExecServerThread(
  307. LPVOID lpThreadParameter
  308. )
  309. {
  310. BOOL Result;
  311. DWORD AmountRead;
  312. CHAR *pBuf;
  313. HANDLE hPipe = (HANDLE)lpThreadParameter;
  314. pBuf = LocalAlloc(LMEM_FIXED, EXECSRV_BUFFER_SIZE );
  315. if (pBuf == NULL) {
  316. OutputDebugString (TEXT("WLEXECSERVER: ExecServerThread : nomemory \n"));
  317. return(STATUS_NO_MEMORY);
  318. }
  319. while( 1 ) {
  320. // read the pipe for a request (pipe is in message mode)
  321. Result = ConnectNamedPipe( hPipe, NULL );
  322. if( !Result ) {
  323. OutputDebugString (TEXT("WLEXECSERVER: ConnectNamePipe failed\n"));
  324. LocalFree( pBuf );
  325. return(FALSE);
  326. }
  327. // read the request from the pipe
  328. Result = ReadFile(
  329. hPipe,
  330. pBuf,
  331. EXECSRV_BUFFER_SIZE,
  332. &AmountRead,
  333. NULL
  334. );
  335. if( Result ) {
  336. ProcessExecRequest( hPipe, pBuf, AmountRead );
  337. }
  338. else {
  339. OutputDebugString (TEXT("WLEXECSERVER: Error reading pipe after connect\n"));
  340. // Could handle the to big error, but this means mismatched client
  341. }
  342. // wait until the client reads out the reply
  343. Result = FlushFileBuffers( hPipe );
  344. #if DBG
  345. if( Result == 0 ) {
  346. OutputDebugString (TEXT("EXECSRV: FlushFileBuffers failed! \n"));
  347. }
  348. #endif
  349. // disconnect the name pipe
  350. Result = DisconnectNamedPipe( hPipe );
  351. #if DBG
  352. if( Result == 0 ) {
  353. OutputDebugString (TEXT("EXECSRV: Disconnect Named Pipe failed! Error \n"));
  354. }
  355. #endif
  356. }
  357. }
  358. /*****************************************************************************
  359. *
  360. * ProcessExecRequest
  361. *
  362. * Do the work of processing a remote exec request
  363. *
  364. * ENTRY:
  365. * hPipe (input)
  366. * Pipe handle for reply
  367. *
  368. * pBuf (input)
  369. * Request buffer
  370. *
  371. * AmountRead (input)
  372. * Amount in request buffer
  373. *
  374. * EXIT:
  375. * STATUS_SUCCESS - no error
  376. *
  377. ****************************************************************************/
  378. BOOLEAN
  379. ProcessExecRequest(
  380. HANDLE hPipe,
  381. PCHAR pBuf,
  382. DWORD AmountRead
  383. )
  384. {
  385. DWORD AmountWrote;
  386. BOOL Result;
  387. HANDLE ImpersonationHandle = NULL;
  388. SECURITY_ATTRIBUTES saProcess;
  389. EXECSRV_REPLY Rep;
  390. HANDLE LocalProc = NULL;
  391. HANDLE RemoteProc = NULL;
  392. HANDLE LocalhProcess = NULL;
  393. HANDLE LocalhThread = NULL;
  394. PEXECSRV_REQUEST p = (PEXECSRV_REQUEST)pBuf;
  395. LPVOID lpEnvironment = NULL;
  396. HANDLE hUserToken=NULL;
  397. BOOL bEnvBlockCreatedLocally = FALSE;
  398. #if DBG
  399. KdPrint(("WLEXECSERVER: AmountRead = %d, pBuf->Size= %d \n", AmountRead, p->Size ));
  400. #endif
  401. RtlZeroMemory(&Rep,sizeof(EXECSRV_REPLY));
  402. if( AmountRead < sizeof(EXECSRV_REQUEST) ) {
  403. // drop the request
  404. OutputDebugString (TEXT("WLEXECSERVER: BAD EXECSRV Request size (WinLogon)\n"));
  405. return(FALSE);
  406. }
  407. // normalize the pointers
  408. if( p->lpszImageName ) {
  409. p->lpszImageName = (PWCHAR)(((ULONG_PTR)p->lpszImageName) + pBuf);
  410. if( ( (PCHAR)p->lpszImageName > (PCHAR)(pBuf+AmountRead)) ||
  411. ((PCHAR)p->lpszImageName < (PCHAR)(pBuf + sizeof(EXECSRV_REQUEST))) ) {
  412. OutputDebugString (TEXT("WLEXECSERVER: Invalid image name pointer\n"));
  413. // drop the request
  414. return(FALSE);
  415. }
  416. }
  417. if( p->lpszCommandLine ) {
  418. p->lpszCommandLine = (PWCHAR)(((ULONG_PTR)p->lpszCommandLine) + pBuf);
  419. if( ((PCHAR)p->lpszCommandLine > (PCHAR)(pBuf+AmountRead)) ||
  420. ((PCHAR)p->lpszCommandLine < (PCHAR)(pBuf + sizeof(EXECSRV_REQUEST)))) {
  421. OutputDebugString (TEXT("WLEXECSERVER: Invalid command line pointer\n"));
  422. // drop the request
  423. return(FALSE);
  424. }
  425. }
  426. if( p->lpszCurDir ) {
  427. p->lpszCurDir = (PWCHAR)(((ULONG_PTR)p->lpszCurDir) + pBuf);
  428. if( ((PCHAR)p->lpszCurDir > (PCHAR)(pBuf+AmountRead)) ||
  429. ((PCHAR)p->lpszCurDir < (PCHAR)(pBuf + sizeof(EXECSRV_REQUEST))) ) {
  430. OutputDebugString (TEXT("WLEXECSERVER: Invalid CurDir pointer\n"));
  431. // drop the request
  432. return(FALSE);
  433. }
  434. }
  435. if( p->StartInfo.lpDesktop ) {
  436. p->StartInfo.lpDesktop = (PWCHAR)(((ULONG_PTR)p->StartInfo.lpDesktop) + pBuf);
  437. if( ((PCHAR)p->StartInfo.lpDesktop > (PCHAR)(pBuf+AmountRead)) ||
  438. ((PCHAR)p->StartInfo.lpDesktop < (PCHAR)(pBuf + sizeof(EXECSRV_REQUEST))) ) {
  439. OutputDebugString (TEXT("WLEXECSERVER: Invalid StartInfo.lpDesktop pointer\n"));
  440. // drop the request
  441. return(FALSE);
  442. }
  443. }
  444. if( p->StartInfo.lpTitle ) {
  445. p->StartInfo.lpTitle = (PWCHAR)(((ULONG_PTR)p->StartInfo.lpTitle) + pBuf);
  446. if( ((PCHAR)p->StartInfo.lpTitle > (PCHAR)(pBuf+AmountRead)) ||
  447. ((PCHAR)p->StartInfo.lpTitle < (PCHAR)(pBuf + sizeof(EXECSRV_REQUEST))) ) {
  448. OutputDebugString (TEXT("WLEXECSERVER: Invalid StartInfo.lpTitle pointer\n"));
  449. // drop the request
  450. return(FALSE);
  451. }
  452. }
  453. if (p->lpvEnvironment )
  454. {
  455. p->lpvEnvironment = (PWCHAR)(((ULONG_PTR)p->lpvEnvironment) + pBuf);
  456. if( ((PCHAR)p->lpvEnvironment > (PCHAR)(pBuf+AmountRead)) ||
  457. ((PCHAR)p->lpvEnvironment < (PCHAR)(pBuf + sizeof(EXECSRV_REQUEST))) ) {
  458. OutputDebugString (TEXT("WLEXECSERVER: Invalid env pointer\n"));
  459. // drop the request
  460. return(FALSE);
  461. }
  462. }
  463. // We do not know what the reserved is, so make sure it is NULL
  464. p->StartInfo.lpReserved = NULL;
  465. //if( p->lpszImageName )
  466. //OutputDebugString (TEXT("WLEXECSERVER: Got request ImageName :%ws:\n", p->lpszImageName));
  467. //if( p->lpszCommandLine )
  468. //OutputDebugString (TEXT("WLEXECSERVER: Got request command line :%ws:\n", p->lpszCommandLine));
  469. //OutputDebugString (TEXT("WLEXECSERVER: CreateFlags 0x%x\n",p->fdwCreate));
  470. //OutputDebugString (TEXT("System Flag 0x%x\n",p->System));
  471. //
  472. // Can only service user security level requests when a user is logged on.
  473. //
  474. if( !p->System ) {
  475. EnterCriticalSection( &GlobalsLock );
  476. if (ghUserToken == NULL) {
  477. #if DBG
  478. OutputDebugString (TEXT("WLEXECSERVER: No USER Logged On for USER CreateProcess Request!\n"));
  479. #endif
  480. LeaveCriticalSection( &GlobalsLock );
  481. return( FALSE );
  482. }
  483. //
  484. // We need to open the remote process in order to duplicate the user token.
  485. // But for that, we need to impersonate the named pipe client.
  486. //
  487. if ( ImpersonateNamedPipeClient( hPipe ) == 0 ) {
  488. LeaveCriticalSection( &GlobalsLock );
  489. return( FALSE );
  490. }
  491. //
  492. // Get the handle to remote process
  493. //
  494. RemoteProc = OpenProcess(
  495. PROCESS_DUP_HANDLE|PROCESS_QUERY_INFORMATION,
  496. FALSE, // no inherit
  497. p->RequestingProcessId
  498. );
  499. if( RemoteProc == NULL ) {
  500. OutputDebugString (TEXT("WLEXECSERVER: Could not get handle to remote process \n"));
  501. //
  502. // on retail builds we can not duplicate a handle into
  503. // service controller process
  504. //
  505. // The handles are not used by SCM right now, we must
  506. // have another way to pass handles if this function
  507. // is used by other services.
  508. //
  509. ASSERT( FALSE ); // Should not happen in WinLogon
  510. RevertToSelf(); // Imperonation of named pipe client had succeeded.
  511. LeaveCriticalSection( &GlobalsLock );
  512. goto ReturnError;
  513. }
  514. if ( !RevertToSelf() ) {
  515. ASSERT( FALSE ); // This RevertToSelf should not fail.
  516. LeaveCriticalSection( &GlobalsLock );
  517. return( FALSE );
  518. }
  519. //
  520. // Get the handle to current process
  521. //
  522. LocalProc = OpenProcess(
  523. PROCESS_DUP_HANDLE|PROCESS_QUERY_INFORMATION,
  524. FALSE, // no inherit
  525. GetCurrentProcessId()
  526. );
  527. if( LocalProc == NULL ) {
  528. OutputDebugString (TEXT("WLEXECSERVER: Could not get handle to local process\n"));
  529. LeaveCriticalSection( &GlobalsLock );
  530. goto ReturnError;
  531. }
  532. // decide if we are creating the new process for the currntly logged in user, or a
  533. // new user
  534. if (p->hToken)
  535. {
  536. //
  537. // we are dealing with a new user, for which we have a token comming from
  538. // services.exe (for SecLogon)
  539. //
  540. Result = DuplicateHandle(
  541. RemoteProc, // Source of the handle (us)
  542. p->hToken, // Source handle
  543. LocalProc, // Target of the handle
  544. &hUserToken, // Target handle
  545. 0, // ignored since DUPLICATE_SAME_ACCESS is set
  546. FALSE, // no inherit on the handle
  547. DUPLICATE_SAME_ACCESS
  548. );
  549. if( !Result ) {
  550. OutputDebugString (TEXT("WLEXECSERVER: Error duping process handle to target process\n"));
  551. LeaveCriticalSection( &GlobalsLock );
  552. goto ReturnError;
  553. }
  554. }
  555. else
  556. {
  557. hUserToken=ghUserToken; // currently logged in user
  558. }
  559. lpEnvironment = p->lpvEnvironment ;
  560. //
  561. // Create Environment Block if we have none
  562. //
  563. if ( !lpEnvironment )
  564. {
  565. if (!CreateEnvironmentBlock (&lpEnvironment, hUserToken, FALSE)) {
  566. KdPrint(("WLEXECSERVER: CreateEnvironmentBlock() Failed\n"));
  567. }
  568. else
  569. {
  570. bEnvBlockCreatedLocally = TRUE;
  571. }
  572. }
  573. //
  574. // If we are to run the process under USER security, impersonate
  575. // the user.
  576. //
  577. // This will also access check the users access to the exe image as well.
  578. //
  579. ImpersonationHandle = ImpersonateUser(hUserToken, NULL );
  580. if (ImpersonationHandle == NULL) {
  581. OutputDebugString (TEXT("WLEXECSERVER: failed to impersonate user\n"));
  582. LeaveCriticalSection( &GlobalsLock );
  583. goto ReturnError;
  584. }
  585. LeaveCriticalSection( &GlobalsLock );
  586. // this environment block is UNICODE
  587. p->fdwCreate |= CREATE_UNICODE_ENVIRONMENT;
  588. Result = CreateProcessAsUserW(
  589. hUserToken,
  590. p->lpszImageName,
  591. p->lpszCommandLine,
  592. NULL, // &saProcess,
  593. NULL, // &p->saThread
  594. p->fInheritHandles,
  595. p->fdwCreate,
  596. lpEnvironment,
  597. p->lpszCurDir,
  598. &p->StartInfo,
  599. &Rep.ProcInfo
  600. );
  601. if ( bEnvBlockCreatedLocally ) {
  602. DestroyEnvironmentBlock (lpEnvironment);
  603. }
  604. }
  605. else {
  606. // If creating system, force separate WOW
  607. p->fdwCreate |= CREATE_SEPARATE_WOW_VDM;
  608. // CreateProcessAsUser() does not take a NULL token for SYSTEM
  609. Result = CreateProcessW(
  610. p->lpszImageName,
  611. p->lpszCommandLine,
  612. NULL, // &saProcess,
  613. NULL, // &p->saThread
  614. p->fInheritHandles,
  615. p->fdwCreate,
  616. NULL, //p->lpvEnvironment
  617. p->lpszCurDir,
  618. &p->StartInfo,
  619. &Rep.ProcInfo
  620. );
  621. }
  622. if( !Result ){
  623. if( ImpersonationHandle ) {
  624. StopImpersonating(ImpersonationHandle);
  625. }
  626. //
  627. // Rep.Result = FALSE;
  628. // Rep.LastError = GetLastError();
  629. // Result = WriteFile( hPipe, &Rep, sizeof(Rep), &AmountWrote, NULL );
  630. // OutputDebugString (TEXT("WLEXECSERVER: Error in CreateProcess\n"));
  631. // return(FALSE);
  632. goto ReturnError;
  633. }
  634. // Stop impersonating the process
  635. if( ImpersonationHandle ) {
  636. StopImpersonating(ImpersonationHandle);
  637. }
  638. if (!Result) {
  639. OutputDebugString (TEXT("ExecServer: failed to resume new process thread\n"));
  640. CloseHandle(Rep.ProcInfo.hProcess);
  641. CloseHandle(Rep.ProcInfo.hThread);
  642. goto ReturnError;
  643. }
  644. //
  645. // do any tricky handle DUP stuff
  646. //
  647. LocalhProcess = Rep.ProcInfo.hProcess;
  648. LocalhThread = Rep.ProcInfo.hThread;
  649. Result = DuplicateHandle(
  650. LocalProc, // Source of the handle (us)
  651. Rep.ProcInfo.hProcess, // Source handle
  652. RemoteProc, // Target of the handle
  653. &Rep.ProcInfo.hProcess, // Target handle
  654. 0, // ignored since DUPLICATE_SAME_ACCESS is set
  655. FALSE, // no inherit on the handle
  656. DUPLICATE_SAME_ACCESS
  657. );
  658. if( !Result ) {
  659. OutputDebugString (TEXT("WLEXECSERVER: Error duping process handle to target process\n"));
  660. }
  661. //
  662. // If the program got launched into the shared WOW virtual machine,
  663. // then the hThread will be NULL.
  664. //
  665. if( Rep.ProcInfo.hThread != NULL ) {
  666. Result = DuplicateHandle(
  667. LocalProc, // Source of the handle (us)
  668. Rep.ProcInfo.hThread, // Source handle
  669. RemoteProc, // Target of the handle
  670. &Rep.ProcInfo.hThread, // Target handle
  671. 0, // ignored since DUPLICATE_SAME_ACCESS is set
  672. FALSE, // no inherit on the handle
  673. DUPLICATE_SAME_ACCESS
  674. );
  675. if( !Result ) {
  676. //OutputDebugString (TEXT("WLEXECSERVER: Error %d duping thread handle to target process, Handle 0x%x, ThreadId 0x%x\n",GetLastError(),Rep.ProcInfo.hThread,Rep.ProcInfo.dwThreadId));
  677. }
  678. }
  679. //OutputDebugString (TEXT("WLXEXECSERVER: Success for %d type exec\n",p->System));
  680. //
  681. // build the reply packet with the handle valid in the context
  682. // of the requesting process
  683. //
  684. Rep.Result = TRUE;
  685. Rep.LastError = 0;
  686. Result = WriteFile( hPipe, &Rep, sizeof(Rep), &AmountWrote, NULL );
  687. if( !Result ) {
  688. OutputDebugString (TEXT("WLEXECSERVER: Error sending reply \n"));
  689. }
  690. //
  691. // close our versions of the handles. The requestors references
  692. // are now the main ones
  693. //
  694. if( LocalProc != NULL )
  695. CloseHandle( LocalProc );
  696. if( RemoteProc != NULL )
  697. CloseHandle( RemoteProc );
  698. if( LocalhProcess != NULL )
  699. CloseHandle( LocalhProcess );
  700. if( LocalhThread != NULL )
  701. CloseHandle( LocalhThread );
  702. if (hUserToken && (hUserToken != ghUserToken))
  703. {
  704. CloseHandle( hUserToken );
  705. }
  706. return (BOOLEAN)Result;
  707. ReturnError:
  708. Rep.Result = FALSE;
  709. Rep.LastError = GetLastError();
  710. //OutputDebugString (TEXT("WLXEXECSERVER: Error %d for %d type exec\n",Rep.LastError,p->System));
  711. Result = WriteFile( hPipe, &Rep, sizeof(Rep), &AmountWrote, NULL );
  712. if( LocalProc != NULL )
  713. CloseHandle( LocalProc );
  714. if( RemoteProc != NULL )
  715. CloseHandle( RemoteProc );
  716. if( LocalhProcess != NULL )
  717. CloseHandle( LocalhProcess );
  718. if( LocalhThread != NULL )
  719. CloseHandle( LocalhThread );
  720. if (hUserToken && (hUserToken != ghUserToken) )
  721. {
  722. CloseHandle( hUserToken );
  723. }
  724. return (BOOLEAN)Result;
  725. }
  726. /***************************************************************************\
  727. * FUNCTION: ImpersonateUser
  728. *
  729. * PURPOSE: Impersonates the user by setting the users token
  730. * on the specified thread. If no thread is specified the token
  731. * is set on the current thread.
  732. *
  733. * RETURNS: Handle to be used on call to StopImpersonating() or NULL on failure
  734. * If a non-null thread handle was passed in, the handle returned will
  735. * be the one passed in. (See note)
  736. *
  737. * NOTES: Take care when passing in a thread handle and then calling
  738. * StopImpersonating() with the handle returned by this routine.
  739. * StopImpersonating() will close any thread handle passed to it -
  740. * even yours !
  741. *
  742. *
  743. \***************************************************************************/
  744. HANDLE
  745. ImpersonateUser(
  746. HANDLE UserToken,
  747. HANDLE ThreadHandle
  748. )
  749. {
  750. NTSTATUS Status, IgnoreStatus;
  751. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  752. OBJECT_ATTRIBUTES ObjectAttributes;
  753. HANDLE ImpersonationToken;
  754. BOOL ThreadHandleOpened = FALSE;
  755. if (ThreadHandle == NULL) {
  756. //
  757. // Get a handle to the current thread.
  758. // Once we have this handle, we can set the user's impersonation
  759. // token into the thread and remove it later even though we ARE
  760. // the user for the removal operation. This is because the handle
  761. // contains the access rights - the access is not re-evaluated
  762. // at token removal time.
  763. //
  764. Status = NtDuplicateObject( NtCurrentProcess(), // Source process
  765. NtCurrentThread(), // Source handle
  766. NtCurrentProcess(), // Target process
  767. &ThreadHandle, // Target handle
  768. THREAD_SET_THREAD_TOKEN,// Access
  769. 0L, // Attributes
  770. DUPLICATE_SAME_ATTRIBUTES
  771. );
  772. if (!NT_SUCCESS(Status)) {
  773. KdPrint(("ImpersonateUser : Failed to duplicate thread handle, status = 0x%lx", Status));
  774. return(NULL);
  775. }
  776. ThreadHandleOpened = TRUE;
  777. }
  778. //
  779. // If the usertoken is NULL, there's nothing to do
  780. //
  781. if (UserToken != NULL) {
  782. //
  783. // UserToken is a primary token - create an impersonation token version
  784. // of it so we can set it on our thread
  785. //
  786. InitializeObjectAttributes(
  787. &ObjectAttributes,
  788. NULL,
  789. 0L,
  790. NULL,
  791. //UserProcessData->NewThreadTokenSD);
  792. NULL);
  793. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  794. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  795. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  796. SecurityQualityOfService.EffectiveOnly = FALSE;
  797. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  798. Status = NtDuplicateToken( UserToken,
  799. TOKEN_IMPERSONATE | TOKEN_READ,
  800. &ObjectAttributes,
  801. FALSE,
  802. TokenImpersonation,
  803. &ImpersonationToken
  804. );
  805. if (!NT_SUCCESS(Status)) {
  806. KdPrint(("Failed to duplicate users token to create"
  807. " impersonation thread, status = 0x%lx\n", Status));
  808. if (ThreadHandleOpened) {
  809. IgnoreStatus = NtClose(ThreadHandle);
  810. ASSERT(NT_SUCCESS(IgnoreStatus));
  811. }
  812. return(NULL);
  813. }
  814. //
  815. // Set the impersonation token on this thread so we 'are' the user
  816. //
  817. Status = NtSetInformationThread( ThreadHandle,
  818. ThreadImpersonationToken,
  819. (PVOID)&ImpersonationToken,
  820. sizeof(ImpersonationToken)
  821. );
  822. //
  823. // We're finished with our handle to the impersonation token
  824. //
  825. IgnoreStatus = NtClose(ImpersonationToken);
  826. ASSERT(NT_SUCCESS(IgnoreStatus));
  827. //
  828. // Check we set the token on our thread ok
  829. //
  830. if (!NT_SUCCESS(Status)) {
  831. KdPrint(( "Failed to set user impersonation token on winlogon thread, status = 0x%lx", Status));
  832. if (ThreadHandleOpened) {
  833. IgnoreStatus = NtClose(ThreadHandle);
  834. ASSERT(NT_SUCCESS(IgnoreStatus));
  835. }
  836. return(NULL);
  837. }
  838. }
  839. return(ThreadHandle);
  840. }
  841. /***************************************************************************\
  842. * FUNCTION: StopImpersonating
  843. *
  844. * PURPOSE: Stops impersonating the client by removing the token on the
  845. * current thread.
  846. *
  847. * PARAMETERS: ThreadHandle - handle returned by ImpersonateUser() call.
  848. *
  849. * RETURNS: TRUE on success, FALSE on failure
  850. *
  851. * NOTES: If a thread handle was passed in to ImpersonateUser() then the
  852. * handle returned was one and the same. If this is passed to
  853. * StopImpersonating() the handle will be closed. Take care !
  854. *
  855. * HISTORY:
  856. *
  857. * 04-21-92 Davidc Created.
  858. *
  859. \***************************************************************************/
  860. BOOL
  861. StopImpersonating(
  862. HANDLE ThreadHandle
  863. )
  864. {
  865. NTSTATUS Status, IgnoreStatus;
  866. HANDLE ImpersonationToken;
  867. //
  868. // Remove the user's token from our thread so we are 'ourself' again
  869. //
  870. ImpersonationToken = NULL;
  871. Status = NtSetInformationThread( ThreadHandle,
  872. ThreadImpersonationToken,
  873. (PVOID)&ImpersonationToken,
  874. sizeof(ImpersonationToken)
  875. );
  876. //
  877. // We're finished with the thread handle
  878. //
  879. IgnoreStatus = NtClose(ThreadHandle);
  880. ASSERT(NT_SUCCESS(IgnoreStatus));
  881. if (!NT_SUCCESS(Status)) {
  882. KdPrint(("Failed to remove user impersonation token from winlogon thread, status = 0x%lx", Status));
  883. }
  884. return(NT_SUCCESS(Status));
  885. }
  886. //---------------------------------------------------------------------------------------
  887. //
  888. // CreateExecSrvPipe
  889. // Creates exec server named pipe with appropriate DACL. It allows access only to local
  890. // system, local service and network service.
  891. // It return handle to the newly created pipe. If the operation fails, it returns
  892. // INVALID_HANDLE_VALUE.
  893. //
  894. //---------------------------------------------------------------------------------------
  895. HANDLE CreateExecSrvPipe( LPCTSTR lpPipeName )
  896. {
  897. HANDLE hPipe = INVALID_HANDLE_VALUE;
  898. NTSTATUS Status;
  899. SECURITY_ATTRIBUTES SecAttr;
  900. PSID pSystemSid = NULL;
  901. PSID pLocalServiceSid = NULL;
  902. PSID pNetworkServiceSid = NULL;
  903. PSECURITY_DESCRIPTOR pSd = NULL;
  904. PACL pDacl;
  905. ULONG AclLength;
  906. SID_IDENTIFIER_AUTHORITY SystemAuth = SECURITY_NT_AUTHORITY;
  907. // Allocate and Initialize the "System" Sid.
  908. Status = RtlAllocateAndInitializeSid( &SystemAuth,
  909. 1,
  910. SECURITY_LOCAL_SYSTEM_RID,
  911. 0, 0, 0, 0, 0, 0, 0,
  912. &pSystemSid );
  913. if (!NT_SUCCESS(Status)) {
  914. goto CreatePipeErr;
  915. }
  916. // Allocate and Initialize the "Local Service" Sid.
  917. Status = RtlAllocateAndInitializeSid( &SystemAuth,
  918. 1,
  919. SECURITY_LOCAL_SERVICE_RID,
  920. 0, 0, 0, 0, 0, 0, 0,
  921. &pLocalServiceSid );
  922. if (!NT_SUCCESS(Status)) {
  923. goto CreatePipeErr;
  924. }
  925. // Allocate and Initialize the "Network Service" Sid.
  926. Status = RtlAllocateAndInitializeSid( &SystemAuth,
  927. 1,
  928. SECURITY_NETWORK_SERVICE_RID,
  929. 0, 0, 0, 0, 0, 0, 0,
  930. &pNetworkServiceSid );
  931. if (!NT_SUCCESS(Status)) {
  932. goto CreatePipeErr;
  933. }
  934. // Allocate space for the security descriptor.
  935. AclLength = (ULONG)sizeof(ACL) +
  936. 3 * sizeof(ACCESS_ALLOWED_ACE) +
  937. RtlLengthSid( pSystemSid ) +
  938. RtlLengthSid( pLocalServiceSid ) +
  939. RtlLengthSid( pNetworkServiceSid ) -
  940. 3 * sizeof( ULONG );
  941. pSd = (PSECURITY_DESCRIPTOR) LocalAlloc( LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH + AclLength );
  942. if (pSd == NULL) {
  943. goto CreatePipeErr;
  944. }
  945. pDacl = (PACL) ((BYTE*)(pSd) + SECURITY_DESCRIPTOR_MIN_LENGTH);
  946. // Set up a new ACL with no ACE.
  947. Status = RtlCreateAcl( pDacl, AclLength, ACL_REVISION2 );
  948. if ( !NT_SUCCESS(Status) ) {
  949. goto CreatePipeErr;
  950. }
  951. // System access
  952. Status = RtlAddAccessAllowedAce( pDacl,
  953. ACL_REVISION2,
  954. GENERIC_READ | GENERIC_WRITE,
  955. pSystemSid
  956. );
  957. if (!NT_SUCCESS(Status)) {
  958. goto CreatePipeErr;
  959. }
  960. // Local Service access
  961. Status = RtlAddAccessAllowedAce( pDacl,
  962. ACL_REVISION2,
  963. GENERIC_READ | GENERIC_WRITE,
  964. pLocalServiceSid
  965. );
  966. if (!NT_SUCCESS(Status)) {
  967. goto CreatePipeErr;
  968. }
  969. // Network Service access
  970. Status = RtlAddAccessAllowedAce( pDacl,
  971. ACL_REVISION2,
  972. GENERIC_READ | GENERIC_WRITE,
  973. pNetworkServiceSid
  974. );
  975. if (!NT_SUCCESS(Status)) {
  976. goto CreatePipeErr;
  977. }
  978. // Now initialize security descriptors that export this protection
  979. Status = RtlCreateSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION1);
  980. if (!NT_SUCCESS(Status)) {
  981. goto CreatePipeErr;
  982. }
  983. Status = RtlSetDaclSecurityDescriptor(pSd, TRUE, pDacl, FALSE);
  984. if (!NT_SUCCESS(Status)) {
  985. goto CreatePipeErr;
  986. }
  987. // Fill the Security Attributes
  988. ZeroMemory(&SecAttr, sizeof(SecAttr));
  989. SecAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  990. SecAttr.lpSecurityDescriptor = pSd;
  991. SecAttr.bInheritHandle = FALSE;
  992. hPipe = CreateNamedPipeW(
  993. lpPipeName,
  994. PIPE_ACCESS_DUPLEX,
  995. PIPE_WAIT | PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE,
  996. PIPE_UNLIMITED_INSTANCES,
  997. EXECSRV_BUFFER_SIZE,
  998. EXECSRV_BUFFER_SIZE,
  999. 0,
  1000. &SecAttr
  1001. );
  1002. // It's very unlikely, but still make sure that pipe with this name does not exist.
  1003. if (GetLastError() == ERROR_ALREADY_EXISTS) {
  1004. NtClose( hPipe );
  1005. hPipe = INVALID_HANDLE_VALUE;
  1006. }
  1007. CreatePipeErr:
  1008. // Free the SIDs
  1009. if ( pSystemSid ) {
  1010. RtlFreeSid( pSystemSid );
  1011. }
  1012. if ( pLocalServiceSid ) {
  1013. RtlFreeSid( pLocalServiceSid );
  1014. }
  1015. if ( pNetworkServiceSid ) {
  1016. RtlFreeSid( pNetworkServiceSid );
  1017. }
  1018. if (pSd) {
  1019. LocalFree(pSd);
  1020. }
  1021. return hPipe;
  1022. }