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.

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