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.

1271 lines
36 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: launch.cxx
  7. //
  8. // Contents:
  9. //
  10. // History: ?-??-?? ??? Created
  11. // 6-17-99 a-sergiv Added event log filtering
  12. //
  13. //--------------------------------------------------------------------------
  14. #include "act.hxx"
  15. #include <winbasep.h> // For CreateProcessInternalW
  16. extern "C" {
  17. #include <execsrv.h>
  18. }
  19. #include "execclt.hxx"
  20. const ULONG MAX_SERVICE_ARGS = 16;
  21. const WCHAR REGEVENT_PREFIX[] = L"RPCSS_REGEVENT:";
  22. const DWORD REGEVENT_PREFIX_STRLEN = sizeof(REGEVENT_PREFIX) / sizeof(WCHAR) - 1;
  23. const WCHAR INITEVENT_PREFIX[] = L"RPCSS_INITEVENT:";
  24. const DWORD INITEVENT_PREFIX_STRLEN = sizeof(INITEVENT_PREFIX) / sizeof(WCHAR) - 1;
  25. extern "C"
  26. {
  27. HANDLE
  28. GetCurrentUserTokenW(WCHAR Winsta[],
  29. DWORD DesiredAccess);
  30. };
  31. //
  32. // Small wrapper class around userenv.dll, so we don't have to link to it.
  33. //
  34. class CUserEnv
  35. {
  36. typedef BOOL (WINAPI *PFNCREATEENVBLOCK) (LPVOID *, HANDLE, BOOL);
  37. typedef BOOL (WINAPI *PFNDESTROYENVBLOCK) (LPVOID);
  38. public:
  39. CUserEnv()
  40. {
  41. // Load the DLL, null out the function pointers.
  42. _hUserEnv = LoadLibrary(L"userenv.dll");
  43. _pfnCreateEnvironmentBlock = NULL;
  44. _pfnDestroyEnvironmentBlock = NULL;
  45. }
  46. ~CUserEnv()
  47. {
  48. // Null the function pointers, unload the DLL.
  49. _pfnCreateEnvironmentBlock = NULL;
  50. _pfnDestroyEnvironmentBlock = NULL;
  51. if (_hUserEnv)
  52. FreeLibrary(_hUserEnv);
  53. }
  54. void Init()
  55. {
  56. // If we loaded the DLL ok, go get the function pointers.
  57. if (_hUserEnv)
  58. {
  59. _pfnCreateEnvironmentBlock = (PFNCREATEENVBLOCK)GetProcAddress(_hUserEnv,
  60. "CreateEnvironmentBlock");
  61. _pfnDestroyEnvironmentBlock = (PFNDESTROYENVBLOCK)GetProcAddress(_hUserEnv,
  62. "DestroyEnvironmentBlock");
  63. }
  64. }
  65. BOOL CreateEnvironmentBlock(LPVOID *lpEnvironment,
  66. HANDLE hToken,
  67. BOOL bInherit)
  68. {
  69. // Initialize on demand.
  70. if (!_pfnCreateEnvironmentBlock)
  71. Init();
  72. if (_pfnCreateEnvironmentBlock)
  73. {
  74. return _pfnCreateEnvironmentBlock(lpEnvironment,
  75. hToken,
  76. bInherit);
  77. }
  78. else
  79. {
  80. SetLastError(ERROR_PROC_NOT_FOUND);
  81. return FALSE;
  82. }
  83. }
  84. BOOL DestroyEnvironmentBlock(LPVOID lpEnvironment)
  85. {
  86. // Initialize on demand.
  87. if (!_pfnDestroyEnvironmentBlock)
  88. Init();
  89. if (_pfnDestroyEnvironmentBlock)
  90. {
  91. return _pfnDestroyEnvironmentBlock(lpEnvironment);
  92. }
  93. else
  94. {
  95. SetLastError(ERROR_PROC_NOT_FOUND);
  96. return FALSE;
  97. }
  98. }
  99. private:
  100. HMODULE _hUserEnv;
  101. PFNCREATEENVBLOCK _pfnCreateEnvironmentBlock;
  102. PFNDESTROYENVBLOCK _pfnDestroyEnvironmentBlock;
  103. } g_UserEnv;
  104. HRESULT
  105. CClsidData::GetAAASaferToken(
  106. IN CToken *pClientToken,
  107. OUT HANDLE *pTokenOut
  108. )
  109. /*++
  110. Routine Description:
  111. Get the token that will be used in an Activate As Activator
  112. launch. This token is the more restricted of the incoming
  113. token and the configured safer level.
  114. Arguments:
  115. pClientToken - token of the user doing the activation
  116. pTokenOut - out parameter that will recieve the handle to use
  117. in the activation.
  118. Return Value:
  119. S_OK: Everything went fine. The caller owns a reference on
  120. pTokenOut and must close it.
  121. S_FALSE: Everything went fine. The caller does not own a
  122. reference on pToken out and does not need to close it.
  123. Anything else: An error occured.
  124. --*/
  125. {
  126. HANDLE hSaferToken = NULL;
  127. HRESULT hr = S_OK;
  128. BOOL bStatus = TRUE;
  129. *pTokenOut = NULL;
  130. Win4Assert(SaferLevel() && "Called GetAAASaferToken with SAFER disabled!");
  131. if (!SaferLevel()) return E_UNEXPECTED;
  132. // Get the safer token for this configuration.
  133. bStatus = SaferComputeTokenFromLevel(SaferLevel(),
  134. pClientToken->GetToken(),
  135. &hSaferToken,
  136. 0,
  137. NULL);
  138. if (bStatus)
  139. {
  140. hr = pClientToken->CompareSaferLevels(hSaferToken);
  141. if (hr == S_OK)
  142. {
  143. CloseHandle(hSaferToken);
  144. hSaferToken = pClientToken->GetToken();
  145. // Shared reference, return S_FALSE.
  146. hr = S_FALSE;
  147. }
  148. else
  149. {
  150. hr = S_OK;
  151. }
  152. }
  153. else
  154. {
  155. hr = HRESULT_FROM_WIN32(GetLastError());
  156. }
  157. *pTokenOut = hSaferToken;
  158. return hr;
  159. }
  160. HRESULT
  161. CClsidData::LaunchActivatorServer(
  162. IN CToken * pClientToken,
  163. IN WCHAR * pEnvBlock,
  164. IN DWORD EnvBlockLength,
  165. IN BOOL fIsRemoteActivation,
  166. IN BOOL fClientImpersonating,
  167. IN WCHAR* pwszWinstaDesktop,
  168. IN DWORD clsctx,
  169. OUT HANDLE * phProcess,
  170. OUT DWORD * pdwProcessId
  171. )
  172. {
  173. WCHAR * pwszCommandLine;
  174. WCHAR * pFinalEnvBlock;
  175. STARTUPINFO StartupInfo;
  176. PROCESS_INFORMATION ProcessInfo;
  177. SECURITY_ATTRIBUTES saProcess;
  178. PSECURITY_DESCRIPTOR psdNewProcessSD;
  179. HRESULT hr;
  180. DWORD CreateFlags;
  181. BOOL bStatus;
  182. ULONG SessionId = 0;
  183. HANDLE hSaferToken = NULL;
  184. BOOL bCloseSaferToken = TRUE;
  185. *phProcess = NULL;
  186. *pdwProcessId = 0;
  187. if ( ! pClientToken )
  188. return (E_ACCESSDENIED);
  189. pFinalEnvBlock = NULL;
  190. StartupInfo.cb = sizeof(StartupInfo);
  191. StartupInfo.lpReserved = NULL;
  192. // Choose desktop for new server:
  193. // client remote -> system chooses desktop
  194. // client local, not impersonating -> we pick client's desktop
  195. // client local, impersonating -> system chooses desktop
  196. StartupInfo.lpDesktop = (fIsRemoteActivation || fClientImpersonating) ? L"" : pwszWinstaDesktop;
  197. StartupInfo.lpTitle = (SERVERTYPE_SURROGATE == _ServerType) ? NULL : _pwszServer;
  198. StartupInfo.dwX = 40;
  199. StartupInfo.dwY = 40;
  200. StartupInfo.dwXSize = 80;
  201. StartupInfo.dwYSize = 40;
  202. StartupInfo.dwFlags = 0;
  203. StartupInfo.wShowWindow = SW_SHOWNORMAL;
  204. StartupInfo.cbReserved2 = 0;
  205. StartupInfo.lpReserved2 = NULL;
  206. ProcessInfo.hThread = 0;
  207. ProcessInfo.hProcess = 0;
  208. ProcessInfo.dwProcessId = 0;
  209. hr = GetLaunchCommandLine( &pwszCommandLine );
  210. if ( hr != S_OK )
  211. return (hr);
  212. if ( pEnvBlock )
  213. {
  214. hr = AddAppPathsToEnv( pEnvBlock, EnvBlockLength, &pFinalEnvBlock );
  215. if ( hr != S_OK )
  216. {
  217. PrivMemFree( pwszCommandLine );
  218. return (hr);
  219. }
  220. }
  221. CreateFlags = CREATE_NEW_CONSOLE | CREATE_SUSPENDED;
  222. if ( pFinalEnvBlock )
  223. CreateFlags |= CREATE_UNICODE_ENVIRONMENT;
  224. CAccessInfo AccessInfo( pClientToken->GetSid() );
  225. //
  226. // Apply configured safer restrictions to the token we're using to launch.
  227. // SAFER might not be enabled at all, in which case we don't need to do this.
  228. //
  229. if ( gbSAFERAAAChecksEnabled && SaferLevel() )
  230. {
  231. hr = GetAAASaferToken( pClientToken, &hSaferToken );
  232. if ( FAILED(hr) ) goto LaunchServerEnd;
  233. if ( hr == S_FALSE )
  234. {
  235. // GetAAASaferToken has returned a shared reference
  236. // to pClientToken.
  237. bCloseSaferToken = FALSE;
  238. hr = S_OK;
  239. }
  240. else
  241. bCloseSaferToken = TRUE;
  242. }
  243. else
  244. {
  245. hSaferToken = pClientToken->GetToken();
  246. bCloseSaferToken = FALSE;
  247. }
  248. //
  249. // This should never fail here, but if it did that would be a really,
  250. // really bad security breach, so check it anyway.
  251. //
  252. if ( ! ImpersonateLoggedOnUser( hSaferToken ) )
  253. {
  254. hr = E_ACCESSDENIED;
  255. goto LaunchServerEnd;
  256. }
  257. //
  258. // Initialize process security info (SDs). We need both SIDs to
  259. // do this, so here is the 1st time we can. We Delete the SD right
  260. // after the CreateProcess call, no matter what happens.
  261. //
  262. psdNewProcessSD = AccessInfo.IdentifyAccess(
  263. FALSE,
  264. PROCESS_ALL_ACCESS,
  265. PROCESS_SET_INFORMATION | // Allow primary token to be set
  266. PROCESS_TERMINATE | SYNCHRONIZE // Allow screen-saver control
  267. );
  268. if ( ! psdNewProcessSD )
  269. {
  270. RevertToSelf();
  271. hr = E_OUTOFMEMORY;
  272. goto LaunchServerEnd;
  273. }
  274. saProcess.nLength = sizeof(SECURITY_ATTRIBUTES);
  275. saProcess.lpSecurityDescriptor = psdNewProcessSD;
  276. saProcess.bInheritHandle = FALSE;
  277. SessionId = fIsRemoteActivation ? 0 : pClientToken->GetSessionId();
  278. if( SessionId != 0 ) {
  279. //
  280. // We must send the request to the remote WinStation
  281. // of the requestor
  282. //
  283. // NOTE: The current WinStationCreateProcessW() does not use
  284. // the supplied security descriptor, but creates the
  285. // process under the account of the logged on user.
  286. //
  287. // We do not stuff the security descriptor, so clear the suspend flag
  288. CreateFlags &= ~CREATE_SUSPENDED;
  289. #if DBGX
  290. CairoleDebugOut((DEB_TRACE, "SCM: Sending CreateProcess to SessionId %d\n",SessionId));
  291. #endif
  292. // Non-zero sessions have only one winstation/desktop which is
  293. // the default one. We will ignore the winstation/desktop passed
  294. // in and use the default one.
  295. // review: Figure this out TarunA 05/07/99
  296. //StartupInfo.lpDesktop = L"WinSta0\\Default";
  297. // jsimmons 4/6/00 -- note that if the client was impersonating, then we won't
  298. // launch the server under the correct identity. More work needed to determine
  299. // if we can fully support this.
  300. //
  301. // Stop impersonating before doing the WinStationCreateProcess.
  302. // The remote winstation exec thread will launch the app under
  303. // the users context. We must not be impersonating because this
  304. // call only lets SYSTEM request the remote execute.
  305. //
  306. RevertToSelf();
  307. HANDLE hDuplicate = NULL;
  308. // We need to pass in the SAFER blessed token to TS so that the
  309. // server can use that token
  310. // TS code will call CreateProcessAsUser, so we need to get a primary token
  311. if (DuplicateTokenForSessionUse(hSaferToken, &hDuplicate))
  312. {
  313. if (bCloseSaferToken)
  314. {
  315. CloseHandle(hSaferToken);
  316. }
  317. hSaferToken = hDuplicate;
  318. bCloseSaferToken = TRUE;
  319. bStatus = CreateRemoteSessionProcess(
  320. SessionId,
  321. hSaferToken,
  322. FALSE, // Run as Logged on USER
  323. NULL, // application name
  324. pwszCommandLine, // command line
  325. &saProcess, // process sec attributes
  326. NULL, // default thread sec attributes
  327. // (this was &saThread, but isn't needed)
  328. FALSE, // dont inherit handles
  329. CreateFlags, // creation flags
  330. pFinalEnvBlock, // use same enviroment block as the client
  331. NULL, // use same directory
  332. &StartupInfo, // startup info
  333. &ProcessInfo // proc info returned
  334. );
  335. }
  336. }
  337. else
  338. {
  339. //
  340. // Do the exec while impersonating so the file access gets ACL
  341. // checked correctly. Create the app suspended so we can stuff
  342. // a new token and resume the process.
  343. //
  344. HANDLE hNewSaferToken = NULL;
  345. //
  346. // We need to use CreateProcessInternalW so that SAFER gets a chance
  347. // to play with the token (some more).
  348. //
  349. bStatus = CreateProcessInternalW(
  350. hSaferToken,
  351. NULL,
  352. pwszCommandLine,
  353. &saProcess,
  354. NULL,
  355. FALSE,
  356. CreateFlags,
  357. pFinalEnvBlock,
  358. NULL,
  359. &StartupInfo,
  360. &ProcessInfo,
  361. &hNewSaferToken);
  362. //
  363. // Everything else we do as ourself.
  364. //
  365. RevertToSelf();
  366. if (bStatus && hNewSaferToken)
  367. {
  368. if (bCloseSaferToken)
  369. {
  370. CloseHandle(hSaferToken);
  371. }
  372. hSaferToken = hNewSaferToken;
  373. bCloseSaferToken = TRUE;
  374. }
  375. }
  376. if ( ! bStatus )
  377. {
  378. hr = HRESULT_FROM_WIN32( GetLastError() );
  379. LogServerStartError( &_Clsid, clsctx, pClientToken, pwszCommandLine );
  380. goto LaunchServerEnd;
  381. }
  382. //
  383. // If the process was "started" in the shared WOW, we don't stuff the token
  384. // or attempt to resume the thread. When a created process is in the shared
  385. // WOW its hThread is NULL.
  386. //
  387. //
  388. // We also only set it for the console. Remote Winstations always
  389. // launch under user security
  390. //
  391. if ( (SessionId == 0) && ( ProcessInfo.hThread ) )
  392. {
  393. // Set the primary token for the app
  394. bStatus = CreateAndSetProcessToken(
  395. &ProcessInfo,
  396. hSaferToken,
  397. pClientToken->GetSid() );
  398. if ( bStatus )
  399. {
  400. if ( ResumeThread( ProcessInfo.hThread ) == -1 )
  401. TerminateProcess( ProcessInfo.hProcess, 0 );
  402. }
  403. if ( ! bStatus )
  404. hr = HRESULT_FROM_WIN32( GetLastError() );
  405. }
  406. LaunchServerEnd:
  407. if ( pFinalEnvBlock && pFinalEnvBlock != pEnvBlock )
  408. PrivMemFree( pFinalEnvBlock );
  409. if ( ProcessInfo.hThread )
  410. CloseHandle( ProcessInfo.hThread );
  411. if ( ProcessInfo.hProcess && ! bStatus )
  412. {
  413. CloseHandle( ProcessInfo.hProcess );
  414. ProcessInfo.hProcess = 0;
  415. }
  416. if ( hSaferToken && bCloseSaferToken )
  417. {
  418. CloseHandle( hSaferToken );
  419. }
  420. *phProcess = ProcessInfo.hProcess;
  421. *pdwProcessId = ProcessInfo.dwProcessId;
  422. PrivMemFree( pwszCommandLine );
  423. return (hr);
  424. }
  425. //+-------------------------------------------------------------------------
  426. //
  427. // LaunchRunAsServer
  428. //
  429. //--------------------------------------------------------------------------
  430. HRESULT
  431. CClsidData::LaunchRunAsServer(
  432. IN CToken * pClientToken,
  433. IN BOOL fIsRemoteActivation,
  434. IN ActivationPropertiesIn *pActIn,
  435. IN DWORD clsctx,
  436. OUT HANDLE * phProcess,
  437. OUT DWORD * pdwProcessId,
  438. OUT void** ppvRunAsHandle
  439. )
  440. {
  441. WCHAR * pwszCommandLine;
  442. STARTUPINFO StartupInfo;
  443. PROCESS_INFORMATION ProcessInfo;
  444. HANDLE hToken;
  445. SECURITY_ATTRIBUTES saProcess;
  446. PSECURITY_DESCRIPTOR psdNewProcessSD;
  447. PSID psidUserSid;
  448. HRESULT hr;
  449. BOOL bStatus;
  450. ULONG ulSessionId;
  451. BOOL bFromRunAsCache = FALSE;
  452. hr = GetLaunchCommandLine( &pwszCommandLine );
  453. if ( hr != S_OK )
  454. return (hr);
  455. *phProcess = NULL;
  456. *pdwProcessId = 0;
  457. hToken = NULL;
  458. bStatus = FALSE;
  459. StartupInfo.cb = sizeof(STARTUPINFO);
  460. StartupInfo.lpReserved = NULL;
  461. StartupInfo.lpDesktop = NULL;
  462. StartupInfo.lpTitle = (SERVERTYPE_SURROGATE == _ServerType) ? NULL : _pwszServer;
  463. StartupInfo.dwFlags = 0;
  464. StartupInfo.cbReserved2 = 0;
  465. StartupInfo.lpReserved2 = NULL;
  466. ulSessionId = 0;
  467. if( IsInteractiveUser() )
  468. {
  469. if (!fIsRemoteActivation)
  470. {
  471. if ( !ImpersonateLoggedOnUser( pClientToken->GetToken() ) )
  472. {
  473. PrivMemFree(pwszCommandLine);
  474. return E_ACCESSDENIED;
  475. }
  476. RevertToSelf();
  477. }
  478. Win4Assert(pActIn);
  479. LONG lSessIdTemp;
  480. // Query for incoming session
  481. GetSessionIDFromActParams(pActIn, &lSessIdTemp);
  482. if (lSessIdTemp != INVALID_SESSION_ID)
  483. {
  484. ulSessionId = lSessIdTemp;
  485. }
  486. // Right now force all complus to
  487. // session 0. Session based activation
  488. // is still ill defined for complus
  489. // servers.
  490. if (_ServerType == SERVERTYPE_COMPLUS)
  491. {
  492. ulSessionId = 0;
  493. }
  494. if ( ulSessionId )
  495. {
  496. //
  497. // for a session, hToken is used only to build the psdNewProcessSD
  498. // and hToken must be closed
  499. //
  500. hToken = GetShellProcessToken( ulSessionId );
  501. }
  502. else
  503. {
  504. // hToken = GetShellProcessToken();
  505. hToken = GetCurrentUserTokenW(L"WinSta0", TOKEN_ALL_ACCESS);
  506. }
  507. }
  508. else
  509. {
  510. hToken = GetRunAsToken( clsctx,
  511. AppidString(),
  512. RunAsDomain(),
  513. RunAsUser() );
  514. if (hToken)
  515. {
  516. hr = RunAsGetTokenElem(&hToken,
  517. ppvRunAsHandle);
  518. if (SUCCEEDED(hr))
  519. bFromRunAsCache = TRUE;
  520. else
  521. {
  522. Win4Assert((*ppvRunAsHandle == NULL) && "RunAsGetTokenElem failed but *ppvRunAsHandle is non-NULL");
  523. PrivMemFree( pwszCommandLine );
  524. CloseHandle(hToken);
  525. return hr;
  526. }
  527. }
  528. }
  529. if ( ! hToken )
  530. {
  531. PrivMemFree( pwszCommandLine );
  532. return (CO_E_RUNAS_LOGON_FAILURE);
  533. }
  534. psdNewProcessSD = 0;
  535. psidUserSid = GetUserSid(hToken);
  536. CAccessInfo AccessInfo(psidUserSid);
  537. // We have to get past the CAccessInfo before we can use a goto.
  538. if ( psidUserSid )
  539. {
  540. psdNewProcessSD = AccessInfo.IdentifyAccess(
  541. FALSE,
  542. PROCESS_ALL_ACCESS,
  543. PROCESS_SET_INFORMATION | // Allow primary token to be set
  544. PROCESS_TERMINATE | SYNCHRONIZE // Allow screen-saver control
  545. );
  546. }
  547. if ( ! psdNewProcessSD )
  548. {
  549. hr = E_OUTOFMEMORY;
  550. goto LaunchRunAsServerEnd;
  551. }
  552. saProcess.nLength = sizeof(SECURITY_ATTRIBUTES);
  553. saProcess.lpSecurityDescriptor = psdNewProcessSD;
  554. saProcess.bInheritHandle = FALSE;
  555. {
  556. //
  557. // Get the environment block of the user
  558. //
  559. LPVOID lpEnvBlock = NULL;
  560. bStatus = g_UserEnv.CreateEnvironmentBlock(&lpEnvBlock,hToken,FALSE);
  561. HANDLE hSaferToken = NULL;
  562. if(bStatus && SaferLevel())
  563. {
  564. bStatus = SaferComputeTokenFromLevel(SaferLevel(),
  565. hToken,
  566. &hSaferToken,
  567. 0,
  568. NULL);
  569. }
  570. else
  571. {
  572. hSaferToken = hToken;
  573. }
  574. if (bStatus && (ulSessionId != 0))
  575. {
  576. bStatus = SetTokenInformation(hSaferToken,
  577. TokenSessionId,
  578. &ulSessionId,
  579. sizeof(ulSessionId));
  580. }
  581. if(bStatus)
  582. {
  583. //
  584. // This allows the process create to work with paths to remote machines.
  585. //
  586. (void) ImpersonateLoggedOnUser( hSaferToken );
  587. bStatus = CreateProcessAsUser(hSaferToken,
  588. NULL,
  589. pwszCommandLine,
  590. &saProcess,
  591. NULL,
  592. FALSE,
  593. CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
  594. lpEnvBlock,
  595. NULL,
  596. &StartupInfo,
  597. &ProcessInfo);
  598. (void) RevertToSelf();
  599. }
  600. //
  601. // Free the environment block buffer
  602. //
  603. if (lpEnvBlock)
  604. g_UserEnv.DestroyEnvironmentBlock(lpEnvBlock);
  605. if (hSaferToken && SaferLevel())
  606. CloseHandle(hSaferToken);
  607. }
  608. if ( ! bStatus )
  609. {
  610. hr = HRESULT_FROM_WIN32( GetLastError() );
  611. LogRunAsServerStartError(
  612. &_Clsid,
  613. clsctx,
  614. pClientToken,
  615. pwszCommandLine,
  616. RunAsUser(),
  617. RunAsDomain() );
  618. goto LaunchRunAsServerEnd;
  619. }
  620. *phProcess = ProcessInfo.hProcess;
  621. *pdwProcessId = ProcessInfo.dwProcessId;
  622. NtClose( ProcessInfo.hThread );
  623. LaunchRunAsServerEnd:
  624. if ( hToken )
  625. {
  626. NtClose( hToken );
  627. }
  628. if ( psidUserSid )
  629. {
  630. PrivMemFree(psidUserSid);
  631. }
  632. PrivMemFree( pwszCommandLine );
  633. if (!bFromRunAsCache)
  634. *ppvRunAsHandle = NULL;
  635. else
  636. if (!SUCCEEDED(hr))
  637. {
  638. RunAsRelease(*ppvRunAsHandle);
  639. *ppvRunAsHandle = NULL;
  640. }
  641. return (hr);
  642. }
  643. //+-------------------------------------------------------------------------
  644. //
  645. // Member: LaunchService
  646. //
  647. //--------------------------------------------------------------------------
  648. HRESULT
  649. CClsidData::LaunchService(
  650. IN CToken * pClientToken,
  651. IN DWORD clsctx,
  652. OUT SC_HANDLE * phService
  653. )
  654. {
  655. WCHAR *pwszArgs = NULL;
  656. ULONG cArgs = 0;
  657. WCHAR *apwszArgs[MAX_SERVICE_ARGS];
  658. BOOL bStatus;
  659. HRESULT hr;
  660. ASSERT(g_hServiceController);
  661. *phService = OpenService( g_hServiceController,
  662. _pAppid->Service(),
  663. GENERIC_EXECUTE | GENERIC_READ );
  664. if ( ! *phService )
  665. return (HRESULT_FROM_WIN32( GetLastError() ));
  666. // Formulate the arguments (if any)
  667. if ( ServiceArgs() )
  668. {
  669. UINT k = 0;
  670. // Make a copy of the service arguments
  671. pwszArgs = (WCHAR *) PrivMemAlloc(
  672. (lstrlenW(ServiceArgs()) + 1) * sizeof(WCHAR));
  673. if ( pwszArgs == NULL )
  674. {
  675. CloseServiceHandle(*phService);
  676. *phService = 0;
  677. return (E_OUTOFMEMORY);
  678. }
  679. lstrcpyW(pwszArgs, ServiceArgs());
  680. // Scan the arguments
  681. do
  682. {
  683. // Scan to the next non-whitespace character
  684. while ( pwszArgs[k] &&
  685. (pwszArgs[k] == L' ' ||
  686. pwszArgs[k] == L'\t') )
  687. {
  688. k++;
  689. }
  690. // Store the next argument
  691. if ( pwszArgs[k] )
  692. {
  693. apwszArgs[cArgs++] = &pwszArgs[k];
  694. }
  695. // Scan to the next whitespace char
  696. while ( pwszArgs[k] &&
  697. pwszArgs[k] != L' ' &&
  698. pwszArgs[k] != L'\t' )
  699. {
  700. k++;
  701. }
  702. // Null terminate the previous argument
  703. if ( pwszArgs[k] )
  704. {
  705. pwszArgs[k++] = L'\0';
  706. }
  707. } while ( pwszArgs[k] );
  708. }
  709. bStatus = StartService( *phService,
  710. cArgs,
  711. cArgs > 0 ? (LPCTSTR *) apwszArgs : NULL);
  712. PrivMemFree(pwszArgs);
  713. if ( bStatus )
  714. return (S_OK);
  715. DWORD dwErr = GetLastError();
  716. hr = HRESULT_FROM_WIN32( dwErr );
  717. if ( dwErr == ERROR_SERVICE_ALREADY_RUNNING )
  718. return (hr);
  719. CairoleDebugOut((DEB_ERROR,
  720. "StartService %ws failed, error = %#x\n",_pAppid->Service(),GetLastError()));
  721. CloseServiceHandle(*phService);
  722. *phService = 0;
  723. LogServiceStartError(
  724. &_Clsid,
  725. clsctx,
  726. pClientToken,
  727. _pAppid->Service(),
  728. ServiceArgs(),
  729. dwErr );
  730. return (hr);
  731. }
  732. //+-------------------------------------------------------------------------
  733. //
  734. // LaunchAllowed
  735. //
  736. //--------------------------------------------------------------------------
  737. BOOL
  738. CClsidData::LaunchAllowed(
  739. IN CToken * pClientToken,
  740. IN DWORD clsctx
  741. )
  742. {
  743. BOOL bStatus;
  744. #if DBG
  745. WCHAR wszUser[MAX_PATH];
  746. ULONG cchSize = MAX_PATH;
  747. if (pClientToken != NULL)
  748. {
  749. pClientToken->Impersonate();
  750. GetUserName( wszUser, &cchSize );
  751. pClientToken->Revert();
  752. }
  753. else
  754. {
  755. lstrcpyW( wszUser, L"Anonymous" );
  756. }
  757. CairoleDebugOut((DEB_TRACE, "RPCSS : CClsidData::LaunchAllowed on %ws\n", wszUser));
  758. #endif
  759. if ( LaunchPermission() )
  760. bStatus = CheckForAccess( pClientToken, LaunchPermission() );
  761. else
  762. {
  763. CSecDescriptor* pSD = GetDefaultLaunchPermissions();
  764. if (pSD)
  765. {
  766. bStatus = CheckForAccess( pClientToken, pSD->GetSD() );
  767. pSD->DecRefCount();
  768. }
  769. else
  770. bStatus = FALSE;
  771. }
  772. if ( ! bStatus )
  773. {
  774. LogLaunchAccessFailed(
  775. &_Clsid,
  776. clsctx,
  777. pClientToken,
  778. 0 == LaunchPermission() );
  779. }
  780. return (bStatus);
  781. }
  782. HRESULT
  783. CClsidData::GetLaunchCommandLine(
  784. OUT WCHAR ** ppwszCommandLine
  785. )
  786. {
  787. DWORD AllocBytes;
  788. *ppwszCommandLine = 0;
  789. if ( (SERVERTYPE_EXE16 == _ServerType) || (SERVERTYPE_EXE32 == _ServerType) )
  790. {
  791. AllocBytes = ( 1 + lstrlenW( L"-Embedding" ) +
  792. 1 + lstrlenW( _pwszServer ) ) * sizeof(WCHAR);
  793. *ppwszCommandLine = (WCHAR *) PrivMemAlloc( AllocBytes );
  794. if ( *ppwszCommandLine != NULL )
  795. {
  796. lstrcpyW( *ppwszCommandLine, _pwszServer );
  797. lstrcatW( *ppwszCommandLine, L" -Embedding" );
  798. }
  799. }
  800. else
  801. {
  802. ASSERT( SERVERTYPE_SURROGATE == _ServerType
  803. || SERVERTYPE_COMPLUS == _ServerType
  804. || SERVERTYPE_DLLHOST == _ServerType );
  805. AllocBytes = ( 1 + lstrlenW( DllSurrogate() ) ) * sizeof(WCHAR);
  806. *ppwszCommandLine = (WCHAR *) PrivMemAlloc( AllocBytes );
  807. if ( *ppwszCommandLine != NULL )
  808. {
  809. lstrcpyW( *ppwszCommandLine, DllSurrogate() );
  810. }
  811. }
  812. return (*ppwszCommandLine ? S_OK : E_OUTOFMEMORY);
  813. }
  814. #define EXENAMELEN 32
  815. HANDLE
  816. CClsidData::ServerLaunchMutex()
  817. {
  818. HANDLE hMutex;
  819. WCHAR wszMutex[EXENAMELEN+1];
  820. WCHAR * pwszPath = NULL;
  821. WCHAR * pwszExeName = NULL;
  822. if ( SERVERTYPE_SURROGATE == _ServerType )
  823. {
  824. pwszPath = DllSurrogate();
  825. // Will never be called any more, ever
  826. if ( ! pwszPath || ! *pwszPath )
  827. {
  828. Win4Assert(_pAppid);
  829. pwszPath = _pAppid->AppidString();
  830. //pwszPath = L"dllhost.exe";
  831. }
  832. }
  833. else if ( DllHostOrComPlusProcess() )
  834. {
  835. Win4Assert(_pAppid);
  836. pwszPath = _pAppid->AppidString();
  837. //pwszPath = L"dllhost.exe";
  838. }
  839. else
  840. {
  841. pwszPath = Server();
  842. }
  843. if ( !pwszPath )
  844. return (NULL);
  845. pwszExeName = pwszPath + lstrlenW( pwszPath );
  846. while ( (pwszExeName != pwszPath) && (pwszExeName[-1] != L'\\') )
  847. pwszExeName--;
  848. for ( int i = 0;
  849. pwszExeName[i] && (pwszExeName[i] != L' ') && (pwszExeName[i] != L'\t') && (i < EXENAMELEN);
  850. i++ )
  851. {
  852. wszMutex[i] = pwszExeName[i];
  853. if ( L'a' <= wszMutex[i] && wszMutex[i] <= L'z' )
  854. wszMutex[i] = (WCHAR) (L'A' + (wszMutex[i] - L'a'));
  855. }
  856. wszMutex[i] = 0;
  857. #ifndef _CHICAGO_
  858. hMutex = CreateMutex(NULL, FALSE, wszMutex);
  859. #else
  860. char szMutex[EXENAMELEN+1];
  861. int Status;
  862. Status = WideCharToMultiByte(
  863. CP_ACP,
  864. 0,
  865. wszMutex,
  866. lstrlenW( wszMutex ),
  867. szMutex,
  868. sizeof(szMutex),
  869. NULL,
  870. NULL );
  871. if ( ! Status )
  872. return (0);
  873. hMutex = CreateMutex( NULL, FALSE, szMutex );
  874. #endif
  875. if ( hMutex )
  876. WaitForSingleObject( hMutex, INFINITE );
  877. return (hMutex);
  878. }
  879. //
  880. // CClsidData::ServerRegisterEvent
  881. //
  882. // Returns a handle to the appropriate register
  883. // event for the server in question.
  884. //
  885. HANDLE
  886. CClsidData::ServerRegisterEvent()
  887. {
  888. if ( DllHostOrComPlusProcess() )
  889. {
  890. // For dllhost\com+ surrogates, we delegate to the appid
  891. ASSERT(_pAppid);
  892. return _pAppid->ServerRegisterEvent();
  893. }
  894. // Prefix the string with a special string; objects with guid
  895. // names are just a touch too common for me to feel comfortable
  896. // otherwise.
  897. WCHAR wszEventName[GUIDSTR_MAX + sizeof(REGEVENT_PREFIX)];
  898. memcpy(wszEventName, REGEVENT_PREFIX, sizeof(REGEVENT_PREFIX));
  899. memcpy(wszEventName + REGEVENT_PREFIX_STRLEN, _wszClsid, sizeof(_wszClsid));
  900. return CreateEvent(NULL, FALSE, FALSE, wszEventName);
  901. }
  902. //
  903. // CClsidData::ServerInitializedEvent
  904. //
  905. // Returns a handle to the appropriate register
  906. // event for the server in question. This event is
  907. // signaled when initialization is finished.
  908. //
  909. HANDLE
  910. CAppidData::ServerInitializedEvent()
  911. {
  912. // Prefix the string with a special string; objects with guid
  913. // names are just a touch too common for me to feel comfortable
  914. // otherwise.
  915. WCHAR wszEventName[GUIDSTR_MAX + sizeof(INITEVENT_PREFIX)];
  916. memcpy(wszEventName, INITEVENT_PREFIX, sizeof(INITEVENT_PREFIX));
  917. memcpy(wszEventName + INITEVENT_PREFIX_STRLEN, _wszAppid, sizeof(_wszAppid));
  918. return CreateEvent(NULL, FALSE, FALSE, wszEventName);
  919. }
  920. //
  921. // CClsidData::ServerInitializedEvent
  922. //
  923. // Returns a handle to the appropriate register
  924. // event for the server in question. This event is
  925. // signaled when initialization is finished.
  926. //
  927. // NOTE: The non-DllHost path is currently not used here.
  928. //
  929. HANDLE
  930. CClsidData::ServerInitializedEvent()
  931. {
  932. if ( DllHostOrComPlusProcess() )
  933. {
  934. // For dllhost\com+ surrogates, we delegate to the appid
  935. ASSERT(_pAppid);
  936. return _pAppid->ServerInitializedEvent();
  937. }
  938. // Prefix the string with a special string; objects with guid
  939. // names are just a touch too common for me to feel comfortable
  940. // otherwise.
  941. WCHAR wszEventName[GUIDSTR_MAX + sizeof(INITEVENT_PREFIX)];
  942. memcpy(wszEventName, INITEVENT_PREFIX, sizeof(INITEVENT_PREFIX));
  943. memcpy(wszEventName + INITEVENT_PREFIX_STRLEN, _wszClsid, sizeof(_wszClsid));
  944. return CreateEvent(NULL, FALSE, FALSE, wszEventName);
  945. }
  946. //
  947. // CAppidData::ServerRegisterEvent
  948. //
  949. // Returns a handle to the appropriate register
  950. // event for the server in question.
  951. //
  952. HANDLE
  953. CAppidData::ServerRegisterEvent()
  954. {
  955. // Prefix the string with a special string; objects with guid
  956. // names are just a touch too common for me to feel comfortable
  957. // otherwise.
  958. WCHAR wszEventName[GUIDSTR_MAX + sizeof(REGEVENT_PREFIX)];
  959. memcpy(wszEventName, REGEVENT_PREFIX, sizeof(REGEVENT_PREFIX));
  960. memcpy(wszEventName + REGEVENT_PREFIX_STRLEN, _wszAppid, sizeof(_wszAppid));
  961. return CreateEvent(NULL, FALSE, FALSE, wszEventName);
  962. }
  963. //+-------------------------------------------------------------------------
  964. //
  965. // CClsidData::AddAppPathsToEnv
  966. //
  967. // Constructs a new environment block with an exe's AppPath value from the
  968. // registry appended to the Path environment variable. Simply returns the
  969. // given environment block if the clsid's server is not a 32 bit exe or if
  970. // no AppPath is found for the exe.
  971. //
  972. //--------------------------------------------------------------------------
  973. HRESULT
  974. CClsidData::AddAppPathsToEnv(
  975. IN WCHAR * pEnvBlock,
  976. IN DWORD EnvBlockLength,
  977. OUT WCHAR ** ppFinalEnvBlock
  978. )
  979. {
  980. HKEY hAppKey;
  981. WCHAR * pwszExe;
  982. WCHAR * pwszExeEnd;
  983. WCHAR * pwszAppPath;
  984. WCHAR * pPath;
  985. WCHAR * pNewEnvBlock;
  986. WCHAR wszStr[8];
  987. WCHAR wszKeyName[APP_PATH_LEN+MAX_PATH];
  988. DWORD AppPathLength;
  989. DWORD EnvFragLength;
  990. DWORD Status;
  991. BOOL bFoundPath;
  992. pwszAppPath = 0;
  993. pNewEnvBlock = 0;
  994. *ppFinalEnvBlock = pEnvBlock;
  995. if ( _ServerType != SERVERTYPE_EXE32 )
  996. return (S_OK);
  997. //
  998. // Find the exe name by looking for the first .exe sub string which
  999. // is followed by a space or null. Only servers registered with a
  1000. // .exe binary are supported. Otherwise the parsing is ambiguous since
  1001. // the LocalServer32 can contain paths with spaces as well as optional
  1002. // arguments.
  1003. //
  1004. if ( ! FindExeComponent( _pwszServer, L" ", &pwszExe, &pwszExeEnd ) )
  1005. return (S_OK);
  1006. //
  1007. // pwszExe points to the beginning of the binary name
  1008. // pwszExeEnd points to one char past the end of the binary name
  1009. //
  1010. memcpy( wszKeyName, APP_PATH, APP_PATH_LEN * sizeof(WCHAR) );
  1011. memcpy( &wszKeyName[APP_PATH_LEN], pwszExe, (ULONG) (pwszExeEnd - pwszExe) * sizeof(WCHAR) );
  1012. wszKeyName[APP_PATH_LEN + (pwszExeEnd - pwszExe)] = 0;
  1013. Status = RegOpenKeyEx(
  1014. HKEY_LOCAL_MACHINE,
  1015. wszKeyName,
  1016. 0,
  1017. KEY_READ,
  1018. &hAppKey );
  1019. if ( ERROR_SUCCESS == Status )
  1020. {
  1021. Status = ReadStringValue( hAppKey, L"Path", &pwszAppPath );
  1022. RegCloseKey( hAppKey );
  1023. }
  1024. if ( Status != ERROR_SUCCESS )
  1025. return (S_OK);
  1026. AppPathLength = lstrlenW(pwszAppPath);
  1027. // New env block size includes space for a new ';' separator in the path.
  1028. pNewEnvBlock = (WCHAR *) PrivMemAlloc( (EnvBlockLength + 1 + AppPathLength) * sizeof(WCHAR) );
  1029. if ( ! pNewEnvBlock )
  1030. {
  1031. PrivMemFree( pwszAppPath );
  1032. return (E_OUTOFMEMORY);
  1033. }
  1034. pPath = pEnvBlock;
  1035. bFoundPath = FALSE;
  1036. for ( ; *pPath; )
  1037. {
  1038. memcpy( wszStr, pPath, 5 * sizeof(WCHAR) );
  1039. wszStr[5] = 0;
  1040. pPath += lstrlenW( pPath ) + 1;
  1041. if ( lstrcmpiW( wszStr, L"Path=" ) == 0 )
  1042. {
  1043. bFoundPath = TRUE;
  1044. break;
  1045. }
  1046. }
  1047. if ( bFoundPath )
  1048. {
  1049. pPath--;
  1050. EnvFragLength = (ULONG) (pPath - pEnvBlock);
  1051. memcpy( pNewEnvBlock,
  1052. pEnvBlock,
  1053. EnvFragLength * sizeof(WCHAR) );
  1054. pNewEnvBlock[EnvFragLength] = L';';
  1055. memcpy( &pNewEnvBlock[EnvFragLength + 1],
  1056. pwszAppPath,
  1057. AppPathLength * sizeof(WCHAR) );
  1058. memcpy( &pNewEnvBlock[EnvFragLength + 1 + AppPathLength],
  1059. pPath,
  1060. (EnvBlockLength - EnvFragLength) * sizeof(WCHAR) );
  1061. *ppFinalEnvBlock = pNewEnvBlock;
  1062. }
  1063. else
  1064. {
  1065. PrivMemFree( pNewEnvBlock );
  1066. }
  1067. PrivMemFree( pwszAppPath );
  1068. return (S_OK);
  1069. }