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.

851 lines
24 KiB

  1. // ----------------------------------------------------------------------------
  2. //
  3. // UManClnt.c
  4. //
  5. // Utility Manager client depending code (used by UtilMan and UManDlg)
  6. //
  7. // Author: J. Eckhardt, ECO Kommunikation
  8. // Copyright (c) 1997-1999 Microsoft Corporation
  9. //
  10. // History: created oct-98 by JE
  11. // JE nov-15-98: removed any code related to key hook
  12. // YX may-27-99: functions to start apps under current user account
  13. // YX may-29-99: apps start under user account even from LogOn desktop,
  14. // if possible
  15. // YX jun-04-99: code to report the app processes status even if they
  16. // have been started outside Utilman
  17. // YX jun-23-99: IsAdmin function added (used in the dialog)
  18. // Bug Fixes and Changes Anil Kumar 1999
  19. // ----------------------------------------------------------------------------
  20. #include <windows.h>
  21. #include <TCHAR.h>
  22. #include <WinSvc.h>
  23. #include "_UMTool.h"
  24. #include "w95trace.c"
  25. #include "UtilMan.h"
  26. #include "_UMClnt.h"
  27. #include "ums_ctrl.h"
  28. #include "w95trace.h"
  29. // Handle to the utilman instance that is showing UI
  30. HANDLE g_hUIProcess = 0;
  31. // From Terminal services
  32. extern BOOL GetWinStationUserToken(ULONG, PHANDLE);
  33. // Private User function that returns user token for session 0 only
  34. HANDLE GetCurrentUserTokenW( WCHAR WinSta[], DWORD desiredAccess);
  35. #include <psapi.h>
  36. #define MAX_NUMBER_OF_PROCESSES 2048
  37. //
  38. // RunningInMySession - returns TRUE if the specified process ID is
  39. // running in the same session as UtilMan. In Whistler, with terminal
  40. // services integrated, UtilMan is able to get information about
  41. // processes that are not running in the same session. We must
  42. // avoid impacting these processes.
  43. //
  44. BOOL RunningInMySession(DWORD dwProcessId)
  45. {
  46. DWORD dwSessionId = -1;
  47. static DWORD dwMySessionId = -1;
  48. if (-1 == dwMySessionId)
  49. {
  50. ProcessIdToSessionId(GetCurrentProcessId(), &dwMySessionId);
  51. }
  52. ProcessIdToSessionId(dwProcessId, &dwSessionId);
  53. return (dwSessionId == dwMySessionId)?TRUE:FALSE;
  54. }
  55. // These are for compiling with irnotig.lib
  56. // To be REMOVED once that becomes an API of advapi.lib
  57. PVOID MIDL_user_allocate(IN size_t BufferSize)
  58. {
  59. return( LocalAlloc(0, BufferSize));
  60. }
  61. VOID MIDL_user_free(IN PVOID Buffer)
  62. {
  63. LocalFree( Buffer );
  64. }
  65. BOOL StartAppAsUser( LPCTSTR appPath,
  66. LPTSTR cmdLine,
  67. LPSTARTUPINFO lpStartupInfo,
  68. LPPROCESS_INFORMATION lpProcessInformation);
  69. BOOL GetApplicationProcessInfo(umclient_tsp tspClient, BOOL fCloseHandle);
  70. BOOL CloseAllWindowsByProcessID(DWORD procID);
  71. // ---------------------------------
  72. BOOL StartClient(HWND hParent,umclient_tsp client)
  73. {
  74. if (client->runCount >= client->machine.MaxRunCount || client->runCount >= MAX_APP_RUNCOUNT)
  75. {
  76. DBPRINTF(_TEXT("StartClient run count >= max run count\r\n"));
  77. return FALSE;
  78. }
  79. switch (client->machine.ApplicationType)
  80. {
  81. case APPLICATION_TYPE_APPLICATION:
  82. {
  83. BOOL fStarted;
  84. TCHAR ApplicationPath[MAX_APPLICATION_PATH_LEN+100];
  85. if (!GetClientApplicationPath(
  86. client->machine.ApplicationName
  87. , ApplicationPath
  88. , MAX_APPLICATION_PATH_LEN))
  89. {
  90. return FALSE;
  91. }
  92. fStarted = StartApplication(ApplicationPath
  93. , UTILMAN_STARTCLIENT_ARG
  94. , client->user.fCanRunSecure
  95. , &client->processID[client->runCount]
  96. , &client->hProcess[client->runCount]
  97. , &client->mainThreadID[client->runCount]);
  98. if (!fStarted)
  99. {
  100. return FALSE;
  101. }
  102. client->runCount++;
  103. client->state = UM_CLIENT_RUNNING;
  104. break;
  105. }
  106. case APPLICATION_TYPE_SERVICE:
  107. {
  108. DWORD i = 0;
  109. SERVICE_STATUS ssStatus;
  110. SC_HANDLE hService;
  111. TCHAR arg2[200];
  112. LPTSTR args[2];
  113. SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  114. if (!hSCM)
  115. return FALSE;
  116. hService = OpenService(hSCM, client->machine.ApplicationName, SERVICE_ALL_ACCESS);
  117. CloseServiceHandle(hSCM);
  118. if (!hService)
  119. {
  120. return FALSE;
  121. }
  122. arg2[0] = 0;
  123. args[0] = UTILMAN_STARTCLIENT_ARG;
  124. args[1] = arg2;
  125. if (!StartService(hService,1,args))
  126. {
  127. CloseServiceHandle(hService);
  128. return FALSE;
  129. }
  130. Sleep(1000);
  131. while(QueryServiceStatus(hService, &ssStatus))
  132. {
  133. if (ssStatus.dwCurrentState == SERVICE_RUNNING)
  134. break;
  135. Sleep(1000);
  136. i++;
  137. if (i >= 60)
  138. break;
  139. }
  140. if (ssStatus.dwCurrentState != SERVICE_RUNNING)
  141. {
  142. CloseServiceHandle(hService);
  143. return FALSE;
  144. }
  145. CloseServiceHandle(hService);
  146. client->runCount++;
  147. client->processID[0] = 0;
  148. client->mainThreadID[0] = 0;
  149. client->hProcess[0] = NULL;
  150. client->state = UM_CLIENT_RUNNING;
  151. break;
  152. }
  153. default:
  154. return FALSE;
  155. }
  156. return TRUE;
  157. }
  158. // ---------------------------------
  159. // The hParent window is used to signal whether the stop is interactive
  160. // (and thus WM_COLSE could be used) or is a reaction to the desktop
  161. // change
  162. BOOL StopClient(umclient_tsp client)
  163. {
  164. if (!client->runCount || client->runCount > MAX_APP_RUNCOUNT)
  165. return FALSE;
  166. switch (client->machine.ApplicationType)
  167. {
  168. case APPLICATION_TYPE_APPLICATION:
  169. {
  170. DWORD j, runCount = client->runCount;
  171. for (j = 0; j < runCount; j++)
  172. {
  173. // If client was started outside UtilMan then try to get its process ID
  174. if (client->mainThreadID[j] == 0)
  175. {
  176. if (!GetApplicationProcessInfo(client, FALSE))
  177. {
  178. // could not find the client, so prevent attempts to stop it
  179. client->hProcess[j] = NULL;
  180. }
  181. }
  182. if (client->hProcess[j])
  183. {
  184. // Try to close the application by sending a WM_CLOSE message to
  185. // all the windows in opened by the process. Then just kill it.
  186. BOOL sent = CloseAllWindowsByProcessID(client->processID[j]);
  187. if (!sent)
  188. {
  189. TerminateProcess(client->hProcess[j],1);
  190. }
  191. client->processID[j] = 0;
  192. CloseHandle(client->hProcess[j]);
  193. client->hProcess[j] = NULL;
  194. client->mainThreadID[j] = 0;
  195. client->runCount--;
  196. if (!client->runCount)
  197. client->state = UM_CLIENT_NOT_RUNNING;
  198. }
  199. }
  200. if (runCount != client->runCount)
  201. {
  202. for (j = 0; j < (runCount-1); j++)
  203. {
  204. if (!client->hProcess[j])
  205. {
  206. memmove(&client->processID[j], &client->processID[j+1],sizeof(DWORD)*(runCount-j-1));
  207. memmove(&client->hProcess[j], &client->hProcess[j+1],sizeof(HANDLE)*(runCount-j-1));
  208. memmove(&client->mainThreadID[j], &client->mainThreadID[j+1],sizeof(DWORD)*(runCount-j-1));
  209. }
  210. }
  211. }
  212. break;
  213. }
  214. case APPLICATION_TYPE_SERVICE:
  215. {
  216. SERVICE_STATUS ssStatus;
  217. SC_HANDLE hService;
  218. SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  219. if (!hSCM)
  220. return FALSE;
  221. hService = OpenService(hSCM, client->machine.ApplicationName, SERVICE_ALL_ACCESS);
  222. CloseServiceHandle(hSCM);
  223. if (!hService)
  224. return FALSE;
  225. if (ControlService(hService, SERVICE_CONTROL_STOP, &ssStatus))
  226. {
  227. DWORD i = 0;
  228. Sleep(1000);
  229. while(QueryServiceStatus(hService, &ssStatus))
  230. {
  231. if (ssStatus.dwCurrentState == SERVICE_STOPPED)
  232. break;
  233. Sleep(1000);
  234. i++;
  235. if (i >= 60)
  236. break;
  237. }
  238. if (ssStatus.dwCurrentState != SERVICE_STOPPED)
  239. {
  240. CloseServiceHandle(hService);
  241. return FALSE;
  242. }
  243. }
  244. CloseServiceHandle(hService);
  245. client->runCount--;
  246. client->processID[0] = 0;
  247. client->hProcess[0] = NULL;
  248. client->mainThreadID[0] = 0;
  249. if (!client->runCount)
  250. client->state = UM_CLIENT_NOT_RUNNING;
  251. break;
  252. }
  253. default:
  254. return FALSE;
  255. }
  256. return TRUE;
  257. }//StopClient
  258. // ---------------------------------
  259. BOOL GetClientApplicationPath(LPTSTR ApplicationName, LPTSTR ApplicationPath,DWORD len)
  260. {
  261. HKEY hKey, sKey;
  262. DWORD ec, slen,type;
  263. ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE, UM_REGISTRY_KEY,0,KEY_READ,&hKey);
  264. if (ec != ERROR_SUCCESS)
  265. return FALSE;
  266. ec = RegOpenKeyEx(hKey,ApplicationName,0,KEY_READ,&sKey);
  267. if (ec != ERROR_SUCCESS)
  268. {
  269. RegCloseKey(hKey);
  270. return FALSE;
  271. }
  272. slen = sizeof(TCHAR)*len;
  273. ec = RegQueryValueEx(sKey,UMR_VALUE_PATH,NULL,&type,(LPBYTE)ApplicationPath,&slen);
  274. if ((ec != ERROR_SUCCESS) || (type != REG_SZ))
  275. {
  276. ApplicationPath[0] = TEXT('\0');
  277. RegCloseKey(sKey);
  278. RegCloseKey(hKey);
  279. return FALSE;
  280. }
  281. ApplicationPath[slen-1] = TEXT('\0');
  282. RegCloseKey(sKey);
  283. RegCloseKey(hKey);
  284. return (slen)?TRUE:FALSE;
  285. }//GetClientApplicationPath
  286. BOOL TestServiceClientRuns(umclient_tsp client,SERVICE_STATUS *ssStatus)
  287. {
  288. SC_HANDLE hService;
  289. SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  290. if (!hSCM)
  291. return FALSE;
  292. hService = OpenService(hSCM, client->machine.ApplicationName, SERVICE_ALL_ACCESS);
  293. CloseServiceHandle(hSCM);
  294. if (!hService)
  295. return FALSE;
  296. if (!QueryServiceStatus(hService, ssStatus) ||
  297. (ssStatus->dwCurrentState == SERVICE_STOPPED))
  298. {
  299. CloseServiceHandle(hService);
  300. return FALSE;
  301. }
  302. CloseServiceHandle(hService);
  303. return TRUE;
  304. }
  305. //
  306. // CheckStatus - Called from utilman's main timer and the dialog's timer
  307. // to detect the state of running applications and pick up
  308. // any that are started outside of utilman.
  309. //
  310. // Returns: TRUE if the state of any application has changed else FALSE
  311. //
  312. BOOL CheckStatus(umclient_tsp c, DWORD cClients)
  313. {
  314. DWORD i;
  315. BOOL fAnyChanges = FALSE;
  316. for (i = 0; i < cClients && cClients < MAX_NUMBER_OF_CLIENTS; i++)
  317. {
  318. // detect the client process started outside UMan
  319. if ( (!c[i].runCount))
  320. {
  321. if (GetApplicationProcessInfo(&c[i], TRUE))
  322. {
  323. fAnyChanges = TRUE;
  324. }
  325. }
  326. // detect clients not running anymore or not responding
  327. switch (c[i].machine.ApplicationType)
  328. {
  329. case APPLICATION_TYPE_APPLICATION:
  330. {
  331. DWORD j, dwRunCount = c[i].runCount;
  332. for (j = 0; j < dwRunCount && j < MAX_APP_RUNCOUNT; j++)
  333. {
  334. // step 1: test if terminated
  335. if (!GetProcessVersion(c[i].processID[j]))
  336. {
  337. c[i].runCount--;
  338. c[i].hProcess[j] = NULL;
  339. c[i].processID[j] = 0;
  340. c[i].mainThreadID[j] = 0;
  341. c[i].state = UM_CLIENT_NOT_RUNNING;
  342. c[i].user.fRestartOnDefaultDesk = FALSE;
  343. fAnyChanges = TRUE;
  344. continue; // its not running anymore
  345. }
  346. // step 2: test if responding (only processes started by utilman - mainThreadID != 0)
  347. if (c[i].mainThreadID[j] != 0)
  348. {
  349. if (!PostThreadMessage(c[i].mainThreadID[j],WM_QUERYENDSESSION,0,ENDSESSION_LOGOFF))
  350. {
  351. c[i].state = UM_CLIENT_NOT_RESPONDING;
  352. fAnyChanges = TRUE;
  353. continue; // its not responding
  354. }
  355. }
  356. if (c[i].state != UM_CLIENT_RUNNING)
  357. {
  358. fAnyChanges = TRUE;
  359. }
  360. c[i].state = UM_CLIENT_RUNNING;
  361. }
  362. if (dwRunCount != c[i].runCount)
  363. {
  364. for (j = 0; j < (dwRunCount-1) && j < (MAX_APP_RUNCOUNT-1); j++)
  365. {
  366. if (!c[i].processID[j])
  367. {
  368. memmove(&c[i].processID[j], &c[i].processID[j+1],sizeof(DWORD)*(dwRunCount-j-1));
  369. memmove(&c[i].hProcess[j], &c[i].hProcess[j+1],sizeof(HANDLE)*(dwRunCount-j-1));
  370. memmove(&c[i].mainThreadID[j], &c[i].mainThreadID[j+1],sizeof(DWORD)*(dwRunCount-j-1));
  371. }
  372. }
  373. }
  374. break;
  375. }
  376. case APPLICATION_TYPE_SERVICE:
  377. {
  378. SERVICE_STATUS ssStatus;
  379. if (!TestServiceClientRuns(&c[i],&ssStatus))
  380. {
  381. c[i].runCount--;
  382. c[i].processID[0] = 0;
  383. c[i].mainThreadID[0] = 0;
  384. c[i].state = UM_CLIENT_NOT_RUNNING;
  385. fAnyChanges = TRUE;
  386. }
  387. break;
  388. }
  389. }
  390. }
  391. return fAnyChanges;
  392. }
  393. __inline DWORD GetCurrentSession()
  394. {
  395. static DWORD dwSessionId = -1;
  396. if (-1 == dwSessionId)
  397. {
  398. ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId);
  399. }
  400. return dwSessionId;
  401. }
  402. // GetUserAccessToken - return the logged on user's access token
  403. //
  404. // If fNeedImpersonationToken is true the token will be an
  405. // impersonation token otherwise it will be a primary token.
  406. // The returned token will be 0 if security calls fail.
  407. //
  408. // Notes: Caller must call CloseHandle on the returned handle.
  409. //
  410. HANDLE GetUserAccessToken(BOOL fNeedImpersonationToken, BOOL *fError)
  411. {
  412. HANDLE hUserToken = 0;
  413. HANDLE hImpersonationToken = 0;
  414. *fError = FALSE;
  415. if (!GetWinStationUserToken(GetCurrentSession(), &hImpersonationToken))
  416. {
  417. // Call private API in the case where terminal services aren't running
  418. HANDLE hPrimaryToken = 0;
  419. DWORD dwFlags = TOKEN_QUERY | TOKEN_DUPLICATE;
  420. dwFlags |= (fNeedImpersonationToken)? TOKEN_IMPERSONATE : TOKEN_ASSIGN_PRIMARY;
  421. hPrimaryToken = GetCurrentUserTokenW (L"WinSta0", dwFlags);
  422. // GetCurrentUserTokenW returns a primary token; turn
  423. // it into an impersonation token if needed
  424. if (hPrimaryToken && fNeedImpersonationToken)
  425. {
  426. if (!DuplicateToken(hPrimaryToken, SecurityImpersonation, &hUserToken))
  427. {
  428. *fError = TRUE;
  429. DBPRINTF(TEXT("GetUserAccessToken: DuplicateToken returned %d\r\n"), GetLastError());
  430. }
  431. CloseHandle(hPrimaryToken);
  432. } else
  433. {
  434. // otherwise, give out the primary token even if NULL
  435. hUserToken = hPrimaryToken;
  436. }
  437. }
  438. else
  439. {
  440. // Terminal services are running see if we need primary token
  441. if (hImpersonationToken && !fNeedImpersonationToken)
  442. {
  443. if (!DuplicateTokenEx(hImpersonationToken, 0, NULL
  444. , SecurityImpersonation, TokenPrimary, &hUserToken))
  445. {
  446. *fError = TRUE;
  447. DBPRINTF(TEXT("GetUserAccessToken: DuplicateTokenEx returned %d\r\n"), GetLastError());
  448. }
  449. CloseHandle(hImpersonationToken);
  450. } else
  451. {
  452. // otherwise, give out the impersonation token even if NULL
  453. hUserToken = hImpersonationToken;
  454. }
  455. }
  456. return hUserToken;
  457. }
  458. // StartAppAsUser - start the app in the context of the logged on user
  459. //
  460. BOOL StartAppAsUser( LPCTSTR appPath, LPTSTR cmdLine,
  461. LPSTARTUPINFO lpStartupInfo,
  462. LPPROCESS_INFORMATION lpProcessInformation)
  463. {
  464. HANDLE hNewToken = 0;
  465. BOOL fStarted = FALSE;
  466. BOOL fError;
  467. // Get the our process's primary token (only succeeds if we are SYSTEM)
  468. hNewToken = GetUserAccessToken(FALSE, &fError);
  469. if (hNewToken)
  470. {
  471. // running in system context so impersonate the logged on user
  472. fStarted = CreateProcessAsUser( hNewToken, appPath,
  473. cmdLine, 0, 0, FALSE,
  474. NORMAL_PRIORITY_CLASS , 0, 0,
  475. lpStartupInfo, lpProcessInformation );
  476. CloseHandle( hNewToken );
  477. DBPRINTF(TEXT("StartAppAsUser: CreateProcessAsUser(%s, %s) returns %d\r\n"), appPath, cmdLine, fStarted);
  478. }
  479. else if (IsInteractiveUser())
  480. {
  481. TCHAR szArg[] = UTILMAN_STARTCLIENT_ARG;
  482. // Running in interactive user's context, just do normal create. Since
  483. // we are the interactive user default security descriptors will do.
  484. fStarted = CreateProcess(appPath, szArg
  485. , NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE
  486. , NULL, NULL, lpStartupInfo, lpProcessInformation);
  487. DBPRINTF(TEXT("StartAppAsUser: CreateProcess(%s, %s) returns %d\r\n"), appPath, UTILMAN_STARTCLIENT_ARG, fStarted);
  488. }
  489. // caller is going to close handles
  490. return fStarted;
  491. }
  492. // Functions to detect running copies of Accessibility utilities
  493. // FindProcess - Searches the running processes by application name. If found,
  494. // returns the process id. Else returns zero. If the process
  495. // id is returned then phProcess is the process handle. The
  496. // caller must close the process handle.
  497. //
  498. // pszApplicationName [in] - application as base.ext
  499. // phProcess [out] - pointer to memory to receive process handle
  500. //
  501. // returns the process Id.
  502. //
  503. DWORD FindProcess(LPCTSTR pszApplicationName, HANDLE *phProcess)
  504. {
  505. DWORD dwProcId = 0;
  506. DWORD adwProcess[MAX_NUMBER_OF_PROCESSES]; // array to receive the process identifiers
  507. DWORD cProcesses;
  508. DWORD dwThisProcess = GetCurrentProcessId();
  509. unsigned int i;
  510. *phProcess = 0;
  511. // Get IDs of all running processes
  512. if (!EnumProcesses(adwProcess, sizeof(adwProcess), &cProcesses))
  513. return 0;
  514. // cProcesses is returned as bytes; convert to number of processes
  515. cProcesses = cProcesses/sizeof(DWORD);
  516. if (cProcesses > MAX_NUMBER_OF_PROCESSES)
  517. cProcesses = MAX_NUMBER_OF_PROCESSES;
  518. // open each process and test against pszApplicationName
  519. for (i = 0; i < cProcesses; i++)
  520. {
  521. HANDLE hProcess;
  522. //
  523. // EnumProcesses returns process IDs across all sessions but
  524. // we are only interested in processes in our session
  525. //
  526. if (!RunningInMySession(adwProcess[i]))
  527. continue;
  528. // Skip this process
  529. if (dwThisProcess == adwProcess[i])
  530. continue;
  531. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ
  532. , FALSE, adwProcess[i]);
  533. if (hProcess != NULL)
  534. {
  535. HMODULE hMod;
  536. TCHAR szProcessName[MAX_PATH];
  537. DWORD ccbProcess;
  538. // find the module handle of exe of this process then it's base name (name.ext)
  539. if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), &ccbProcess) )
  540. {
  541. DWORD ctch = GetModuleBaseName(hProcess, hMod, szProcessName, MAX_PATH);
  542. if (ctch && _wcsicmp(szProcessName, pszApplicationName) == 0)
  543. {
  544. *phProcess = hProcess; // found it
  545. dwProcId = adwProcess[i];
  546. break;
  547. }
  548. }
  549. CloseHandle(hProcess);
  550. }
  551. }
  552. return dwProcId;
  553. }
  554. // GetApplicationProcessInfo - Tries to find the process running for this application
  555. BOOL GetApplicationProcessInfo(umclient_tsp tspClient, BOOL fCloseHandle)
  556. {
  557. DWORD dwProcId;
  558. HANDLE hProcess;
  559. TCHAR ApplicationPath[MAX_PATH];
  560. TCHAR szDrive[_MAX_DRIVE];
  561. TCHAR szPath[_MAX_PATH];
  562. TCHAR szName[_MAX_FNAME+_MAX_EXT];
  563. TCHAR szExt[_MAX_EXT];
  564. if (GetClientApplicationPath(tspClient->machine.ApplicationName, ApplicationPath, MAX_PATH))
  565. {
  566. // ApplicationPath may include path information but we need just the base name
  567. _wsplitpath(ApplicationPath, szDrive, szPath, szName, szExt);
  568. lstrcat(szName, szExt);
  569. dwProcId = FindProcess(szName, &hProcess);
  570. if (dwProcId)
  571. {
  572. tspClient->processID[0] = dwProcId;
  573. // I do not know how to get main thread ID
  574. tspClient->mainThreadID[0] = 0;
  575. tspClient->runCount = 1;
  576. tspClient->state = UM_CLIENT_RUNNING;
  577. // In order to keep the HANDLE usable, we may have to keep it open.
  578. // So, we do not close it here, but I consider it relatively safe,
  579. // since we cannot execute this code more than once without
  580. // terminating the process first (and thus closing the handle)
  581. if (fCloseHandle)
  582. {
  583. CloseHandle(hProcess);
  584. tspClient->hProcess[0] = NULL;
  585. } else
  586. {
  587. tspClient->hProcess[0] = hProcess;
  588. }
  589. return TRUE; // the application is running
  590. }
  591. }
  592. return FALSE; // the application is not running
  593. }
  594. // YX 06-15-99 [
  595. // Code to finid the window by its Process ID
  596. static BOOL SentClose;
  597. BOOL CALLBACK FindWindowByID(HWND hWnd, LPARAM lParam)
  598. {
  599. DWORD procID;
  600. if (GetWindowThreadProcessId(hWnd, &procID) != 0)
  601. {
  602. if (procID == (DWORD)lParam)
  603. {
  604. // The process, We are looking for
  605. // Send a message to close this window
  606. // CAUTION: A SendMessage is Synchronous, So It will freeze UM if the
  607. // message doenot return so PostMessage is safer or a SendMessageTimeout()
  608. // PostMessage is sufficient....
  609. PostMessage(hWnd, WM_CLOSE, 0, 0);
  610. SentClose = TRUE;
  611. }
  612. }
  613. return TRUE;
  614. }
  615. BOOL CloseAllWindowsByProcessID(DWORD procID)
  616. {
  617. BOOL rc = FALSE;
  618. SentClose = FALSE;
  619. rc = EnumWindows(FindWindowByID, (LPARAM)procID);
  620. return SentClose;
  621. }
  622. // IsAdmin - Returns TRUE if our process has admin priviliges else FALSE
  623. //
  624. BOOL IsAdmin()
  625. {
  626. BOOL fStatus = FALSE;
  627. BOOL fIsAdmin = FALSE;
  628. PSID AdministratorsSid = AdminSid(TRUE);
  629. if (AdministratorsSid)
  630. {
  631. fStatus = CheckTokenMembership(NULL, AdministratorsSid, &fIsAdmin);
  632. }
  633. return (fStatus && fIsAdmin);
  634. }
  635. // IsInteractiveUser - Returns TRUE if our process has an Interactive User SID
  636. //
  637. BOOL IsInteractiveUser()
  638. {
  639. BOOL fStatus = FALSE;
  640. BOOL fIsInteractiveUser = FALSE;
  641. PSID psidInteractive = InteractiveUserSid(TRUE);
  642. if (psidInteractive)
  643. {
  644. fStatus = CheckTokenMembership(NULL, psidInteractive, &fIsInteractiveUser);
  645. }
  646. return (fStatus && fIsInteractiveUser);
  647. }
  648. // IsSystem - Returns TRUE if our process is running as SYSTEM
  649. //
  650. BOOL IsSystem()
  651. {
  652. BOOL fStatus = FALSE;
  653. BOOL fIsLocalSystem = FALSE;
  654. SID_IDENTIFIER_AUTHORITY siaLocalSystem = SECURITY_NT_AUTHORITY;
  655. PSID psidSystem = SystemSid(TRUE);
  656. if (psidSystem)
  657. {
  658. fStatus = CheckTokenMembership(NULL, psidSystem, &fIsLocalSystem);
  659. }
  660. return (fStatus && fIsLocalSystem);
  661. }
  662. BOOL StartApplication(
  663. LPTSTR pszPath, // IN path + filename of application to start
  664. LPTSTR pszArg, // IN command line argument(s)
  665. BOOL fIsTrusted, // IN TRUE if app can run on secure desktop
  666. DWORD *pdwProcessId, // OUT if not NULL, returned process Id
  667. HANDLE *phProcess, // OUT if not NULL, returned process handle (caller must close)
  668. DWORD *pdwThreadId // OUT if not NULL, returned thread Id
  669. )
  670. {
  671. STARTUPINFO si;
  672. PROCESS_INFORMATION pi;
  673. desktop_ts desktop;
  674. BOOL fStarted;
  675. memset(&si,0,sizeof(STARTUPINFO));
  676. si.cb = sizeof(STARTUPINFO);
  677. memset(&pi,0,sizeof(PROCESS_INFORMATION));
  678. QueryCurrentDesktop(&desktop, TRUE);
  679. DBPRINTF(TEXT("StartApplication: pszPath=%s pszArg=%s fIsTrusted=%d Utilman is SYSTEM=%d\r\n"), pszPath, pszArg, fIsTrusted, IsSystem());
  680. // If not on the winlogon desktop, first try starting the app as the interactive
  681. // user. If that fails (eg. the case when OOBE runs after setup when there is
  682. // no interactive user) then, if its the winlogon desktop or utilman is running
  683. // SYSTEM and the app is trusted then use CreateProcess (the app will be running
  684. // as SYSTEM). The latter case (running SYSTEM and the app is trusted allows
  685. // applets to run when OOBE is running.
  686. fStarted = FALSE;
  687. if (desktop.type != DESKTOP_WINLOGON)
  688. {
  689. si.lpDesktop = desktop.name;
  690. fStarted = StartAppAsUser(pszPath, pszArg, &si,&pi);
  691. }
  692. if (!fStarted && (desktop.type == DESKTOP_WINLOGON || (IsSystem() && fIsTrusted)))
  693. {
  694. if (fIsTrusted)
  695. {
  696. si.lpDesktop = 0;
  697. // Since we only run trusted apps we can run with default security descriptor
  698. fStarted = CreateProcess(pszPath, pszArg, NULL, NULL, FALSE,
  699. CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi);
  700. DBPRINTF(TEXT("StartApplication: trusted CreateProcess(%s, %s) returns %d\r\n"), pszPath, pszArg, fStarted);
  701. }
  702. }
  703. if (fStarted)
  704. {
  705. if (pdwProcessId)
  706. {
  707. *pdwProcessId = pi.dwProcessId;
  708. }
  709. if (phProcess)
  710. {
  711. *phProcess = pi.hProcess;
  712. }
  713. else
  714. {
  715. CloseHandle(pi.hProcess);
  716. }
  717. if (pdwThreadId)
  718. {
  719. *pdwThreadId = pi.dwThreadId;
  720. }
  721. CloseHandle(pi.hThread);
  722. }
  723. return fStarted;
  724. }