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.

1135 lines
32 KiB

  1. #include "stdafx.h"
  2. #include <wininet.h>
  3. #include "CommonFuncs.h"
  4. #include "FileHash.h"
  5. #define SAFE_LOCAL_SCRIPTS_KEY TEXT("Software\\Microsoft\\WBEM\\SafeLocalScripts")
  6. #define VS_PATH_KEY TEXT("Software\\Microsoft\\VisualStudio\\7.0\\Setup\\VS")
  7. #define DEVENV_VALUE TEXT("VS7EnvironmentLocation")
  8. #define VC_PATH_KEY TEXT("Software\\Microsoft\\VisualStudio\\7.0\\Setup\\VC")
  9. #define VC_PRODUCTDIR_VALUE TEXT("ProductDir")
  10. #define VS_VER_INDEPENDANT_PATH_KEY TEXT("Software\\Microsoft\\VisualStudio")
  11. TCHAR strVSPathKey[MAX_PATH * 2]= VS_PATH_KEY;
  12. TCHAR strVCPathKey[MAX_PATH * 2] = VC_PATH_KEY;
  13. HRESULT ConvertToTString(BSTR strPath,TCHAR **ppStr);
  14. // QUESTIONS:
  15. // - What is passed to SetSite when we are create in script?
  16. // - If we are passed an IOleClientSite, is it a good idea to QueryService for
  17. // an IWebBrowserApp?
  18. // - Is there a better way to get the IHTMLDocument2 when we are created through
  19. // script?
  20. // Here are some general notes about what I've observed when creating objects
  21. // in HTML with IE 5.x.
  22. // Observed IE 5.x Behavior
  23. // If an object implements IOleObject AND IObjectWithSite
  24. // - For objects created in an HTML page with an <OBJECT...> tag, IE calls
  25. // IOleObject::SetClientSite and passes an IOleClientSite object
  26. // - For object created in script of HTML page using JScript
  27. // 'new ActiveXObject' or VBScript 'CreateObject' function, IE calls
  28. // IObjectWithSite::SetSite with a ??? object
  29. // If an object implements IObjectWithSite (and NOT IOleObject)
  30. // - For object created in HTML page with <OBJECT...> tag, IE calls
  31. // IObjectWithSite::SetSite and passes an IOleClientSite object
  32. // - For object created in script of HTML page using JScript
  33. // 'new ActiveXObject' or VBScript 'CreateObject' function, IE calls
  34. // IObjectWithSite::SetSite with a ??? object
  35. // BYTE *pbData = NULL;
  36. // DWORD dwSize;
  37. // GetSourceFromDoc(pDoc, &pbData, &dwSize);
  38. // Get the original source to the document specified by pDoc
  39. HRESULT GetSourceFromDoc(IHTMLDocument2 *pDoc, BYTE **ppbData, DWORD *pdwSize)
  40. {
  41. HRESULT hr = E_FAIL;
  42. IPersistStreamInit *pPersistStreamInit = NULL;
  43. IStream *pStream = NULL;
  44. *ppbData = NULL;
  45. __try
  46. {
  47. if(FAILED(hr = pDoc->QueryInterface(IID_IPersistStreamInit, (void**) &pPersistStreamInit)))
  48. __leave;
  49. if (FAILED(hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream)))
  50. __leave;
  51. if(FAILED(hr = pPersistStreamInit->Save(pStream, TRUE)))
  52. __leave;
  53. // We are not responsible for freeing this HGLOBAL
  54. HGLOBAL hGlobal = NULL;
  55. if(FAILED(hr = GetHGlobalFromStream(pStream, &hGlobal)))
  56. __leave;
  57. STATSTG ss;
  58. if(FAILED(hr = pStream->Stat(&ss, STATFLAG_NONAME)))
  59. __leave;
  60. // This should never happen
  61. if(ss.cbSize.HighPart != 0)
  62. __leave;
  63. if(NULL == ((*ppbData) = new BYTE[ss.cbSize.LowPart]))
  64. __leave;
  65. LPVOID pHTMLText = NULL;
  66. if(NULL == (pHTMLText = GlobalLock(hGlobal)))
  67. __leave;
  68. *pdwSize = ss.cbSize.LowPart;
  69. memcpy(*ppbData, pHTMLText, ss.cbSize.LowPart);
  70. GlobalUnlock(hGlobal);
  71. hr = S_OK;
  72. }
  73. __finally
  74. {
  75. // If we did not finish, but we allocated memory, we free it.
  76. if(FAILED(hr) && (*ppbData)!=NULL)
  77. delete [] (*ppbData);
  78. if(pPersistStreamInit)
  79. pPersistStreamInit->Release();
  80. if(pStream)
  81. pStream->Release();
  82. }
  83. return hr;
  84. }
  85. // For a control specified by pUnk, get the IServiceProvider of the host
  86. HRESULT GetSiteServices(IUnknown *pUnk, IServiceProvider **ppServProv)
  87. {
  88. HRESULT hr = E_FAIL;
  89. IOleObject *pOleObj = NULL;
  90. IObjectWithSite *pObjWithSite = NULL;
  91. IOleClientSite *pSite = NULL;
  92. __try
  93. {
  94. // Check if the ActiveX control supports IOleObject.
  95. if(SUCCEEDED(pUnk->QueryInterface(IID_IOleObject, (void**)&pOleObj)))
  96. {
  97. // If the control was created through an <OBJECT...> tag, IE will
  98. // have passed us an IOleClientSite. If we have not been passed
  99. // an IOleClientSite, GetClientSite will still SUCCEED, but pSite
  100. // will be NULL. In this case, we just go to the next section.
  101. if(SUCCEEDED(pOleObj->GetClientSite(&pSite)) && pSite)
  102. {
  103. hr = pSite->QueryInterface(IID_IServiceProvider, (void**)ppServProv);
  104. // At this point, we are done and do not want to process the
  105. // code in the next seciont
  106. __leave;
  107. }
  108. }
  109. // At this point, one of two things has happened:
  110. // 1) We didn't support IOleObject
  111. // 2) We supported IOleObject, but we were never passed an IOleClientSite
  112. // In either case, we now need to look at IObjectWithSite to try to get
  113. // to our site
  114. if(FAILED(hr = pUnk->QueryInterface(IID_IObjectWithSite, (void**)&pObjWithSite)))
  115. __leave;
  116. hr = pObjWithSite->GetSite(IID_IServiceProvider, (void**)ppServProv);
  117. }
  118. __finally
  119. {
  120. // Release any interfaces we used along the way
  121. if(pOleObj)
  122. pOleObj->Release();
  123. if(pObjWithSite)
  124. pObjWithSite->Release();
  125. if(pSite)
  126. pSite->Release();
  127. }
  128. return hr;
  129. }
  130. // This function shows how to get to the IHTMLDocument2 that created an
  131. // arbitrary control represented by pUnk
  132. HRESULT GetDocument(IUnknown *pUnk, IHTMLDocument2 **ppDoc)
  133. {
  134. HRESULT hr = E_FAIL;
  135. IServiceProvider* pServProv = NULL;
  136. IDispatch *pDisp = NULL;
  137. __try
  138. {
  139. if(FAILED(hr = GetSiteServices(pUnk, &pServProv)))
  140. __leave;
  141. if(FAILED(hr = pServProv->QueryService(SID_SContainerDispatch, IID_IDispatch, (void**)&pDisp)))
  142. __leave;
  143. hr = pDisp->QueryInterface(IID_IHTMLDocument2, (void**)ppDoc);
  144. }
  145. __finally
  146. {
  147. if(pServProv)
  148. pServProv->Release();
  149. if(pDisp)
  150. pDisp->Release();
  151. }
  152. return hr;
  153. }
  154. // This function will Release() the current document and return a pointer to
  155. // the parent document. If no parent document is available, this function
  156. // will return NULL (but will still release the current document)
  157. IHTMLDocument2 *GetParentDocument(IHTMLDocument2 *pDoc)
  158. {
  159. BSTR bstrURL = NULL;
  160. BSTR bstrURLParent = NULL;
  161. IHTMLWindow2 *pWndParent = NULL;
  162. IHTMLWindow2 *pWndParentParent = NULL;
  163. IHTMLDocument2 *pDocParent = NULL;
  164. __try
  165. {
  166. if(FAILED(pDoc->get_URL(&bstrURL)))
  167. __leave;
  168. if(FAILED(pDoc->get_parentWindow(&pWndParent)))
  169. __leave;
  170. if(FAILED(pWndParent->get_parent(&pWndParentParent)))
  171. __leave;
  172. if(FAILED(pWndParentParent->get_document(&pDocParent)))
  173. __leave;
  174. if(FAILED(pDocParent->get_URL(&bstrURLParent)))
  175. __leave;
  176. // TODO: Make this more robust
  177. if(0 == lstrcmpW(bstrURL, bstrURLParent))
  178. {
  179. // We are at the top document. Release the new document pointer we
  180. // just received.
  181. pDocParent->Release();
  182. pDocParent = NULL;
  183. }
  184. }
  185. __finally
  186. {
  187. if(bstrURL)
  188. SysFreeString(bstrURL);
  189. if(bstrURLParent)
  190. SysFreeString(bstrURLParent);
  191. if(pWndParent)
  192. pWndParent->Release();
  193. if(pWndParentParent)
  194. pWndParentParent->Release();
  195. if(pDoc)
  196. pDoc->Release();
  197. }
  198. return pDocParent;
  199. }
  200. // Try to append bstr2 to pbstr1. If this function fails, pbstr1 will still
  201. // point to the original valid allocated bstr.
  202. HRESULT AppendBSTR(BSTR *pbstr1, BSTR bstr2)
  203. {
  204. HRESULT hr = S_OK;
  205. CComBSTR bstr;
  206. if(FAILED(bstr.AppendBSTR(*pbstr1)))
  207. hr = E_FAIL;
  208. if(FAILED(bstr.AppendBSTR(bstr2)))
  209. hr = E_FAIL;
  210. if(SUCCEEDED(hr))
  211. {
  212. SysFreeString(*pbstr1);
  213. *pbstr1 = bstr.Detach();
  214. }
  215. return hr;
  216. }
  217. BSTR AllocBSTR(LPCTSTR lpsz)
  218. {
  219. CComBSTR bstr(lpsz);
  220. return bstr.Detach();
  221. }
  222. BOOL IsURLLocal(LPWSTR szURL)
  223. {
  224. CComBSTR bstrURL(szURL);
  225. if ( !bstrURL )
  226. return FALSE;
  227. if(FAILED(bstrURL.ToLower()))
  228. return FALSE;
  229. // Make sure the URL starts with 'file://'
  230. // NOTE: Calling code may rely on the fact that this method verifies that
  231. // the URL starts with file://. If you change this function to work
  232. // differently, you must examine the places that call this method so that
  233. // they don't rely on this assumption.
  234. if(0 != wcsncmp(bstrURL, L"file://", 7))
  235. return FALSE;
  236. // Make sure the next part is a drive letter, such as 'C:\'
  237. if(0 != wcsncmp(&(bstrURL[8]), L":\\", 2))
  238. return FALSE;
  239. WCHAR drive = bstrURL[7];
  240. // Make sure the URL points to drive 'a' to 'z'
  241. if(drive < 'a' || drive > 'z')
  242. return FALSE;
  243. TCHAR szDrive[4];
  244. StringCchCopy(szDrive,sizeof(szDrive),TEXT("c:\\")); // 4505 in WMI
  245. szDrive[0] = (TCHAR)drive;
  246. UINT uDriveType = GetDriveType(szDrive);
  247. return (DRIVE_FIXED == uDriveType);
  248. }
  249. // Try to convert the BSTR to lower case. If this function fails, pbstr will
  250. // still point to the original valid allocated bstr.
  251. HRESULT ToLowerBSTR(BSTR *pbstr)
  252. {
  253. CComBSTR bstr;
  254. if(FAILED(bstr.AppendBSTR(*pbstr)))
  255. return E_FAIL;
  256. if(FAILED(bstr.ToLower()))
  257. return E_FAIL;
  258. SysFreeString(*pbstr);
  259. *pbstr = bstr.Detach();
  260. return S_OK;
  261. }
  262. // For a given instance of an ActiveX control (represented by pUnk), and a
  263. // specified strProgId, this function creates a 'full path' that can be checked
  264. // in the registry to see if object creation should be allowed. The full
  265. // location is created from the following information
  266. // 1) The name of the current EXE
  267. // 2) The ProgId requested
  268. // 3) The HREF of the current document
  269. // 4) The HREF of every parent document up the available hierarchy
  270. // All of the documents in the hierarchy must be on a local hard drive or the
  271. // function will fail. In addition, if any piece of informaiton along the way
  272. // is not available, the function will fail. This increases the security of
  273. // our process.
  274. // This function will also create a BSTR in *pbstrHash that contains the
  275. // cumulative MD5 hash of the document and its parents. This BSTR will be
  276. // allocated by the function and should be freed by the caller. If the
  277. // function returns NULL for the full location, it will also return NULL for
  278. // *pbstrHash
  279. BSTR GetFullLocation(IUnknown *pUnk, BSTR strProgId, BSTR *pbstrHash)
  280. {
  281. HRESULT hr = E_FAIL;
  282. IHTMLDocument2 *pDoc = NULL;
  283. BSTR bstrURL = NULL;
  284. BSTR bstrFullLocation = NULL;
  285. *pbstrHash = NULL;
  286. BYTE *pbData = NULL;
  287. BSTR bstrHash = NULL;
  288. __try
  289. {
  290. if(FAILED(GetDocument(pUnk, &pDoc)))
  291. __leave;
  292. TCHAR szFilename[_MAX_PATH];
  293. TCHAR szFilenameLong[_MAX_PATH];
  294. GetModuleFileName(NULL, szFilenameLong, _MAX_PATH);
  295. GetShortPathName(szFilenameLong, szFilename, _MAX_PATH);
  296. if(NULL == (bstrFullLocation = AllocBSTR(szFilename)))
  297. __leave;
  298. if(FAILED(AppendBSTR(&bstrFullLocation, strProgId)))
  299. __leave;
  300. if(NULL == (*pbstrHash = AllocBSTR(_T(""))))
  301. __leave;
  302. int nDepth = 0;
  303. do
  304. {
  305. // Make sure we don't get stuck in some infinite loop of parent
  306. // documents. If we do get more than 100 levels of parent
  307. // documents, we assume failure
  308. if(++nDepth >= 100)
  309. __leave;
  310. if(FAILED(pDoc->get_URL(&bstrURL)))
  311. __leave;
  312. DWORD dwDataSize = 0;
  313. if(FAILED(GetSourceFromDoc(pDoc, &pbData, &dwDataSize)))
  314. __leave;
  315. MD5Hash hash;
  316. if(FAILED(hash.HashData(pbData, dwDataSize)))
  317. __leave;
  318. if(NULL == (bstrHash = hash.GetHashBSTR()))
  319. __leave;
  320. if(FAILED(AppendBSTR(pbstrHash, bstrHash)))
  321. __leave;
  322. SysFreeString(bstrHash);
  323. bstrHash = NULL;
  324. delete [] pbData;
  325. pbData = NULL;
  326. // Make sure every document is on the local hard drive
  327. if(!IsURLLocal(bstrURL))
  328. __leave;
  329. if(FAILED(AppendBSTR(&bstrFullLocation, bstrURL)))
  330. __leave;
  331. SysFreeString(bstrURL);
  332. bstrURL = NULL;
  333. } while (NULL != (pDoc = GetParentDocument(pDoc)));
  334. // Make sure we do not have any embeded NULLs. If we do, we just
  335. // FAIL the call
  336. if(SysStringLen(bstrFullLocation) != wcslen(bstrFullLocation))
  337. __leave;
  338. // Make the location lower case
  339. if(FAILED(ToLowerBSTR(&bstrFullLocation)))
  340. __leave;
  341. // We've now created the normalized full location
  342. hr = S_OK;
  343. }
  344. __finally
  345. {
  346. // pDoc should be NULL if we got to the top of the hierarchy. If not,
  347. // we should release it
  348. if(pDoc)
  349. pDoc->Release();
  350. // pbData should be NULL unless there was an error calculating the hash
  351. if(pbData)
  352. delete [] pbData;
  353. // bstrHash should be NULL unless there was a problem
  354. if(bstrHash)
  355. SysFreeString(bstrHash);
  356. // bstrURL should be NULL unless there was a problem
  357. if(bstrURL)
  358. SysFreeString(bstrURL);
  359. // If we didn't make it all the way to the end, we free the full location
  360. if(FAILED(hr) && bstrFullLocation)
  361. {
  362. SysFreeString(bstrFullLocation);
  363. bstrFullLocation = NULL;
  364. }
  365. // If we didn't make it all the way to the end, we free the checksum
  366. if(FAILED(hr) && *pbstrHash)
  367. {
  368. SysFreeString(*pbstrHash);
  369. *pbstrHash = NULL;
  370. }
  371. }
  372. return bstrFullLocation;
  373. }
  374. // This version of the control is hard coded to only allow ProgIds to be
  375. // registered under restricted conditions. In this version, this means
  376. // that the process registering a ProgID must be DevEnv.exe, as specified
  377. // by the value in:
  378. // HKLM\Software\Microsoft\VisualStudio\7.0\Setup\VS\VS7EnvironmentLocation
  379. // Also, only wbemscripting.swbemlocator and wbemscripting.swbemsink can
  380. // be registered
  381. HRESULT AreCrippledCriteriaMet(BSTR strProgId)
  382. {
  383. BSTR bstrProgIdLowerCase = NULL;
  384. BSTR bstrModuleName = NULL;
  385. BSTR bstrDevEnvPath = NULL;
  386. HKEY hKeyVSPaths = NULL;
  387. HRESULT hr = E_FAIL;
  388. __try
  389. {
  390. ////////////////////////////////////////////////////////////////////////////////
  391. // Make sure the ProgId is wbemscripting.swbemsink or wbemscripting.swbemlocator
  392. // Copy strProgId to tempory BSTR
  393. if(NULL == (bstrProgIdLowerCase = SysAllocString(strProgId)))
  394. __leave;
  395. // Change it to lower case
  396. if(FAILED(ToLowerBSTR(&bstrProgIdLowerCase)))
  397. __leave;
  398. // See if the prog id is for the sink or locator. If not, leave
  399. if(0 != wcscmp(bstrProgIdLowerCase, L"wbemscripting.swbemsink") && 0 != wcscmp(bstrProgIdLowerCase, L"wbemscripting.swbemlocator"))
  400. __leave;
  401. ////////////////////////////////////////////////////////////////////////////////
  402. // Make sure we are running from devenv.exe
  403. TCHAR szFilename[_MAX_PATH];
  404. TCHAR szFilenameLong[_MAX_PATH];
  405. TCHAR szDevEnvLong[_MAX_PATH];
  406. TCHAR szDevEnv[_MAX_PATH];
  407. GetModuleFileName(NULL, szFilenameLong, _MAX_PATH);
  408. GetShortPathName(szFilenameLong, szFilename, _MAX_PATH);
  409. // Make into BSTR
  410. if(NULL == (bstrModuleName = AllocBSTR(szFilename)))
  411. __leave;
  412. // Make lower case
  413. if(FAILED(ToLowerBSTR(&bstrModuleName)))
  414. __leave;
  415. // Open the registry key to get the path to DevEnv.exe
  416. if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,strVSPathKey,0,KEY_QUERY_VALUE,&hKeyVSPaths))
  417. __leave;
  418. DWORD cbValue = _MAX_PATH * sizeof(TCHAR);
  419. DWORD dwType = 0;
  420. if(ERROR_SUCCESS != RegQueryValueEx(hKeyVSPaths, DEVENV_VALUE, NULL, &dwType, (LPBYTE)szDevEnvLong, &cbValue))
  421. __leave;
  422. if(dwType != REG_SZ)
  423. __leave;
  424. GetShortPathName(szDevEnvLong, szDevEnv, _MAX_PATH);
  425. // make BSTR for devenv.exe path
  426. if(NULL == (bstrDevEnvPath = AllocBSTR(szDevEnv)))
  427. __leave;
  428. // Make lower case
  429. if(FAILED(ToLowerBSTR(&bstrDevEnvPath)))
  430. __leave;
  431. // If current process is not the registered DevEnv.exe, we will 'fail'
  432. if(0 != wcscmp(bstrModuleName, bstrDevEnvPath))
  433. __leave;
  434. hr = S_OK;
  435. }
  436. __finally
  437. {
  438. if(bstrProgIdLowerCase)
  439. SysFreeString(bstrProgIdLowerCase);
  440. if(bstrModuleName)
  441. SysFreeString(bstrModuleName);
  442. if(bstrDevEnvPath)
  443. SysFreeString(bstrDevEnvPath);
  444. if(hKeyVSPaths)
  445. RegCloseKey(hKeyVSPaths);
  446. }
  447. return hr;
  448. }
  449. // Makes sure the string starts with the specified string
  450. // On success, it updates the passed in pointer to point to the next character
  451. HRESULT StartsWith(LPCWSTR *ppsz, LPCWSTR pszTest)
  452. {
  453. int len = wcslen(pszTest);
  454. if(0 != wcsncmp(*ppsz, pszTest, len))
  455. return E_FAIL;
  456. *ppsz += len;
  457. return S_OK;
  458. }
  459. // Makes sure the next character is 0 through 9, and updates the input pointer
  460. // by one character
  461. HRESULT NextCharacterIsDigit(LPCWSTR *ppsz)
  462. {
  463. WCHAR c = **ppsz;
  464. if(c < L'0' || c > L'9')
  465. return E_FAIL;
  466. (*ppsz)++;
  467. return S_OK;
  468. }
  469. // For a special case, where the crippled criteria are met and we are dealking
  470. // with a well known document, we will hard code acceptance of control creation
  471. // This method tests if the crippled critera are met, and if this is a well
  472. // known document
  473. HRESULT IsWellKnownHostDocument(IUnknown *pUnk, BSTR strProgId)
  474. {
  475. HRESULT hr = E_FAIL;
  476. IHTMLDocument2 *pDoc = NULL;
  477. IHTMLDocument2 *pParentDoc = NULL;
  478. BSTR bstrURL = NULL;
  479. BSTR bstrDocumentFile = NULL;
  480. BSTR bstrVCPath = NULL;
  481. HKEY hKey = NULL;
  482. __try
  483. {
  484. // Make sure the crippled criteria are met. In other words, we are
  485. // running in a known instance of devenv.exe, and we are requesting a
  486. // known ProgId
  487. if(FAILED(AreCrippledCriteriaMet(strProgId)))
  488. __leave;
  489. // Get the HTML Document
  490. if(FAILED(GetDocument(pUnk, &pDoc)))
  491. __leave;
  492. // If there is a parent document, this is not a well know document
  493. if(NULL != (pParentDoc = GetParentDocument(pDoc)))
  494. __leave;
  495. // Get the URL of the document
  496. if(FAILED(pDoc->get_URL(&bstrURL)))
  497. __leave;
  498. // Make sure the well known document canidate is on the local hard drive
  499. if(!IsURLLocal(bstrURL))
  500. __leave;
  501. // Open the registry key to get the VC path
  502. if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,strVCPathKey,0,KEY_QUERY_VALUE,&hKey))
  503. __leave;
  504. TCHAR szVCPath[_MAX_PATH];
  505. TCHAR szVCPathURL[_MAX_PATH*2];
  506. DWORD cbValue = _MAX_PATH * sizeof(TCHAR);
  507. DWORD dwType = 0;
  508. if(ERROR_SUCCESS != RegQueryValueEx(hKey, VC_PRODUCTDIR_VALUE, NULL, &dwType, (LPBYTE)szVCPath, &cbValue))
  509. __leave;
  510. if(dwType != REG_SZ)
  511. __leave;
  512. // Canonicalize the VC path
  513. cbValue = _MAX_PATH*2; // Length in TCHARs of szVCPathURL
  514. if(!InternetCanonicalizeUrl(szVCPath, szVCPathURL, &cbValue, 0))
  515. __leave;
  516. // make BSTR for devenv.exe path
  517. if(NULL == (bstrVCPath = AllocBSTR(szVCPathURL)))
  518. __leave;
  519. // Make lower case
  520. if(FAILED(ToLowerBSTR(&bstrVCPath)))
  521. __leave;
  522. // Make document path lower case
  523. if(FAILED(ToLowerBSTR(&bstrURL)))
  524. __leave;
  525. LPCWSTR szStartDoc = bstrURL;
  526. // Make sure we start with the correct VC directory
  527. if(FAILED(StartsWith(&szStartDoc, bstrVCPath)))
  528. __leave;
  529. // Make sure we next have "VCWizards\ClassWiz\ATL\"
  530. if(FAILED(StartsWith(&szStartDoc, L"vcwizards\\classwiz\\atl\\")))
  531. __leave;
  532. // Make sure we next have 'event\' or 'instance\'
  533. if(FAILED(StartsWith(&szStartDoc, L"event\\")) && FAILED(StartsWith(&szStartDoc, L"instance\\")))
  534. __leave;
  535. // Make sure we next have "html\"
  536. if(FAILED(StartsWith(&szStartDoc, L"html\\")))
  537. __leave;
  538. // Make sure the next four characters are numbers
  539. if(FAILED(NextCharacterIsDigit(&szStartDoc)))
  540. __leave;
  541. if(FAILED(NextCharacterIsDigit(&szStartDoc)))
  542. __leave;
  543. if(FAILED(NextCharacterIsDigit(&szStartDoc)))
  544. __leave;
  545. if(FAILED(NextCharacterIsDigit(&szStartDoc)))
  546. __leave;
  547. // Make sure what's left is '\wmiclass.htm'
  548. if(0 != wcscmp(szStartDoc, L"\\wmiclass.htm"))
  549. __leave;
  550. hr = S_OK;
  551. }
  552. __finally
  553. {
  554. if(pDoc)
  555. pDoc->Release();
  556. if(pParentDoc)
  557. pParentDoc->Release();
  558. if(bstrURL)
  559. SysFreeString(bstrURL);
  560. if(bstrDocumentFile)
  561. SysFreeString(bstrDocumentFile);
  562. if(bstrVCPath)
  563. SysFreeString(bstrVCPath);
  564. if(hKey)
  565. RegCloseKey(hKey);
  566. }
  567. return hr;
  568. }
  569. // For a given instance of an ActiveXControl (specified by pUnk), see if it is
  570. // permitted to create the object specified by bstrProgId. This is done by
  571. // verifying that the control was created in an allowed HTML document.
  572. HRESULT IsCreateObjectAllowed(IUnknown *pUnk, BSTR strProgId, BSTR *pstrValueName)
  573. {
  574. BSTR bstrFullLocation = NULL;
  575. HRESULT hr = E_FAIL;
  576. HKEY hKey = NULL;
  577. LPTSTR pszValueName = NULL;
  578. LPTSTR pszValue = NULL;
  579. __try
  580. {
  581. BSTR bstrHash = NULL;
  582. // Make sure the crippled criteria are met
  583. if(FAILED(AreCrippledCriteriaMet(strProgId)))
  584. __leave;
  585. // We are going to hard code a specific set of conditions that are
  586. // allowed. We will only do this if pstrValueName is NULL (which
  587. // happens during CreateObject and CanCreateObject).
  588. // NOTE: this performs a redundant check to make sure the crippled
  589. // criteria are met
  590. if(FAILED(IsWellKnownHostDocument(pUnk, strProgId)))
  591. {
  592. __leave;
  593. }
  594. // Get the full location
  595. if(NULL == (bstrFullLocation = GetFullLocation(pUnk, strProgId, &bstrHash)))
  596. __leave;
  597. SysFreeString(bstrHash);
  598. // Make sure we don't have a zero length string
  599. if(0 == SysStringLen(bstrFullLocation))
  600. __leave;
  601. // Open the registry key to see if this full location is registered
  602. if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,SAFE_LOCAL_SCRIPTS_KEY,0,KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE ,&hKey))
  603. __leave;
  604. // Get info on the max lenghts of values in this key
  605. DWORD cValues, cMaxValueNameLen, cMaxValueLen;
  606. if(ERROR_SUCCESS != RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &cValues, &cMaxValueNameLen, &cMaxValueLen, NULL, NULL))
  607. __leave;
  608. // Allocate space for the value name
  609. if(NULL == (pszValueName = new TCHAR[cMaxValueNameLen + 1]))
  610. __leave;
  611. // Allocate space for the value (this may be twice as big as necessary in UNICODE)
  612. if(NULL == (pszValue = new TCHAR[cMaxValueLen + 1]))
  613. __leave;
  614. for(DWORD dw = 0;dw<cValues;dw++)
  615. {
  616. DWORD cValueNameLen = cMaxValueNameLen+1;
  617. DWORD cbData = (cMaxValueLen+1)*sizeof(TCHAR);
  618. DWORD dwType;
  619. if(ERROR_SUCCESS != RegEnumValue(hKey, dw, pszValueName, &cValueNameLen, NULL, &dwType, (LPBYTE)pszValue, &cbData))
  620. continue;
  621. if(dwType != REG_SZ)
  622. continue;
  623. BSTR bstrValue = AllocBSTR(pszValue);
  624. if(!bstrValue)
  625. continue;
  626. // SEE IF WE HAVE A MATCH
  627. if(0 == wcscmp(bstrFullLocation, bstrValue))
  628. {
  629. // Return the ValueName if requested
  630. if(pstrValueName)
  631. {
  632. *pstrValueName = AllocBSTR(pszValueName);
  633. }
  634. hr = S_OK;
  635. }
  636. SysFreeString(bstrValue);
  637. if(SUCCEEDED(hr))
  638. __leave; // WE FOUND A MATCH
  639. }
  640. }
  641. __finally
  642. {
  643. if(bstrFullLocation)
  644. SysFreeString(bstrFullLocation);
  645. if(hKey)
  646. RegCloseKey(hKey);
  647. if(pszValueName)
  648. delete [] pszValueName;
  649. if(pszValue)
  650. delete [] pszValue;
  651. }
  652. return hr;
  653. }
  654. // This function will register the location of the current ActiveX control
  655. // (specified by pUnk) to be allowed to create objects of type strProgId
  656. HRESULT RegisterCurrentDoc(IUnknown *pUnk, BSTR strProgId)
  657. {
  658. USES_CONVERSION;
  659. HRESULT hr = E_FAIL;
  660. BSTR bstrFullLocation = NULL;
  661. LPTSTR pszFullLocation = NULL;
  662. HKEY hKey = NULL;
  663. __try
  664. {
  665. // Make sure the crippled criteria are met
  666. if(FAILED(AreCrippledCriteriaMet(strProgId)))
  667. __leave;
  668. // See if we are already registered
  669. if(SUCCEEDED(IsCreateObjectAllowed(pUnk, strProgId, NULL)))
  670. {
  671. hr = S_OK;
  672. __leave;
  673. }
  674. // TODO: Maybe reuse some of the code from IsCreateObjectAllowed
  675. BSTR bstrHash = NULL;
  676. // Get the full location
  677. if(NULL == (bstrFullLocation = GetFullLocation(pUnk, strProgId, &bstrHash)))
  678. __leave;
  679. SysFreeString(bstrHash);
  680. // Make sure we don't have a zero length string
  681. if(0 == SysStringLen(bstrFullLocation))
  682. __leave;
  683. if(bstrFullLocation != NULL)
  684. {
  685. #ifdef _UNICODE
  686. pszFullLocation = bstrFullLocation;
  687. #else
  688. pszFullLocation = new TCHAR[SysStringLen(bstrFullLocation) + 1];
  689. if(pszFullLocation == NULL)
  690. __leave;
  691. if(0 == WideCharToMultiByte(CP_ACP, 0, bstrFullLocation, -1, pszFullLocation, (SysStringLen(bstrFullLocation) + 1) * sizeof(TCHAR), NULL, NULL))
  692. __leave;
  693. #endif
  694. }
  695. if(NULL == pszFullLocation)
  696. __leave;
  697. // Create or open the registry key to store the registration
  698. if(ERROR_SUCCESS != RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  699. SAFE_LOCAL_SCRIPTS_KEY,
  700. 0,
  701. TEXT(""),
  702. REG_OPTION_NON_VOLATILE,
  703. KEY_SET_VALUE | KEY_QUERY_VALUE,
  704. NULL,
  705. &hKey,
  706. NULL))
  707. __leave;
  708. // Find an empty slot (no more than 1000 registrations
  709. TCHAR sz[10];
  710. for(int i=1;i<1000;i++)
  711. {
  712. StringCchPrintf(sz,sizeof(sz),TEXT("%i"),i);
  713. DWORD cbValue;
  714. if(ERROR_SUCCESS != RegQueryValueEx(hKey, sz, NULL, NULL, NULL, &cbValue))
  715. break; // There is nothing in this slot
  716. }
  717. // See if we found a slot
  718. if(i>=1000)
  719. __leave;
  720. // Register the location
  721. if(ERROR_SUCCESS != RegSetValueEx(hKey, sz, 0, REG_SZ, (CONST BYTE *)pszFullLocation, (lstrlen(pszFullLocation) + 1) *sizeof(TCHAR)))
  722. __leave;
  723. // Registered!
  724. hr = S_OK;
  725. }
  726. __finally
  727. {
  728. if(bstrFullLocation)
  729. SysFreeString(bstrFullLocation);
  730. #ifndef _UNICODE
  731. if( pszFullLocation)
  732. delete []pszFullLocation;
  733. #endif
  734. if(hKey)
  735. RegCloseKey(hKey);
  736. }
  737. return hr;
  738. }
  739. // This function will remove any registration for the current document and
  740. // strProgId
  741. HRESULT UnRegisterCurrentDoc(IUnknown *pUnk, BSTR strProgId)
  742. {
  743. USES_CONVERSION;
  744. BSTR bstrValueName = NULL;
  745. // Make sure the crippled criteria are met
  746. if(FAILED(AreCrippledCriteriaMet(strProgId)))
  747. return E_FAIL;
  748. HKEY hKey = NULL;
  749. if(ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE, SAFE_LOCAL_SCRIPTS_KEY, &hKey))
  750. return E_FAIL;
  751. // Make sure to remove ALL instances of this doc/strProgId in the registry
  752. // NOTE: Each iteration of this loop allocates some space off of the stack
  753. // for the conversion to ANSI (if not UNICODE build). This should not be a
  754. // problem since there should not be too many keys ever registered with the
  755. // same location.
  756. while(SUCCEEDED(IsCreateObjectAllowed(pUnk, strProgId, &bstrValueName)) && bstrValueName)
  757. {
  758. LPTSTR szValueName = NULL;
  759. if(FAILED(ConvertToTString(bstrValueName,&szValueName)))
  760. {
  761. SysFreeString(bstrValueName);
  762. return E_FAIL;
  763. }
  764. SysFreeString(bstrValueName);
  765. bstrValueName = NULL;
  766. RegDeleteValue(hKey, szValueName);
  767. delete [] szValueName;
  768. }
  769. RegCloseKey(hKey);
  770. return S_OK;
  771. }
  772. ///////////////////////////////////////////////////////////////////////////////
  773. // VC 6.0 did not ship with header files that included the CONFIRMSAFETY
  774. // definition.
  775. #ifndef CONFIRMSAFETYACTION_LOADOBJECT
  776. EXTERN_C const GUID GUID_CUSTOM_CONFIRMOBJECTSAFETY;
  777. #define CONFIRMSAFETYACTION_LOADOBJECT 0x00000001
  778. struct CONFIRMSAFETY
  779. {
  780. CLSID clsid;
  781. IUnknown * pUnk;
  782. DWORD dwFlags;
  783. };
  784. #endif
  785. const GUID GUID_CUSTOM_CONFIRMOBJECTSAFETY =
  786. { 0x10200490, 0xfa38, 0x11d0, { 0xac, 0xe, 0x0, 0xa0, 0xc9, 0xf, 0xff, 0xc0 }};
  787. ///////////////////////////////////////////////////////////////////////////////
  788. HRESULT SafeCreateObject(IUnknown *pUnkControl, BOOL fSafetyEnabled, CLSID clsid, IUnknown **ppUnk)
  789. {
  790. HRESULT hr = E_FAIL;
  791. IInternetHostSecurityManager *pSecMan = NULL;
  792. IServiceProvider *pServProv = NULL;
  793. __try
  794. {
  795. if (fSafetyEnabled)
  796. {
  797. if(FAILED(hr = GetSiteServices(pUnkControl, &pServProv)))
  798. __leave;
  799. if(FAILED(hr = pServProv->QueryService(SID_SInternetHostSecurityManager, IID_IInternetHostSecurityManager, (void**)&pSecMan)))
  800. __leave;
  801. // Ask security manager if we can create objects.
  802. DWORD dwPolicy = 0x12345678;
  803. if(FAILED(hr = pSecMan->ProcessUrlAction(URLACTION_ACTIVEX_RUN, (BYTE *)&dwPolicy, sizeof(dwPolicy), (BYTE *)&clsid, sizeof(clsid), 0, 0)))
  804. __leave;
  805. // TODO: BUG: If we are loaded in an HTA, hr returns S_OK, but
  806. // dwPolicy only has the first byte set to zero. See documentation
  807. // for ProcessUrlAction.
  808. // NOTE: This bug is caused by CClient::ProcessUrlAction in
  809. // nt\private\inet\mshtml\src\other\htmlapp\site.cxx. This line
  810. // uses *pPolicy = dwPolicy, but pPolicy is a BYTE * so only the
  811. // first byte of the policy is copied to the output parameter.
  812. // To fix this, we check for hr==S_OK (as opposed to S_FALSE), and
  813. // see if dwPolicy is 0x12345600 (in other words, only the lower
  814. // byte of dwPolicy was changed). As per the documentation, S_OK
  815. // alone should be enough to assume the dwPolicy was
  816. // URL_POLICY_ALLOW
  817. if(S_OK == hr && 0x12345600 == dwPolicy)
  818. dwPolicy = URLPOLICY_ALLOW;
  819. if(URLPOLICY_ALLOW != dwPolicy)
  820. {
  821. hr = E_FAIL;
  822. __leave;;
  823. }
  824. }
  825. // Create the requested object
  826. if (FAILED(hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)ppUnk)))
  827. __leave;
  828. if (fSafetyEnabled)
  829. {
  830. // Query the security manager to see if this object is safe to use.
  831. DWORD dwPolicy, *pdwPolicy;
  832. DWORD cbPolicy;
  833. CONFIRMSAFETY csafe;
  834. csafe.pUnk = *ppUnk;
  835. csafe.clsid = clsid;
  836. csafe.dwFlags = 0;
  837. // csafe.dwFlags = (fWillLoad ? CONFIRMSAFETYACTION_LOADOBJECT : 0);
  838. if(FAILED(hr = pSecMan->QueryCustomPolicy(GUID_CUSTOM_CONFIRMOBJECTSAFETY, (BYTE **)&pdwPolicy, &cbPolicy, (BYTE *)&csafe, sizeof(csafe), 0)))
  839. __leave;
  840. dwPolicy = URLPOLICY_DISALLOW;
  841. if (NULL != pdwPolicy)
  842. {
  843. if (sizeof(DWORD) <= cbPolicy)
  844. dwPolicy = *pdwPolicy;
  845. CoTaskMemFree(pdwPolicy);
  846. }
  847. if(URLPOLICY_ALLOW != dwPolicy)
  848. {
  849. hr = E_FAIL;
  850. __leave;
  851. }
  852. }
  853. hr = S_OK;
  854. }
  855. __finally
  856. {
  857. // If we did not succeeded, we need to release the object we created (if any)
  858. if(FAILED(hr) && (*ppUnk))
  859. {
  860. (*ppUnk)->Release();
  861. *ppUnk = NULL;
  862. }
  863. if(pServProv)
  864. pServProv->Release();
  865. if(pSecMan)
  866. pSecMan->Release();
  867. }
  868. return hr;
  869. }
  870. BOOL IsInternetHostSecurityManagerAvailable(IUnknown *pUnkControl)
  871. {
  872. HRESULT hr = E_FAIL;
  873. IInternetHostSecurityManager *pSecMan = NULL;
  874. IServiceProvider *pServProv = NULL;
  875. __try
  876. {
  877. if(FAILED(hr = GetSiteServices(pUnkControl, &pServProv)))
  878. __leave;
  879. if(FAILED(hr = pServProv->QueryService(SID_SInternetHostSecurityManager, IID_IInternetHostSecurityManager, (void**)&pSecMan)))
  880. __leave;
  881. }
  882. __finally
  883. {
  884. if(pServProv)
  885. pServProv->Release();
  886. if(pSecMan)
  887. pSecMan->Release();
  888. }
  889. return SUCCEEDED(hr);
  890. }
  891. HRESULT SetVSInstallDirectory(IDispatch * pEnv)
  892. {
  893. HRESULT hr = E_FAIL;
  894. DISPID dispid;
  895. LPOLESTR szMember = OLESTR("RegistryRoot");;
  896. VARIANT varResult;
  897. VariantInit(&varResult);
  898. TCHAR *pTemp = NULL;
  899. DISPPARAMS dispParams;
  900. dispParams.cArgs = 0;
  901. dispParams.cNamedArgs = 0;
  902. dispParams.rgvarg = NULL;
  903. dispParams.rgdispidNamedArgs = NULL;
  904. if(pEnv)
  905. {
  906. hr = pEnv->GetIDsOfNames(IID_NULL ,&szMember,1, LOCALE_SYSTEM_DEFAULT,&dispid);
  907. if(SUCCEEDED(hr))
  908. {
  909. hr = pEnv->Invoke(dispid,IID_NULL,GetThreadLocale(),DISPATCH_PROPERTYGET,&dispParams,&varResult,NULL,NULL);
  910. if(SUCCEEDED(hr))
  911. {
  912. hr = ConvertToTString(varResult.bstrVal,&pTemp);
  913. if(SUCCEEDED(hr))
  914. {
  915. // Check if this is the standard VS Location in Registry
  916. if(_tcsncmp(pTemp,VS_VER_INDEPENDANT_PATH_KEY,_tcslen(VS_VER_INDEPENDANT_PATH_KEY)) == 0)
  917. {
  918. StringCchCopy(strVSPathKey,MAX_PATH * 2,pTemp);
  919. StringCchCopy(strVCPathKey,MAX_PATH * 2,pTemp);
  920. StringCchCat(strVSPathKey,MAX_PATH * 2,TEXT("\\Setup\\VS"));
  921. StringCchCat(strVCPathKey,MAX_PATH * 2,TEXT("\\Setup\\VC"));
  922. }
  923. else
  924. {
  925. hr = E_FAIL;
  926. }
  927. delete [] pTemp;
  928. }
  929. VariantClear(&varResult);
  930. }
  931. }
  932. }
  933. return hr;
  934. }
  935. HRESULT ConvertToTString(BSTR strPath,TCHAR **ppStr)
  936. {
  937. HRESULT hr = E_OUTOFMEMORY;
  938. #ifdef _UNICODE
  939. *ppStr = new TCHAR[SysStringLength(strPath) + 1];
  940. if(*ppStr)
  941. {
  942. StringCchCopy(*ppStr,sizeof(*ppStr),strPath);
  943. hr = S_OK;
  944. }
  945. #else
  946. *ppStr = new TCHAR[SysStringLen(strPath) + 1];
  947. if(WideCharToMultiByte(CP_ACP, 0, strPath, -1, *ppStr, (SysStringLen(strPath) + 1) * sizeof(TCHAR), NULL, NULL))
  948. {
  949. hr = S_OK;
  950. }
  951. else
  952. delete [] *ppStr;
  953. #endif
  954. return hr;
  955. }