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.

1214 lines
30 KiB

  1. // Util.cpp : Implementation of CUtil
  2. #include "stdafx.h"
  3. #include "CompatUI.h"
  4. #include "Util.h"
  5. #include <shlobj.h>
  6. #include <shellapi.h>
  7. #include <shlwapi.h>
  8. #include <msi.h>
  9. #include <sfc.h>
  10. #include <wininet.h>
  11. #include "Aclapi.h"
  12. extern "C" {
  13. #include "shimdb.h"
  14. }
  15. #pragma warning(disable:4786)
  16. #include <string>
  17. #include <xstring>
  18. #include <map>
  19. #include <locale>
  20. #include <algorithm>
  21. #include <vector>
  22. using namespace std;
  23. /////////////////////////////////////////////////////////////////////////////
  24. // CUtil
  25. extern "C"
  26. VOID
  27. InvalidateAppcompatCacheEntry(
  28. LPCWSTR pwszDosPath
  29. );
  30. BOOL
  31. GetExePathFromObject(
  32. LPCTSTR lpszPath, // path to an arbitrary object
  33. CComBSTR& bstrExePath
  34. );
  35. typedef
  36. INSTALLSTATE (WINAPI*PMsiGetComponentPath)(
  37. LPCTSTR szProduct, // product code for client product
  38. LPCTSTR szComponent, // component ID
  39. LPTSTR lpPathBuf, // returned path
  40. DWORD *pcchBuf // buffer character count
  41. );
  42. typedef
  43. UINT (WINAPI* PMsiGetShortcutTarget)(
  44. LPCTSTR szShortcutTarget, // path to shortcut link file
  45. LPTSTR szProductCode, // fixed length buffer for product code
  46. LPTSTR szFeatureId, // fixed length buffer for feature id
  47. LPTSTR szComponentCode // fixed length buffer for component code
  48. );
  49. BOOL
  50. IsUserAdmin(
  51. void
  52. );
  53. BOOL
  54. GiveUsersWriteAccess(
  55. void
  56. );
  57. BOOL
  58. IsLUAEnabled(
  59. LPCWSTR pszLayers
  60. );
  61. wstring
  62. StrUpCase(
  63. wstring& wstr
  64. );
  65. BOOL
  66. ShimExpandEnvironmentVars(
  67. LPCTSTR lpszCmd,
  68. CComBSTR& bstr
  69. )
  70. {
  71. DWORD dwLength;
  72. LPTSTR lpBuffer = NULL;
  73. BOOL bExpanded = FALSE;
  74. if (_tcschr(lpszCmd, TEXT('%')) == NULL) {
  75. goto out;
  76. }
  77. dwLength = ExpandEnvironmentStrings(lpszCmd, NULL, 0);
  78. if (!dwLength) {
  79. goto out;
  80. }
  81. lpBuffer = new TCHAR[dwLength];
  82. if (NULL == lpBuffer) {
  83. goto out;
  84. }
  85. dwLength = ExpandEnvironmentStrings(lpszCmd, lpBuffer, dwLength);
  86. if (!dwLength) {
  87. goto out;
  88. }
  89. bstr = lpBuffer;
  90. bExpanded = TRUE;
  91. out:
  92. if (!bExpanded) {
  93. bstr = lpszCmd;
  94. }
  95. if (lpBuffer) {
  96. delete[] lpBuffer;
  97. }
  98. return bExpanded;
  99. }
  100. wstring
  101. ShimUnquotePath(
  102. LPCTSTR pwszFileName
  103. )
  104. {
  105. wstring sFileName;
  106. LPCTSTR pScan = pwszFileName;
  107. LPCTSTR pQuote;
  108. LPCTSTR pLastQuote = NULL;
  109. // skip over the leading spaces
  110. pScan += _tcsspn(pScan, TEXT(" \t"));
  111. while (*pScan) {
  112. pQuote = _tcschr(pScan, TEXT('\"'));
  113. if (NULL == pQuote) {
  114. sFileName += pScan;
  115. break;
  116. }
  117. //
  118. // we found a quote
  119. // is this the first quote we've found?
  120. if (pLastQuote == NULL) {
  121. pLastQuote = pQuote;
  122. // add the current string
  123. sFileName += wstring(pScan, (int)(pQuote-pScan));
  124. } else {
  125. // we have a closing quote
  126. ++pLastQuote;
  127. sFileName += wstring(pLastQuote, (int)(pQuote-pLastQuote));
  128. pLastQuote = NULL;
  129. }
  130. pScan = pQuote + 1;
  131. }
  132. return sFileName;
  133. }
  134. //
  135. // ShimGetPathFromCmdLine
  136. //
  137. BOOL
  138. ShimGetPathFromCmdLine(
  139. LPCTSTR pwszCmdLine,
  140. CComBSTR& StrPath
  141. )
  142. {
  143. TCHAR chSave;
  144. LPTSTR pScan = (LPTSTR)pwszCmdLine;
  145. LPTSTR pAppName;
  146. TCHAR szBuffer[MAX_PATH];
  147. DWORD dwLength;
  148. DWORD dwAttributes;
  149. BOOL bScan = FALSE;
  150. CComBSTR bstrPathName;
  151. if (*pScan == TEXT('\"')) {
  152. // seek till we find matching "
  153. pAppName = ++pScan;
  154. while (*pScan) {
  155. if (*pScan == TEXT('\"')) {
  156. break;
  157. }
  158. ++pScan;
  159. }
  160. } else {
  161. pAppName = pScan;
  162. while (*pScan) {
  163. if (_istspace(*pScan)) {
  164. bScan = TRUE;
  165. break;
  166. }
  167. ++pScan;
  168. }
  169. }
  170. while (TRUE) {
  171. chSave = *pScan;
  172. *pScan = TEXT('\0');
  173. ShimExpandEnvironmentVars(pAppName, bstrPathName);
  174. //
  175. // check whether bstrPathName is valid (failure due to memory allocation is possible)
  176. //
  177. if (!bstrPathName) {
  178. //
  179. // overloaded operator ! for CComBSTR will check whether bstrPathName == NULL
  180. //
  181. break;
  182. }
  183. //
  184. // Check this path
  185. //
  186. dwLength = SearchPathW(NULL,
  187. bstrPathName,
  188. TEXT(".exe"),
  189. CHARCOUNT(szBuffer),
  190. szBuffer,
  191. NULL);
  192. //
  193. // restore the character
  194. //
  195. *pScan = chSave;
  196. if (dwLength && dwLength < CHARCOUNT(szBuffer)) {
  197. //
  198. // check attributes
  199. //
  200. dwAttributes = GetFileAttributesW(szBuffer);
  201. if ((dwAttributes != (DWORD)-1) &&
  202. !(dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  203. //
  204. // we are mighty done
  205. //
  206. StrPath = (LPCWSTR)szBuffer;
  207. return TRUE;
  208. }
  209. }
  210. if (!bScan || *pScan == TEXT('\0')) {
  211. break;
  212. }
  213. ++pScan;
  214. while (*pScan) {
  215. if (_istspace(*pScan)) {
  216. break;
  217. }
  218. ++pScan;
  219. }
  220. }
  221. return FALSE;
  222. }
  223. //
  224. // This class allows us to change error mode on selected apis
  225. //
  226. //
  227. class CSaveErrorMode {
  228. public:
  229. CSaveErrorMode() {
  230. m_uiErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  231. }
  232. ~CSaveErrorMode() {
  233. SetErrorMode(m_uiErrorMode);
  234. }
  235. protected:
  236. UINT m_uiErrorMode;
  237. };
  238. STDMETHODIMP CUtil::IsCompatWizardDisabled(BOOL* pbDisabled)
  239. {
  240. HKEY hKey;
  241. LONG lResult;
  242. DWORD dwValue, dwSize = sizeof(dwValue);
  243. DWORD dwType;
  244. //
  245. // First, check for the whole engine being disabled.
  246. //
  247. lResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  248. POLICY_KEY_APPCOMPAT_W,
  249. 0,
  250. KEY_READ,
  251. &hKey);
  252. if (lResult == ERROR_SUCCESS) {
  253. dwValue = 0;
  254. lResult = RegQueryValueExW(hKey,
  255. POLICY_VALUE_DISABLE_ENGINE_W,
  256. 0,
  257. &dwType,
  258. (LPBYTE)&dwValue,
  259. &dwSize);
  260. RegCloseKey (hKey);
  261. }
  262. //
  263. // The default is enabled, so if we didn't find a value, treat it like the value is 0.
  264. //
  265. if (lResult != ERROR_SUCCESS || dwValue == 0) {
  266. //
  267. // Check for the proppage being disabled.
  268. //
  269. lResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  270. POLICY_KEY_APPCOMPAT_W,
  271. 0,
  272. KEY_READ,
  273. &hKey);
  274. if (lResult == ERROR_SUCCESS) {
  275. dwValue = 0;
  276. lResult = RegQueryValueExW(hKey,
  277. POLICY_VALUE_DISABLE_WIZARD_W,
  278. 0,
  279. &dwType,
  280. (LPBYTE) &dwValue, &dwSize);
  281. RegCloseKey (hKey);
  282. }
  283. //
  284. // The default is to be enabled, so if we didn't find a value, or the value is 0, then we're good to go.
  285. //
  286. }
  287. *pbDisabled = (lResult == ERROR_SUCCESS) && (dwValue != 0);
  288. return S_OK;
  289. }
  290. STDMETHODIMP CUtil::RemoveArgs(BSTR pVar, VARIANT* pRet)
  291. {
  292. // TODO: Add your implementation code here
  293. CComBSTR bstr;
  294. CSaveErrorMode ErrMode;
  295. if (!ShimGetPathFromCmdLine(pVar, bstr)) {
  296. bstr = pVar;
  297. }
  298. pRet->vt = VT_BSTR;
  299. pRet->bstrVal = bstr.Copy();
  300. return S_OK;
  301. }
  302. STDMETHODIMP CUtil::GetItemKeys(BSTR pVar, VARIANT *pRet)
  303. {
  304. CComBSTR bstr = pVar;
  305. CComBSTR bstrOut;
  306. LPWSTR pwszPermKeys;
  307. DWORD cbSize;
  308. BOOL bLayers;
  309. if (!m_Safe) {
  310. return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  311. }
  312. bLayers = SdbGetPermLayerKeys(bstr, NULL, &cbSize, GPLK_ALL);
  313. if (bLayers) {
  314. pwszPermKeys = new WCHAR[cbSize / sizeof(WCHAR)];
  315. if (pwszPermKeys == NULL) {
  316. return HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  317. }
  318. bLayers = SdbGetPermLayerKeys(bstr, pwszPermKeys, &cbSize, GPLK_ALL);
  319. if (bLayers) {
  320. bstrOut = pwszPermKeys;
  321. }
  322. delete [] pwszPermKeys;
  323. }
  324. if (!bstrOut) {
  325. pRet->vt = VT_NULL;
  326. } else {
  327. pRet->vt = VT_BSTR;
  328. pRet->bstrVal = bstrOut.Copy();
  329. }
  330. return S_OK;
  331. }
  332. STDMETHODIMP CUtil::SetItemKeys(BSTR pszPath, VARIANT* pKeys, VARIANT* pKeysMachine, BOOL *pVal)
  333. {
  334. // TODO: Add your implementation code here
  335. CComBSTR bstrKeys;
  336. CComBSTR bstrKeysMachine;
  337. BOOL bSuccess = TRUE;
  338. VARIANT varKeys;
  339. VARIANT varKeysMachine;
  340. if (!m_Safe) {
  341. return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  342. }
  343. InvalidateAppcompatCacheEntry(pszPath);
  344. if (pKeys->vt == VT_NULL || pKeys->vt == VT_EMPTY) {
  345. bSuccess &= SdbDeletePermLayerKeys(pszPath, FALSE);
  346. } else {
  347. VariantInit(&varKeys);
  348. if (SUCCEEDED(VariantChangeType(&varKeys, pKeys, 0, VT_BSTR))) {
  349. bstrKeys = varKeys.bstrVal;
  350. VariantClear(&varKeys);
  351. }
  352. if (bstrKeys) {
  353. bSuccess &= SdbSetPermLayerKeys(pszPath, bstrKeys, FALSE);
  354. }
  355. }
  356. if (IsUserAdmin()) {
  357. if (pKeysMachine->vt == VT_NULL || pKeysMachine->vt == VT_EMPTY) {
  358. bSuccess &= SdbDeletePermLayerKeys(pszPath, TRUE);
  359. } else {
  360. VariantInit(&varKeysMachine);
  361. if (SUCCEEDED(VariantChangeType(&varKeysMachine, pKeysMachine, 0, VT_BSTR))) {
  362. bstrKeysMachine = varKeysMachine.bstrVal;
  363. VariantClear(&varKeysMachine);
  364. }
  365. if (bstrKeysMachine) {
  366. bSuccess &= SdbSetPermLayerKeys(pszPath, bstrKeysMachine, TRUE);
  367. //
  368. // find whether we need to have LUA setting handled by granting write access to a common area
  369. //
  370. if (IsLUAEnabled(bstrKeysMachine)) {
  371. GiveUsersWriteAccess();
  372. }
  373. }
  374. }
  375. }
  376. *pVal = bSuccess;
  377. return S_OK;
  378. }
  379. BOOL
  380. SearchGroupForSID(
  381. DWORD dwGroup,
  382. BOOL* pfIsMember
  383. )
  384. {
  385. PSID pSID = NULL;
  386. SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
  387. BOOL fRes = TRUE;
  388. if (!AllocateAndInitializeSid(&SIDAuth,
  389. 2,
  390. SECURITY_BUILTIN_DOMAIN_RID,
  391. dwGroup,
  392. 0,
  393. 0,
  394. 0,
  395. 0,
  396. 0,
  397. 0,
  398. &pSID)) {
  399. ATLTRACE(_T("[SearchGroupForSID] AllocateAndInitializeSid failed 0x%lx\n"),
  400. GetLastError());
  401. return FALSE;
  402. }
  403. if (!CheckTokenMembership(NULL, pSID, pfIsMember)) {
  404. ATLTRACE(_T("[SearchGroupForSID] CheckTokenMembership failed 0x%x\n"),
  405. GetLastError());
  406. fRes = FALSE;
  407. }
  408. FreeSid(pSID);
  409. return fRes;
  410. }
  411. BOOL
  412. IsUserAdmin(
  413. void
  414. )
  415. {
  416. BOOL fIsUser, fIsAdmin, fIsPowerUser;
  417. if (!SearchGroupForSID(DOMAIN_ALIAS_RID_USERS, &fIsUser) ||
  418. !SearchGroupForSID(DOMAIN_ALIAS_RID_ADMINS, &fIsAdmin)) {
  419. return FALSE;
  420. }
  421. return (fIsUser && fIsAdmin);
  422. }
  423. BOOL
  424. GiveUsersWriteAccess(
  425. void
  426. )
  427. {
  428. DWORD dwRes;
  429. EXPLICIT_ACCESS ea;
  430. PACL pOldDACL;
  431. PACL pNewDACL = NULL;
  432. PSECURITY_DESCRIPTOR pSD = NULL;
  433. SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
  434. PSID pUsersSID = NULL;
  435. TCHAR szDir[MAX_PATH];
  436. ExpandEnvironmentStrings(LUA_REDIR_W, szDir, MAX_PATH);
  437. if (!CreateDirectory(szDir, NULL)) {
  438. DWORD err = GetLastError();
  439. if (GetLastError() != ERROR_ALREADY_EXISTS) {
  440. return FALSE;
  441. }
  442. }
  443. dwRes = GetNamedSecurityInfo(szDir,
  444. SE_FILE_OBJECT,
  445. DACL_SECURITY_INFORMATION,
  446. NULL,
  447. NULL,
  448. &pOldDACL,
  449. NULL,
  450. &pSD);
  451. if (ERROR_SUCCESS != dwRes) {
  452. goto Cleanup;
  453. }
  454. if (!AllocateAndInitializeSid(&SIDAuth,
  455. 2,
  456. SECURITY_BUILTIN_DOMAIN_RID,
  457. DOMAIN_ALIAS_RID_USERS,
  458. 0,
  459. 0,
  460. 0,
  461. 0,
  462. 0,
  463. 0,
  464. &pUsersSID) ) {
  465. goto Cleanup;
  466. }
  467. //
  468. // Initialize an EXPLICIT_ACCESS structure for the new ACE.
  469. //
  470. ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
  471. ea.grfAccessPermissions = FILE_GENERIC_WRITE | FILE_GENERIC_READ | DELETE;
  472. ea.grfAccessMode = GRANT_ACCESS;
  473. ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  474. ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
  475. ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  476. ea.Trustee.ptstrName = (LPTSTR)pUsersSID;
  477. //
  478. // Create a new ACL that merges the new ACE
  479. // into the existing DACL.
  480. //
  481. dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
  482. if (ERROR_SUCCESS != dwRes) {
  483. goto Cleanup;
  484. }
  485. dwRes = SetNamedSecurityInfo(szDir,
  486. SE_FILE_OBJECT,
  487. DACL_SECURITY_INFORMATION,
  488. NULL,
  489. NULL,
  490. pNewDACL,
  491. NULL);
  492. if (ERROR_SUCCESS != dwRes) {
  493. goto Cleanup;
  494. }
  495. Cleanup:
  496. if (pSD) {
  497. LocalFree(pSD);
  498. }
  499. if (pUsersSID) {
  500. FreeSid(pUsersSID);
  501. }
  502. if (pNewDACL) {
  503. LocalFree(pNewDACL);
  504. }
  505. return (dwRes == ERROR_SUCCESS);
  506. }
  507. BOOL
  508. IsLUAEnabled(
  509. LPCWSTR pszLayers
  510. )
  511. {
  512. LPCWSTR pchStart = pszLayers;
  513. LPCWSTR pch;
  514. wstring strTok;
  515. BOOL bLUAEnabled = FALSE;
  516. pchStart += wcsspn(pchStart, L"#!");
  517. while (pchStart != NULL && *pchStart != L'\0' && !bLUAEnabled) {
  518. pchStart += wcsspn(pchStart, L" \t");
  519. if (*pchStart == L'\0') {
  520. break;
  521. }
  522. pch = wcspbrk(pchStart, L" \t");
  523. if (pch == NULL) {
  524. strTok = pchStart;
  525. pchStart = NULL;
  526. } else {
  527. strTok = wstring(pchStart, (size_t)(pch - pchStart));
  528. StrUpCase(strTok);
  529. pchStart = pch;
  530. }
  531. bLUAEnabled = (strTok == L"LUA");
  532. }
  533. return bLUAEnabled;
  534. }
  535. // this method returns true when we should present the LUA checkbox and
  536. // false when we should not
  537. STDMETHODIMP CUtil::CheckAdminPrivileges(BOOL *pVal)
  538. {
  539. *pVal = IsUserAdmin();
  540. return S_OK;
  541. }
  542. STDMETHODIMP CUtil::RunApplication(BSTR pLayers, BSTR pszCmdLine, BOOL bEnableLog, DWORD* pResult)
  543. {
  544. LPCWSTR pszExt;
  545. BOOL bShellExecute = FALSE;
  546. BOOL bSuccess = FALSE;
  547. DWORD dwError = 0;
  548. DWORD dwBinaryType = 0;
  549. DWORD dwCreateProcessFlags = 0;
  550. CSaveErrorMode ErrMode;
  551. if (!m_Safe) {
  552. return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  553. }
  554. CComBSTR bstrAppName = pszCmdLine;
  555. ShimGetPathFromCmdLine(pszCmdLine, bstrAppName);
  556. CComBSTR bstrExePath;
  557. if (!bstrAppName) {
  558. dwError = ERROR_BAD_PATHNAME;
  559. goto Done;
  560. }
  561. // check if we are using .lnk file
  562. pszExt = PathFindExtension(bstrAppName);
  563. if (pszExt != NULL) {
  564. bShellExecute = !_tcsicmp(pszExt, TEXT(".lnk"));
  565. }
  566. if (!bShellExecute) { // not shell exec? check the binary
  567. if (!pszExt || (_tcsicmp(pszExt, TEXT(".cmd")) && _tcsicmp(pszExt, TEXT(".bat")))) {
  568. bShellExecute = !GetBinaryTypeW(bstrAppName, &dwBinaryType);
  569. if (!bShellExecute && (dwBinaryType == SCS_WOW_BINARY || dwBinaryType == SCS_PIF_BINARY)) {
  570. dwCreateProcessFlags |= CREATE_SEPARATE_WOW_VDM;
  571. }
  572. }
  573. }
  574. //
  575. // invalidate cache
  576. //
  577. if (::GetExePathFromObject(bstrAppName, bstrExePath)) {
  578. InvalidateAppcompatCacheEntry(bstrExePath);
  579. }
  580. SetEnvironmentVariable(TEXT("__COMPAT_LAYER"), pLayers);
  581. SetEnvironmentVariable(TEXT("SHIM_FILE_LOG"), bEnableLog ? TEXT("shim.log") : NULL);
  582. //
  583. // now we shall either ShellExecute or do a CreateProcess
  584. //
  585. if (bShellExecute) {
  586. int nLength = bstrAppName.Length() + 3;
  587. LPTSTR pszCmdLineShellExec = new TCHAR[nLength];
  588. SHELLEXECUTEINFO ShExecInfo = { 0 };
  589. if (pszCmdLineShellExec == NULL) {
  590. //
  591. // out of memory, just do a create process
  592. //
  593. goto HandleCreateProcess;
  594. }
  595. nLength = _sntprintf(pszCmdLineShellExec,
  596. nLength,
  597. TEXT("\"%s\""),
  598. (LPCTSTR)bstrAppName);
  599. if (nLength < 0) {
  600. delete[] pszCmdLineShellExec;
  601. goto HandleCreateProcess;
  602. }
  603. ShExecInfo.cbSize = sizeof(ShExecInfo);
  604. ShExecInfo.fMask = 0; //SEE_MASK_FLAG_NO_UI;
  605. ShExecInfo.lpVerb = L"open";
  606. ShExecInfo.lpFile = pszCmdLineShellExec;
  607. ShExecInfo.nShow = SW_SHOW;
  608. bSuccess = ShellExecuteEx(&ShExecInfo);
  609. if (!bSuccess || (int)((INT_PTR)ShExecInfo.hInstApp) < 32) {
  610. dwError = GetLastError();
  611. }
  612. delete[] pszCmdLineShellExec;
  613. } else {
  614. HandleCreateProcess:
  615. // get working directory
  616. TCHAR szWorkingDir[MAX_PATH];
  617. LPTSTR pAppName = (LPTSTR)bstrAppName.m_str;
  618. int nLength;
  619. LPTSTR pszWorkingDir = NULL;
  620. STARTUPINFO StartupInfo;
  621. PROCESS_INFORMATION ProcessInfo;
  622. LPTSTR pBackslash = _tcsrchr(pAppName, TEXT('\\'));
  623. if (pBackslash != NULL) {
  624. //
  625. // check for root
  626. //
  627. nLength = (int)(pBackslash - pAppName);
  628. if (nLength == 2 && pAppName[1] == TEXT(':')) {
  629. ++nLength;
  630. }
  631. _tcsncpy(szWorkingDir, pAppName, nLength);
  632. szWorkingDir[nLength] = TEXT('\0');
  633. pszWorkingDir = szWorkingDir;
  634. }
  635. ZeroMemory(&StartupInfo, sizeof(StartupInfo));
  636. StartupInfo.cb = sizeof(StartupInfo);
  637. ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
  638. bSuccess = CreateProcess(NULL,
  639. pszCmdLine,
  640. NULL,
  641. NULL,
  642. FALSE,
  643. 0,
  644. NULL,
  645. pszWorkingDir,
  646. &StartupInfo,
  647. &ProcessInfo);
  648. if (!bSuccess) {
  649. dwError = GetLastError();
  650. }
  651. if (ProcessInfo.hThread) {
  652. CloseHandle(ProcessInfo.hThread);
  653. }
  654. if (ProcessInfo.hProcess) {
  655. CloseHandle(ProcessInfo.hProcess);
  656. }
  657. }
  658. Done:
  659. *pResult = dwError;
  660. SetEnvironmentVariable(TEXT("__COMPAT_LAYER"), NULL);
  661. SetEnvironmentVariable(TEXT("SHIM_FILE_LOG") , NULL);
  662. return S_OK;
  663. }
  664. BOOL
  665. GetExePathFromLink(
  666. LPMALLOC pMalloc,
  667. LPCITEMIDLIST pidlLinkFull,
  668. LPCTSTR pszLinkFile,
  669. LPTSTR pszExePath,
  670. DWORD dwBufferSize
  671. )
  672. {
  673. IShellLink* psl = NULL;
  674. WIN32_FIND_DATA wfd;
  675. HRESULT hr;
  676. BOOL bSuccess = FALSE;
  677. TCHAR szPath[MAX_PATH];
  678. IPersistFile* ipf = NULL;
  679. IShellLinkDataList* pdl;
  680. DWORD dwFlags = 0;
  681. BOOL bMsiLink = FALSE;
  682. HMODULE hMSI = NULL;
  683. // first do the link
  684. hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  685. IID_IShellLink, (LPVOID*)&psl);
  686. if (!SUCCEEDED(hr)) {
  687. return FALSE; // we can't create link object
  688. }
  689. hr = psl->SetIDList(pidlLinkFull); // set the id list
  690. if (!SUCCEEDED(hr)) {
  691. goto out;
  692. }
  693. hr = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ipf);
  694. if (!SUCCEEDED(hr)) {
  695. goto out;
  696. }
  697. hr = ipf->Load(pszLinkFile, STGM_READ);
  698. if (!SUCCEEDED(hr)) {
  699. goto out;
  700. }
  701. //
  702. // resolve the link for now
  703. //
  704. // hr = psl->Resolve(NULL, SLR_NO_UI|SLR_NOUPDATE);
  705. //
  706. hr = psl->QueryInterface(IID_IShellLinkDataList, (LPVOID*)&pdl);
  707. if (SUCCEEDED(hr)) {
  708. hr = pdl->GetFlags(&dwFlags);
  709. bMsiLink = SUCCEEDED(hr) && (dwFlags & SLDF_HAS_DARWINID);
  710. pdl->Release();
  711. }
  712. if (bMsiLink) {
  713. //
  714. // this is msi link, we need to crack it using msi
  715. //
  716. UINT ErrCode;
  717. TCHAR szProduct [MAX_PATH];
  718. TCHAR szFeatureId [MAX_PATH];
  719. TCHAR szComponentCode[MAX_PATH];
  720. INSTALLSTATE is;
  721. hMSI = LoadLibrary(TEXT("Msi.dll"));
  722. if (NULL == hMSI) {
  723. goto out;
  724. }
  725. PMsiGetComponentPath pfnGetComponentPath = (PMsiGetComponentPath )GetProcAddress(hMSI, "MsiGetComponentPathW");
  726. PMsiGetShortcutTarget pfnGetShortcutTarget = (PMsiGetShortcutTarget)GetProcAddress(hMSI, "MsiGetShortcutTargetW");
  727. if (!pfnGetComponentPath || !pfnGetShortcutTarget)
  728. {
  729. goto out;
  730. }
  731. ErrCode = pfnGetShortcutTarget(pszLinkFile,
  732. szProduct,
  733. szFeatureId,
  734. szComponentCode);
  735. if (ERROR_SUCCESS != ErrCode) {
  736. goto out;
  737. }
  738. *pszExePath = TEXT('\0');
  739. is = pfnGetComponentPath(szProduct, szComponentCode, pszExePath, &dwBufferSize);
  740. bSuccess = (INSTALLSTATE_LOCAL == is);
  741. } else {
  742. hr = psl->GetPath(pszExePath, dwBufferSize, &wfd, 0);
  743. bSuccess = SUCCEEDED(hr);
  744. }
  745. out:
  746. if (hMSI) {
  747. FreeLibrary(hMSI);
  748. }
  749. if (NULL != ipf) {
  750. ipf->Release();
  751. }
  752. if (NULL != psl) {
  753. psl->Release();
  754. }
  755. return bSuccess;
  756. }
  757. BOOL
  758. GetExePathFromObject(
  759. LPCTSTR lpszPath, // path to an arbitrary object
  760. CComBSTR& bstrExePath
  761. )
  762. {
  763. IShellFolder* psh = NULL;
  764. LPMALLOC pMalloc = NULL;
  765. HRESULT hr;
  766. LPITEMIDLIST pidl = NULL;
  767. DWORD dwAttributes;
  768. CComBSTR bstr;
  769. BOOL bSuccess = FALSE;
  770. hr = SHGetMalloc(&pMalloc);
  771. if (!SUCCEEDED(hr)) {
  772. goto cleanup;
  773. }
  774. hr = SHGetDesktopFolder(&psh);
  775. if (!SUCCEEDED(hr)) {
  776. goto cleanup;
  777. }
  778. if (!ShimGetPathFromCmdLine(lpszPath, bstr)) {
  779. goto cleanup;
  780. }
  781. //
  782. // parse display name
  783. //
  784. dwAttributes = SFGAO_LINK | SFGAO_FILESYSTEM | SFGAO_VALIDATE;
  785. hr = psh->ParseDisplayName(NULL,
  786. NULL,
  787. bstr, // path to the executable file
  788. NULL, // number of chars eaten
  789. &pidl,
  790. &dwAttributes);
  791. if (!SUCCEEDED(hr)) {
  792. goto cleanup;
  793. }
  794. //
  795. // display name parsed, check whether it's a link
  796. //
  797. if (dwAttributes & SFGAO_LINK) {
  798. TCHAR szExePath[MAX_PATH];
  799. //
  800. // it's a link, crack it
  801. //
  802. bSuccess = GetExePathFromLink(pMalloc,
  803. pidl,
  804. bstr,
  805. szExePath,
  806. CHARCOUNT(szExePath));
  807. // after recovering the path -- get the env vars expanded
  808. if (bSuccess) {
  809. ShimExpandEnvironmentVars(szExePath, bstrExePath);
  810. }
  811. } else if (dwAttributes & SFGAO_FILESYSTEM) {
  812. //
  813. // filesystem object (a file)
  814. //
  815. bstrExePath = bstr;
  816. bSuccess = TRUE;
  817. }
  818. cleanup:
  819. if (pidl) {
  820. pMalloc->Free(pidl);
  821. }
  822. if (psh) {
  823. psh->Release();
  824. }
  825. if (pMalloc) {
  826. pMalloc->Release();
  827. }
  828. return bSuccess;
  829. }
  830. STDMETHODIMP CUtil::GetExePathFromObject(BSTR pszPath, VARIANT* pExePath)
  831. {
  832. CComBSTR bstrExePath;
  833. BOOL bSuccess;
  834. CSaveErrorMode ErrMode;
  835. if (!m_Safe) {
  836. return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  837. }
  838. bSuccess = ::GetExePathFromObject(pszPath, bstrExePath);
  839. if (bSuccess) {
  840. pExePath->vt = VT_BSTR;
  841. pExePath->bstrVal = bstrExePath.Copy();
  842. } else {
  843. pExePath->vt = VT_NULL;
  844. }
  845. return S_OK;
  846. }
  847. STDMETHODIMP CUtil::IsSystemTarget(BSTR bstrPath, BOOL *pbSystemTarget)
  848. {
  849. CComBSTR bstrExePath;
  850. BOOL bSystemTarget = FALSE;
  851. DWORD dwAttributes;
  852. CSaveErrorMode ErrMode;
  853. /*++
  854. //
  855. // This code was used to check system directory
  856. //
  857. ULONG uSize;
  858. int nch;
  859. TCHAR szSystemDir[MAX_PATH];
  860. TCHAR szCommonPath[MAX_PATH];
  861. uSize = ::GetSystemWindowsDirectory(szSystemDir,
  862. CHARCOUNT(szSystemDir));
  863. if (uSize == 0 || uSize > CHARCOUNT(szSystemDir)) {
  864. *pbSystemTarget = FALSE;
  865. return S_OK;
  866. }
  867. --*/
  868. if (!::GetExePathFromObject(bstrPath, bstrExePath)) {
  869. bstrExePath = bstrPath;
  870. }
  871. if (!bstrExePath) {
  872. goto Done;
  873. }
  874. /*++
  875. // this code was used before -- it checked system directory as
  876. // well as sfc, we are only checking sfc now
  877. nch = PathCommonPrefix(szSystemDir, bstrExePath, szCommonPath);
  878. bSystemTarget = (nch == (int)uSize);
  879. if (!bSystemTarget) {
  880. bSystemTarget = SfcIsFileProtected(NULL, bstrExePath);
  881. }
  882. --*/
  883. bSystemTarget = SfcIsFileProtected(NULL, bstrExePath);
  884. if (!bSystemTarget) {
  885. dwAttributes = GetFileAttributes(bstrExePath);
  886. bSystemTarget = (dwAttributes == (DWORD)-1 || (dwAttributes & FILE_ATTRIBUTE_DIRECTORY));
  887. }
  888. Done:
  889. *pbSystemTarget = bSystemTarget;
  890. return S_OK;
  891. }
  892. STDMETHODIMP CUtil::IsExecutableFile(BSTR bstrPath, BOOL *pbExecutableFile)
  893. {
  894. BOOL bExecutable = FALSE;
  895. DWORD dwExeType = 0;
  896. CComBSTR bstrExePath;
  897. LPCWSTR pszExt;
  898. CSaveErrorMode ErrMode;
  899. if (!m_Safe) {
  900. return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  901. }
  902. if (!::GetExePathFromObject(bstrPath, bstrExePath)) {
  903. bstrExePath = bstrPath;
  904. }
  905. if (!bstrExePath) {
  906. //
  907. // this could happen on a memory allocation failure path
  908. //
  909. goto Done;
  910. }
  911. bExecutable = GetBinaryTypeW(bstrExePath, &dwExeType);
  912. if (!bExecutable) {
  913. // is this a batch file? if not -- you are out!
  914. pszExt = PathFindExtension(bstrPath);
  915. if (pszExt != NULL) {
  916. bExecutable = !_tcsicmp(pszExt, TEXT(".bat")) ||
  917. !_tcsicmp(pszExt, TEXT(".cmd"));
  918. }
  919. }
  920. Done:
  921. *pbExecutableFile = bExecutable;
  922. return S_OK;
  923. }
  924. ////////////////////////////////////////////////////////////////////////////////////
  925. //
  926. // Security: Check for invocation via the hcp protocol and system as the host
  927. //
  928. //
  929. BOOL
  930. CheckHost(
  931. IUnknown* pObjectClientSite
  932. )
  933. {
  934. HRESULT hr;
  935. CComPtr<IOleClientSite> spClientSite;
  936. BSTR bstrURL = NULL;
  937. TCHAR szScheme[INTERNET_MAX_SCHEME_LENGTH];
  938. TCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH];
  939. URL_COMPONENTS UrlComponents = { 0 };
  940. BOOL bHostVerified = FALSE;
  941. if (pObjectClientSite == NULL) {
  942. return FALSE;
  943. }
  944. CComQIPtr<IServiceProvider, &IID_IServiceProvider> spServiceProvider(pObjectClientSite);
  945. if (spServiceProvider == NULL) {
  946. return FALSE;
  947. }
  948. CComPtr<IWebBrowser2> spBrowser;
  949. hr = spServiceProvider->QueryService(SID_SWebBrowserApp,
  950. IID_IWebBrowser2,
  951. reinterpret_cast<void**>(&spBrowser));
  952. if (!SUCCEEDED(hr)) {
  953. return FALSE;
  954. }
  955. //
  956. // we have browser i/f -- get url now
  957. //
  958. hr = spBrowser->get_LocationURL(&bstrURL);
  959. if (!SUCCEEDED(hr) || bstrURL == NULL) {
  960. return FALSE;
  961. }
  962. //
  963. // crack the url
  964. //
  965. UrlComponents.dwStructSize = sizeof(UrlComponents);
  966. UrlComponents.lpszScheme = szScheme;
  967. UrlComponents.dwSchemeLength = CHARCOUNT(szScheme);
  968. UrlComponents.lpszHostName = szHostName;
  969. UrlComponents.dwHostNameLength = CHARCOUNT(szHostName);
  970. if (!InternetCrackUrl(bstrURL, 0, 0, &UrlComponents)) {
  971. goto cleanup;
  972. }
  973. //
  974. // now we should be good to go to check scheme and the host name
  975. //
  976. if (_tcsicmp(UrlComponents.lpszScheme, TEXT("hcp")) != 0 ) {
  977. //
  978. // bad protocol
  979. //
  980. goto cleanup;
  981. }
  982. if (_tcsicmp(UrlComponents.lpszHostName, TEXT("system")) != 0) {
  983. //
  984. // bad host
  985. //
  986. goto cleanup;
  987. }
  988. bHostVerified = TRUE;
  989. cleanup:
  990. if (bstrURL) {
  991. SysFreeString(bstrURL);
  992. }
  993. return bHostVerified;
  994. }