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.

1091 lines
30 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-2001 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: RedirectUtil.cpp
  6. // Author: Charles Ma, 9/19/2001
  7. //
  8. // Revision History:
  9. //
  10. //
  11. //
  12. // Description:
  13. //
  14. // Helper function(s) for handling server redirect
  15. // Can be shared by IU control and other Windows Update components
  16. //
  17. //=======================================================================
  18. #include <iucommon.h>
  19. #include <logging.h>
  20. #include <stringutil.h>
  21. #include <fileutil.h> // for using function GetIndustryUpdateDirectory()
  22. #include <download.h>
  23. #include <trust.h>
  24. #include <memutil.h>
  25. #include <wininet.h> // for define of INTERNET_MAX_URL_LENGTH
  26. #include <RedirectUtil.h>
  27. #include <MISTSAFE.h>
  28. #include <wusafefn.h>
  29. const TCHAR IDENTNEWCABDIR[] = _T("temp"); // temp name for newly downloaded cab
  30. // we need to validate time before we take it as a good iuident.cab
  31. const TCHAR IDENTCAB[] = _T("iuident.cab");
  32. const TCHAR REDIRECT_SECTION[] = _T("redirect");
  33. //
  34. // private structure, which defines data used to
  35. // determine server redirect key
  36. //
  37. typedef struct OS_VER_FOR_REDIRECT
  38. {
  39. DWORD dwMajor;
  40. DWORD dwMinor;
  41. DWORD dwBuildNumber;
  42. DWORD dwSPMajor;
  43. DWORD dwSPMinor;
  44. } OSVerForRedirect, *pOSVerForRedirect;
  45. const OSVerForRedirect MAX_VERSION = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
  46. //-----------------------------------------------------------------------
  47. //
  48. // private helper function:
  49. // read data in string, convert it to structure
  50. // string ends with \0 or "-"
  51. //
  52. //-----------------------------------------------------------------------
  53. HRESULT ConvertStrToOSVer(LPCTSTR pszVer, pOSVerForRedirect pOSVer)
  54. {
  55. int Numbers[5] = {0, 0, 0, 0, 0}; // default version component val is 0
  56. int n = 0;
  57. if (NULL == pOSVer || NULL == pszVer)
  58. {
  59. return E_INVALIDARG;
  60. }
  61. //
  62. // recognizing numbers from string can be done in two ways:
  63. // 1. more acceptive: stop if known ending char, otherwise continue
  64. // 2. more rejective: stop if anything not known.
  65. // we use the first way
  66. //
  67. while ('\0' != *pszVer &&
  68. _T('-') != *pszVer &&
  69. _T('=') != *pszVer &&
  70. n < sizeof(Numbers)/sizeof(int))
  71. {
  72. if (_T('.') == *pszVer)
  73. {
  74. n++;
  75. }
  76. else if (_T('0') <= *pszVer && *pszVer <= _T('9'))
  77. {
  78. //
  79. // if this is a digit, add to the current ver component
  80. //
  81. Numbers[n] = Numbers[n]*10 + (*pszVer - _T('0'));
  82. }
  83. //
  84. // else - for any other chars, skip it and continue,
  85. // therefore we are using a very acceptive algorithm
  86. //
  87. pszVer++;
  88. }
  89. pOSVer->dwMajor = Numbers[0];
  90. pOSVer->dwMinor = Numbers[1];
  91. pOSVer->dwBuildNumber = Numbers[2];
  92. pOSVer->dwSPMajor = Numbers[3];
  93. pOSVer->dwSPMinor = Numbers[4];
  94. return S_OK;
  95. }
  96. //-----------------------------------------------------------------------
  97. //
  98. // Private helper function: retrieve version info from current OS
  99. //
  100. //-----------------------------------------------------------------------
  101. HRESULT GetCurrentOSVerInfo(pOSVerForRedirect pOSVer)
  102. {
  103. OSVERSIONINFO osVer;
  104. OSVERSIONINFOEX osVerEx;
  105. osVer.dwOSVersionInfoSize = sizeof(osVer);
  106. osVerEx.dwOSVersionInfoSize = sizeof(osVerEx);
  107. if (NULL == pOSVer)
  108. {
  109. return E_INVALIDARG;
  110. }
  111. //
  112. // first, get basic version info
  113. //
  114. if (0 == GetVersionEx(&osVer))
  115. {
  116. return HRESULT_FROM_WIN32(GetLastError());
  117. }
  118. //
  119. // check what kinf of platform is this?
  120. //
  121. if (VER_PLATFORM_WIN32_WINDOWS == osVer.dwPlatformId ||
  122. (VER_PLATFORM_WIN32_NT == osVer.dwPlatformId && osVer.dwMajorVersion < 5) )
  123. {
  124. //
  125. // if this is Win9X or NT4 and below, then OSVERSIONINFO is the only thing we can get
  126. // unless we hard code all those SP strings here.
  127. // Since Windows Update team has no intention to set different site
  128. // for different releases and SPs of these down level OS, we simply put 0.0 for
  129. // SP components.
  130. //
  131. osVerEx.dwMajorVersion = osVer.dwMajorVersion;
  132. osVerEx.dwMinorVersion = osVer.dwMinorVersion;
  133. osVerEx.dwBuildNumber = osVer.dwBuildNumber;
  134. osVerEx.wServicePackMajor = osVerEx.wServicePackMinor = 0x0;
  135. }
  136. else
  137. {
  138. //
  139. // for later OS, we can get OSVERSIONINFOEX data, which contains SP data
  140. //
  141. if (0 == GetVersionEx((LPOSVERSIONINFO)&osVerEx))
  142. {
  143. return HRESULT_FROM_WIN32(GetLastError());
  144. }
  145. }
  146. pOSVer->dwMajor = osVerEx.dwMajorVersion;
  147. pOSVer->dwMinor = osVerEx.dwMinorVersion;
  148. pOSVer->dwBuildNumber = osVerEx.dwBuildNumber;
  149. pOSVer->dwSPMajor = osVerEx.wServicePackMajor;
  150. pOSVer->dwSPMinor = osVerEx.wServicePackMinor;
  151. return S_OK;
  152. }
  153. //-----------------------------------------------------------------------
  154. //
  155. // Private helper function: to tell one given ver structure is between
  156. // two known ver structures or not.
  157. //
  158. // when compare, pass all 3 structures in ptr. Any NULL ptr will return FALSE
  159. //
  160. //-----------------------------------------------------------------------
  161. BOOL IsVerInRange(pOSVerForRedirect pVerToBeTested,
  162. const pOSVerForRedirect pVerRangeStart,
  163. const pOSVerForRedirect pVerRangeEnd)
  164. {
  165. if (NULL == pVerToBeTested ||
  166. NULL == pVerRangeStart ||
  167. NULL == pVerRangeEnd)
  168. {
  169. return FALSE;
  170. }
  171. return ((pVerRangeStart->dwMajor < pVerToBeTested->dwMajor && // if major in the range
  172. pVerToBeTested->dwMajor < pVerRangeEnd->dwMajor) ||
  173. ((pVerRangeStart->dwMajor == pVerToBeTested->dwMajor || // or major equal
  174. pVerRangeEnd->dwMajor == pVerToBeTested->dwMajor) &&
  175. ((pVerRangeStart->dwMinor < pVerToBeTested->dwMinor && // and minor in the range
  176. pVerToBeTested->dwMinor < pVerRangeEnd->dwMinor) ||
  177. ((pVerRangeStart->dwMinor == pVerToBeTested->dwMinor || // or minor equal too
  178. pVerToBeTested->dwMinor == pVerRangeEnd->dwMinor) &&
  179. ((pVerRangeStart->dwBuildNumber < pVerToBeTested->dwBuildNumber && // and build number in the range
  180. pVerToBeTested->dwBuildNumber < pVerRangeEnd->dwBuildNumber) ||
  181. ((pVerRangeStart->dwBuildNumber == pVerToBeTested->dwBuildNumber || // or build number equal too
  182. pVerToBeTested->dwBuildNumber == pVerRangeEnd->dwBuildNumber) &&
  183. ((pVerRangeStart->dwSPMajor < pVerToBeTested->dwSPMajor && // and service pack major within
  184. pVerToBeTested->dwSPMajor < pVerRangeEnd->dwSPMajor) ||
  185. ((pVerRangeStart->dwSPMajor == pVerToBeTested->dwSPMajor || // or spmajor equal too
  186. pVerToBeTested->dwSPMajor == pVerRangeEnd->dwSPMajor) &&
  187. ((pVerRangeStart->dwSPMinor <= pVerToBeTested->dwSPMinor && // and sp minor within
  188. pVerToBeTested->dwSPMinor <= pVerRangeEnd->dwSPMinor)
  189. )
  190. )
  191. )
  192. )
  193. )
  194. )
  195. )
  196. ));
  197. }
  198. //-----------------------------------------------------------------------
  199. //
  200. // GetRedirectServerUrl()
  201. // Search the [redirect] section of the given init file for the base
  202. // server URL corresponding to the OS version.
  203. //
  204. // Parameters:
  205. // pcszInitFile - file name (including path) of the ini file.
  206. // if this paramater is NULL or empty string,
  207. // then it's assumed IUident.txt file.
  208. // lpszNewUrl - point to a buffer to receive redirect server url, if found
  209. // nBufSize - size of pointed buffer, in number of chars
  210. //
  211. // Returns:
  212. // HRESULT about success or error of this action
  213. // S_OK - the redirect server url is found and been put into pszBuffer
  214. // S_FALSE - no redirect server url defined for this OS.
  215. // other - error code
  216. //
  217. // Comments:
  218. // Expected section in IUIDENT has the following format;
  219. // Section name: [redirect]
  220. // Its entries should be defined according to GetINIValueByOSVer().
  221. //
  222. //-----------------------------------------------------------------------
  223. HRESULT GetRedirectServerUrl(
  224. LPCTSTR pcszInitFile, // path of file name.
  225. LPTSTR lpszNewUrl, // points to a buffer to receive new server url
  226. int nBufSize // size of buffer, in chars
  227. )
  228. {
  229. LOG_Block("GetRedirectServerUrl()");
  230. return GetINIValueByOSVer(
  231. pcszInitFile,
  232. REDIRECT_SECTION,
  233. lpszNewUrl,
  234. nBufSize);
  235. }
  236. //-----------------------------------------------------------------------
  237. //
  238. // GetINIValueByOSVer()
  239. // Search the specified section of the given init file for
  240. // the value corresponding to the version of the OS.
  241. //
  242. // Parameters:
  243. // pcszInitFile - file name (including path) of the ini file.
  244. // if this paramater is NULL or empty string,
  245. // then it's assumed IUident.txt file.
  246. // pcszSection - section name which the key is under
  247. // lpszValue - point to a buffer to receive the entry value, if found
  248. // nBufSize - size of pointed buffer, in number of chars
  249. //
  250. // Returns:
  251. // HRESULT about success or error of this action
  252. // S_OK - the redirect server url is found and been put into pszBuffer
  253. // S_FALSE - no value defined for this OS.
  254. // other - error code
  255. //
  256. // Comments:
  257. // Expected section in IUIDENT has the following format;
  258. // this section contains zero or more entries, each entry has format:
  259. // <beginVersionRange>-<endVersionRange>=<redirect server url>
  260. // where:
  261. // <beginVersionRange> ::= <VersionRangeBound>
  262. // <endVersionRange> ::= <VersionRangeBound>
  263. // <VersionRangeBound> ::= EMPTY | Major[.Minor[.Build[.ServicePackMajor[.ServicePackMinor]]]]
  264. // <redirect server url>=http://blahblah....
  265. // an empty version range bound means boundless.
  266. // a missing version component at end of a version data string means default value 0.
  267. // (e.g., 5.2 = 5.2.0.0.0)
  268. //
  269. //-----------------------------------------------------------------------
  270. HRESULT GetINIValueByOSVer(
  271. LPCTSTR pcszInitFile, // path of file name.
  272. LPCTSTR pcszSection, // section name
  273. LPTSTR lpszValue, // points to a buffer to receive new server url
  274. int nBufSize) // size of buffer, in chars
  275. {
  276. LOG_Block("GetINIValueByOSVer");
  277. HRESULT hr = S_OK;
  278. TCHAR szInitFile[MAX_PATH];
  279. LPTSTR pszBuffer = NULL;
  280. LPTSTR pszCurrentChar = NULL;
  281. LPCTSTR pszDash = NULL;
  282. DWORD dwRet;
  283. DWORD dwSize = INTERNET_MAX_URL_LENGTH;
  284. if (NULL == pcszSection || NULL == lpszValue || nBufSize < 1)
  285. {
  286. return E_INVALIDARG;
  287. }
  288. OSVerForRedirect osCurrent, osBegin, osEnd;
  289. CleanUpIfFailedAndSetHrMsg(GetCurrentOSVerInfo(&osCurrent));
  290. pszBuffer = (LPTSTR) malloc(dwSize * sizeof(TCHAR));
  291. CleanUpFailedAllocSetHrMsg(pszBuffer);
  292. //
  293. // find out what's the right init file to search
  294. //
  295. if (NULL == pcszInitFile ||
  296. _T('\0') == *pcszInitFile)
  297. {
  298. //
  299. // if not specified, use iuident.txt
  300. //
  301. GetIndustryUpdateDirectory(pszBuffer);
  302. if (FAILED(hr=PathCchCombine(szInitFile,ARRAYSIZE(szInitFile), pszBuffer, IDENTTXT)) )
  303. {
  304. goto CleanUp;
  305. }
  306. }
  307. else
  308. {
  309. lstrcpyn(szInitFile, pcszInitFile, ARRAYSIZE(szInitFile));
  310. }
  311. LOG_Out(_T("Init file to retrieve redirect data: %s"), szInitFile);
  312. //
  313. // read in all key names
  314. //
  315. if (GetPrivateProfileString(
  316. pcszSection,
  317. NULL,
  318. _T(""),
  319. pszBuffer,
  320. dwSize,
  321. szInitFile) == dwSize-2)
  322. {
  323. //
  324. // buffer too small? assume bad ident. stop here
  325. //
  326. hr = S_FALSE;
  327. goto CleanUp;
  328. }
  329. //
  330. // loop through each key
  331. //
  332. pszCurrentChar = pszBuffer;
  333. while (_T('\0') != *pszCurrentChar)
  334. {
  335. //
  336. // for the current key, we first try to make sure it's in the right format:
  337. // there should be a dash "-". If no, then assume this key is bad and we try to
  338. // skip it.
  339. //
  340. pszDash = MyStrChr(pszCurrentChar, _T('-'));
  341. if (NULL != pszDash)
  342. {
  343. //
  344. // get lower bound of ver range. If string starts with "-",
  345. // then the returned ver would be 0.0.0.0.0
  346. //
  347. ConvertStrToOSVer(pszCurrentChar, &osBegin);
  348. //
  349. // get upper bound of ver range
  350. //
  351. pszDash++;
  352. ConvertStrToOSVer(pszDash, &osEnd);
  353. if (0x0 == osEnd.dwMajor &&
  354. 0x0 == osEnd.dwMinor &&
  355. 0x0 == osEnd.dwBuildNumber &&
  356. 0x0 == osEnd.dwSPMajor &&
  357. 0x0 == osEnd.dwSPMinor)
  358. {
  359. //
  360. // if 0.0.0.0.0. it means nothing after "-".
  361. // assume the upper bound is unlimited
  362. //
  363. osEnd = MAX_VERSION;
  364. }
  365. if (IsVerInRange(&osCurrent, &osBegin, &osEnd))
  366. {
  367. //
  368. // the current OS falls in this range.
  369. // we read the redirect URL
  370. //
  371. if (GetPrivateProfileString(
  372. pcszSection,
  373. pszCurrentChar, // use current str as key
  374. _T(""),
  375. lpszValue,
  376. nBufSize,
  377. szInitFile) == nBufSize - 1)
  378. {
  379. Win32MsgSetHrGotoCleanup(ERROR_INSUFFICIENT_BUFFER);
  380. }
  381. hr = S_OK;
  382. goto CleanUp;
  383. }
  384. }
  385. //
  386. // move to next string
  387. //
  388. pszCurrentChar += lstrlen(pszCurrentChar) + 1;
  389. }
  390. //
  391. // if come to here, it means no suitable version range found.
  392. //
  393. *lpszValue = _T('\0');
  394. hr = S_FALSE;
  395. CleanUp:
  396. SafeFree(pszBuffer);
  397. return hr;
  398. }
  399. //-----------------------------------------------------------------------
  400. //
  401. // DownloadCab()
  402. // download a cab file of specific name from a base web address. The
  403. // file will be saved locally, with file trust verified and extracted to
  404. // a specific folder.
  405. //
  406. // Parameters:
  407. // hQuitEvent - the event handle to cancel this operation
  408. // ptszCabName - the file name of the cab file (eg. iuident.cab)
  409. // ptszBaseUrl - the base web address to download the cab file
  410. // ptszExtractDir - the local dir to save the cab file and those extracted from it
  411. // dwFlags - the set of flags to be passed to DownloadFileLite()
  412. // fExtractFiles (default as TRUE) - extract files
  413. //
  414. // Returns:
  415. // HRESULT about success or error of this action
  416. // S_OK - iuident.cab was successfully downloaded into the specified location
  417. // other - error code
  418. //
  419. //-----------------------------------------------------------------------
  420. HRESULT DownloadCab(
  421. HANDLE hQuitEvent,
  422. LPCTSTR ptszCabName,
  423. LPCTSTR ptszBaseUrl,
  424. LPCTSTR ptszExtractDir,
  425. DWORD dwFlags,
  426. BOOL fExtractFiles)
  427. {
  428. LOG_Block("DownloadCab");
  429. LPTSTR ptszFullCabUrl;
  430. if (NULL == ptszCabName ||
  431. NULL == ptszBaseUrl ||
  432. _T('\0') == *ptszBaseUrl ||
  433. NULL == ptszExtractDir ||
  434. _T('\0') == *ptszExtractDir)
  435. {
  436. return E_INVALIDARG;
  437. }
  438. if (NULL == (ptszFullCabUrl = (LPTSTR) malloc(sizeof(TCHAR) * INTERNET_MAX_URL_LENGTH)))
  439. {
  440. return E_OUTOFMEMORY;
  441. }
  442. HRESULT hr = S_OK;
  443. TCHAR tszTarget[MAX_PATH+1];
  444. int nBaseUrlLen = lstrlen(ptszBaseUrl);
  445. if (SUCCEEDED(PathCchCombine(tszTarget,ARRAYSIZE(tszTarget),ptszExtractDir, ptszCabName)) &&
  446. INTERNET_MAX_URL_LENGTH > nBaseUrlLen)
  447. {
  448. hr=StringCchCopyEx(ptszFullCabUrl,INTERNET_MAX_URL_LENGTH,ptszBaseUrl,NULL,NULL,MISTSAFE_STRING_FLAGS);
  449. CleanUpIfFailedAndMsg(hr);
  450. if (_T('/') != ptszFullCabUrl[nBaseUrlLen-1])
  451. {
  452. ptszFullCabUrl[nBaseUrlLen++] = _T('/');
  453. }
  454. if (INTERNET_MAX_URL_LENGTH > nBaseUrlLen + lstrlen(ptszCabName))
  455. {
  456. //
  457. // changes made by charlma 4/24/2002: add a safegard:
  458. //
  459. // first, make sure that if the local file exist, then it must be trusted. Otherwise,
  460. // it will block the download if the size/timestamp match the server file.
  461. //
  462. if (FileExists(tszTarget))
  463. {
  464. hr = VerifyFileTrust(tszTarget, NULL, ReadWUPolicyShowTrustUI());
  465. if (FAILED(hr))
  466. {
  467. (void)DeleteFile(tszTarget);
  468. }
  469. }
  470. hr=StringCchCopyEx(ptszFullCabUrl+ nBaseUrlLen,INTERNET_MAX_URL_LENGTH-nBaseUrlLen,ptszCabName,NULL,NULL,MISTSAFE_STRING_FLAGS);
  471. CleanUpIfFailedAndMsg(hr);
  472. // if (SUCCEEDED(hr = DownloadFile(
  473. // ptszFullCabUrl, // full http url
  474. // ptszBaseUrl,
  475. // tszTarget, // optional local file name to rename the downloaded file to if pszLocalPath does not contain file name
  476. // NULL,
  477. // &hQuitEvent, // quit event
  478. // 1,
  479. // NULL,
  480. // NULL,
  481. // dwFlags))) //dwFlags | WUDF_ALLOWWINHTTPONLY)))
  482. if (SUCCEEDED(hr = DownloadFileLite(
  483. ptszFullCabUrl, // full http url
  484. tszTarget, // optional local file name to rename the downloaded file to if pszLocalPath does not contain file name
  485. hQuitEvent, // quit event
  486. dwFlags))) //dwFlags | WUDF_ALLOWWINHTTPONLY)))
  487. {
  488. // need to use the VerifyFile function, not CheckWinTrust (WU bug # 12251)
  489. if (SUCCEEDED(hr = VerifyFileTrust(tszTarget, NULL, ReadWUPolicyShowTrustUI())))
  490. {
  491. if (WAIT_TIMEOUT != WaitForSingleObject(hQuitEvent, 0))
  492. {
  493. hr = E_ABORT;
  494. LOG_ErrorMsg(hr);
  495. }
  496. else
  497. {
  498. //
  499. // changed by charlma for bug 602435:
  500. // added new flag to tell if we should extract files. default as TRUE
  501. //
  502. if (fExtractFiles)
  503. {
  504. if (IUExtractFiles(tszTarget, ptszExtractDir))
  505. {
  506. hr = S_OK;
  507. if (WAIT_TIMEOUT != WaitForSingleObject(hQuitEvent, 0))
  508. {
  509. hr = E_ABORT;
  510. LOG_ErrorMsg(hr);
  511. }
  512. }
  513. else
  514. {
  515. hr = E_FAIL;
  516. LOG_Error(_T("failed to extract %s"), tszTarget);
  517. }
  518. }
  519. }
  520. }
  521. else
  522. {
  523. LOG_Error(_T("VerifyFileTrust(\"%s\", NULL, ReadWUPolicyShowTrustUI()) failed (%#lx)"), tszTarget, hr);
  524. DeleteFile(tszTarget);
  525. }
  526. }
  527. #ifdef DBG
  528. else
  529. {
  530. LOG_Error(_T("DownloadFileLite(\"%s\", \"%s\", xxx, %#lx) failed (%#lx)."), ptszFullCabUrl, tszTarget, dwFlags, hr);
  531. }
  532. #endif
  533. }
  534. else
  535. {
  536. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  537. }
  538. }
  539. else
  540. {
  541. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  542. }
  543. CleanUp:
  544. free(ptszFullCabUrl);
  545. return hr;
  546. }
  547. //-----------------------------------------------------------------------
  548. //
  549. // ValidateNewlyDownloadedCab()
  550. //
  551. // This is a new helper function to validate the newly downloaded iuident.cab
  552. //
  553. // Description:
  554. // The newly downloaded iuident.cab will be saved as IUIDENTNEWCAB
  555. // then this function will do the following validation:
  556. // (1) if local iuident.cab not exist, then the new one is valid
  557. // (2) otherwise, extract iuident.txt from both cabs, make sure
  558. // the one from new cab has later date then the one from existing cab.
  559. // (3) If not valid, then delete the new cab.
  560. //
  561. // Return:
  562. // S_OK: validated, existing cab been replaced with the new one
  563. // S_FALSE: not valid, new cab deleted.
  564. // error: any error encountered during validation
  565. //
  566. //-----------------------------------------------------------------------
  567. HRESULT ValidateNewlyDownloadedCab(LPCTSTR lpszNewIdentCab)
  568. {
  569. HRESULT hr = S_OK;
  570. BOOL fRet;
  571. DWORD dwErr;
  572. TCHAR szExistingIdent[MAX_PATH + 1];
  573. TCHAR szIUDir[MAX_PATH + 1];
  574. HANDLE hFile = INVALID_HANDLE_VALUE;
  575. FILETIME ft1, ft2;
  576. ZeroMemory(&ft1, sizeof(ft1));
  577. ZeroMemory(&ft2, sizeof(ft2));
  578. LOG_Block("ValidateNewlyDownloadedCab()");
  579. if (NULL == lpszNewIdentCab)
  580. {
  581. hr = E_INVALIDARG;
  582. LOG_ErrorMsg(hr);
  583. return hr;
  584. }
  585. if (!FileExists(lpszNewIdentCab))
  586. {
  587. LOG_ErrorMsg(ERROR_PATH_NOT_FOUND);
  588. hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
  589. return hr;
  590. }
  591. //
  592. // create existing cab path
  593. //
  594. fRet = GetWUDirectory(szIUDir, ARRAYSIZE(szIUDir), TRUE);
  595. CleanUpIfFalseAndSetHrMsg(!fRet, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND));
  596. hr = PathCchCombine(szExistingIdent, ARRAYSIZE(szExistingIdent), szIUDir, IDENTCAB);
  597. CleanUpIfFailedAndMsg(hr);
  598. //
  599. // if original ident not exist, we will assume the new one is valid,
  600. // since we don't have anything else to validate against!
  601. //
  602. if (!FileExists(szExistingIdent))
  603. {
  604. LOG_Internet(_T("%s not exist. Will use new cab"), szExistingIdent);
  605. hr = S_OK;
  606. goto CleanUp;
  607. }
  608. if (!IUExtractFiles(szExistingIdent, szIUDir, IDENTTXT))
  609. {
  610. LOG_Internet(_T("Error 0x%x when extracting ident.txt from %s. Use new one"), GetLastError(), szExistingIdent);
  611. hr = S_OK;
  612. goto CleanUp;
  613. }
  614. //
  615. // get the time stamp from the extacted files: we borrow szExistingIdent buffer
  616. // to contstruct the file name of iuident.txt
  617. //
  618. hr = PathCchCombine(szExistingIdent, ARRAYSIZE(szExistingIdent), szIUDir, IDENTTXT);
  619. CleanUpIfFailedAndMsg(hr);
  620. //
  621. // open file for retrieving modified time
  622. //
  623. hFile = CreateFile(szExistingIdent, GENERIC_READ, FILE_SHARE_READ, NULL,
  624. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  625. if (hFile == INVALID_HANDLE_VALUE)
  626. {
  627. LOG_ErrorMsg(GetLastError());
  628. hr = S_OK; // use new cab
  629. goto CleanUp;
  630. }
  631. if (!GetFileTime(hFile, NULL, NULL, &ft1))
  632. {
  633. LOG_ErrorMsg(GetLastError());
  634. hr = S_OK; // use new cab
  635. goto CleanUp;
  636. }
  637. CloseHandle(hFile);
  638. hFile = INVALID_HANDLE_VALUE;
  639. DeleteFile(szExistingIdent);
  640. //
  641. // extract files from new cab
  642. //
  643. if (!IUExtractFiles(lpszNewIdentCab, szIUDir, IDENTTXT))
  644. {
  645. dwErr = GetLastError();
  646. LOG_Internet(_T("Error 0x%x when extracting ident.txt from %s"), dwErr, lpszNewIdentCab);
  647. hr = HRESULT_FROM_WIN32(dwErr);
  648. goto CleanUp;
  649. }
  650. //
  651. // open file for retrieving modified time
  652. //
  653. hFile = CreateFile(szExistingIdent, GENERIC_READ, FILE_SHARE_READ, NULL,
  654. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  655. if (hFile == INVALID_HANDLE_VALUE)
  656. {
  657. dwErr = GetLastError();
  658. LOG_ErrorMsg(dwErr);
  659. hr = HRESULT_FROM_WIN32(dwErr);
  660. goto CleanUp;
  661. }
  662. if (!GetFileTime(hFile, NULL, NULL, &ft2))
  663. {
  664. dwErr = GetLastError();
  665. LOG_ErrorMsg(dwErr);
  666. hr = HRESULT_FROM_WIN32(dwErr);
  667. goto CleanUp;
  668. }
  669. CloseHandle(hFile);
  670. hFile = INVALID_HANDLE_VALUE;
  671. DeleteFile(szExistingIdent);
  672. //
  673. // compare the two values: if ft2 (from new cab) is later than ft1 (from old cab)
  674. // then S_OK, otherwise, S_FALSE
  675. //
  676. hr = ((ft2.dwHighDateTime > ft1.dwHighDateTime) ||
  677. ((ft2.dwHighDateTime == ft1.dwHighDateTime) &&
  678. (ft2.dwLowDateTime > ft1.dwLowDateTime)))
  679. ? S_OK : S_FALSE;
  680. CleanUp:
  681. if (INVALID_HANDLE_VALUE != hFile)
  682. {
  683. CloseHandle(hFile);
  684. }
  685. if (S_OK == hr)
  686. {
  687. //
  688. // validated. copy the new cab to existing cab name
  689. //
  690. (void)PathCchCombine(szExistingIdent, ARRAYSIZE(szExistingIdent), szIUDir, IDENTCAB);
  691. if (CopyFile(lpszNewIdentCab, szExistingIdent, FALSE))
  692. {
  693. LOG_Internet(_T("New cab is better, copy to existing one, if any"));
  694. }
  695. else
  696. {
  697. dwErr = GetLastError();
  698. LOG_ErrorMsg(dwErr);
  699. hr = HRESULT_FROM_WIN32(dwErr);
  700. }
  701. }
  702. else
  703. {
  704. //
  705. // if not to use the new cab, we delete it.
  706. //
  707. LOG_Internet(_T("Error (0x%x) or new iuident.cab not better than old one."), hr);
  708. if ((ft2.dwHighDateTime != ft1.dwHighDateTime) || (ft2.dwLowDateTime != ft1.dwLowDateTime))
  709. {
  710. LOG_Internet(_T("Found bad iuident.cab downloaded! Try to delete it."));
  711. if (!DeleteFile(lpszNewIdentCab))
  712. {
  713. LOG_ErrorMsg(GetLastError());
  714. }
  715. }
  716. }
  717. //
  718. // clean up the extracted ident
  719. //
  720. if (SUCCEEDED(PathCchCombine(szExistingIdent, ARRAYSIZE(szExistingIdent), szIUDir, IDENTTXT)))
  721. {
  722. DeleteFile(szExistingIdent);
  723. }
  724. return hr;
  725. }
  726. //-----------------------------------------------------------------------
  727. //
  728. // DownloadIUIdent()
  729. // download iuident.cab from a specific location, if provided.
  730. // Otherwise get it from where the WUServer registry value points to.
  731. // Either case, it will handle ident redirection.
  732. //
  733. // Parameters:
  734. // hQuitEvent - the event handle to cancel this operation
  735. // ptszBaseUrl - the initial base URL for iuident.cab, must be no bigger than
  736. // (INTERNET_MAX_URL_LENGTH) TCHARs. Otherwise use
  737. // WUServer entry from policy. If entry not found,
  738. // use "http://windowsupdate.microsoft.com/v4"
  739. // ptszFileCacheDir - the local base path to store the iuident.cab and
  740. // the files extracted from it
  741. // dwFlags - the set of flags used by DownloadCab()
  742. // fIdentFromPolicy - tell if this is corpwu use. It has these impacts:
  743. // TRUE: (1) no iuident.txt timestamp validation will be done by
  744. // comparing the newly downloaded cab and existing one.
  745. // (2) if download fail and ident cab exist and valid,
  746. // we will verify trust and extract iuident to use.
  747. // FALSE: will validate newly downloaded cab against existing one
  748. //
  749. // Returns:
  750. // HRESULT about success or error of this action
  751. // S_OK - iuident.cab was successfully downloaded into the specified location
  752. // other - error code
  753. //
  754. //-----------------------------------------------------------------------
  755. HRESULT DownloadIUIdent(
  756. HANDLE hQuitEvent,
  757. LPCTSTR ptszBaseUrl,
  758. LPTSTR ptszFileCacheDir,
  759. DWORD dwFlags,
  760. BOOL fIdentFromPolicy
  761. )
  762. {
  763. LOG_Block("DownloadIUIdent");
  764. HRESULT hr = S_OK;
  765. TCHAR tszTargetPath[MAX_PATH + 1];
  766. LPTSTR ptszIdentBaseUrl = NULL;
  767. BOOL fVerifyTempDir = TRUE;
  768. DWORD dwErr = 0;
  769. USES_MY_MEMORY;
  770. if (NULL == ptszBaseUrl ||
  771. NULL == ptszFileCacheDir)
  772. {
  773. return E_INVALIDARG;
  774. }
  775. ptszIdentBaseUrl = (LPTSTR) MemAlloc(sizeof(TCHAR) * INTERNET_MAX_URL_LENGTH);
  776. CleanUpFailedAllocSetHrMsg(ptszIdentBaseUrl);
  777. hr = StringCchCopyEx(ptszIdentBaseUrl, INTERNET_MAX_URL_LENGTH, ptszBaseUrl, NULL,NULL,MISTSAFE_STRING_FLAGS);
  778. CleanUpIfFailedAndMsg(hr);
  779. int iRedirectCounter = 3; // any non-negative value; to catch circular reference
  780. while (0 <= iRedirectCounter)
  781. {
  782. if (fIdentFromPolicy)
  783. {
  784. //
  785. // for corpwu case, always download it to overwrite the original
  786. // no iuident.txt timestamp validation needed.
  787. //
  788. hr = StringCchCopyEx(tszTargetPath, ARRAYSIZE(tszTargetPath), ptszFileCacheDir, NULL,NULL,MISTSAFE_STRING_FLAGS);
  789. CleanUpIfFailedAndMsg(hr);
  790. }
  791. else
  792. {
  793. //
  794. // constrcut the temp local path for consumer case: download it to v4\temp
  795. //
  796. hr = PathCchCombine(tszTargetPath, ARRAYSIZE(tszTargetPath), ptszFileCacheDir, IDENTNEWCABDIR);
  797. CleanUpIfFailedAndMsg(hr);
  798. if (fVerifyTempDir)
  799. {
  800. if (!CreateNestedDirectory(tszTargetPath))
  801. {
  802. dwErr = GetLastError();
  803. LOG_ErrorMsg(dwErr);
  804. hr = HRESULT_FROM_WIN32(dwErr);
  805. goto CleanUp;
  806. }
  807. fVerifyTempDir = FALSE;
  808. }
  809. }
  810. hr = DownloadCab(
  811. hQuitEvent,
  812. IDENTCAB,
  813. ptszIdentBaseUrl,
  814. tszTargetPath,
  815. dwFlags,
  816. FALSE); // download cab without extracting it.
  817. if (FAILED(hr))
  818. {
  819. LOG_ErrorMsg(hr);
  820. // Bad Case, couldn't download the iuident.. iuident is needed for security..
  821. #if defined(UNICODE) || defined(_UNICODE)
  822. LogError(hr, "Failed to download %ls from %ls to %ls", IDENTCAB, ptszIdentBaseUrl, tszTargetPath);
  823. #else
  824. LogError(hr, "Failed to download %s from %s to %s", IDENTCAB, ptszIdentBaseUrl, tszTargetPath);
  825. #endif
  826. //
  827. // construct original path.
  828. //
  829. HRESULT hr1 = PathCchCombine(tszTargetPath, ARRAYSIZE(tszTargetPath), ptszFileCacheDir, IDENTCAB);
  830. if (FAILED(hr1))
  831. {
  832. LOG_ErrorMsg(hr1);
  833. goto CleanUp;
  834. }
  835. if (fIdentFromPolicy && FileExists(tszTargetPath))
  836. {
  837. //
  838. // charlma: moved the fix from selfupd.cpp to here:
  839. //
  840. // bug 580808 CorpWU: IU: If corpwu server is not available when user navigates to web site,
  841. // website displays x80072ee7 error and cannot be used.
  842. // Fix:
  843. // if corpwu policy is set but the corpwu server is unavailable,
  844. // we fail over to the local iuident.
  845. // This is true for both corpwu client and site client.
  846. hr = S_OK;
  847. #if defined(DBG)
  848. LOG_Out(_T("Ignore above error, use local copy of %s from %s"), IDENTCAB, ptszFileCacheDir);
  849. #endif
  850. #if defined(UNICODE) || defined(_UNICODE)
  851. LogMessage("Ignore above error, use local copy of %ls from %ls", IDENTCAB, ptszFileCacheDir);
  852. #else
  853. LogMessage("Ignore above error, use local copy of %s from %s", IDENTCAB, ptszFileCacheDir);
  854. #endif
  855. }
  856. else
  857. {
  858. //
  859. // if this is the consumer case, or iuident.cab not exist, can't continue
  860. //
  861. break;
  862. }
  863. }
  864. else
  865. {
  866. #if defined(UNICODE) || defined(_UNICODE)
  867. LogMessage("Downloaded %ls from %ls to %ls", IDENTCAB, ptszIdentBaseUrl, ptszFileCacheDir);
  868. #else
  869. LogMessage("Downloaded %s from %s to %s", IDENTCAB, ptszIdentBaseUrl, ptszFileCacheDir);
  870. #endif
  871. //
  872. // added by charlma for bug 602435 fix: verify the signed time stamp of
  873. // the downloaded cab is newer than the local one.
  874. //
  875. if (!fIdentFromPolicy)
  876. {
  877. //
  878. // if the newly downloaded cab is newer, and nothing bad happen (SUCCEEDED(hr)), we
  879. // we'll have an iuident.cab there, new or old.
  880. //
  881. (void) PathCchCombine(tszTargetPath, ARRAYSIZE(tszTargetPath), ptszFileCacheDir, IDENTNEWCABDIR);
  882. hr = PathCchAppend(tszTargetPath, ARRAYSIZE(tszTargetPath), IDENTCAB);
  883. CleanUpIfFailedAndMsg(hr);
  884. hr = ValidateNewlyDownloadedCab(tszTargetPath);
  885. if (FAILED(hr))
  886. {
  887. break;
  888. }
  889. //
  890. // if we need to use old one, it's fine. so we correct S_FALSE to S_OK;
  891. //
  892. hr = S_OK;
  893. }
  894. //
  895. // construct original path. we won't fail since we already tried IDENTNEWCAB on this buffer
  896. //
  897. (void)PathCchCombine(tszTargetPath, ARRAYSIZE(tszTargetPath), ptszFileCacheDir, IDENTCAB);
  898. }
  899. //
  900. // validat the iuidentcab trust
  901. //
  902. if (FAILED(hr = VerifyFileTrust(tszTargetPath, NULL, ReadWUPolicyShowTrustUI())))
  903. {
  904. //
  905. // alreaady logged by VerifyFileTrust(), so just bail out.
  906. //
  907. DeleteFile(tszTargetPath);
  908. goto CleanUp;
  909. }
  910. //
  911. // now, we have iuident.cab ready to use. extract the files
  912. //
  913. if (!IUExtractFiles(tszTargetPath, ptszFileCacheDir, IDENTTXT))
  914. {
  915. dwErr = GetLastError();
  916. LOG_Internet(_T("Error 0x%x when extracting ident.txt from %s"), dwErr, tszTargetPath);
  917. hr = HRESULT_FROM_WIN32(dwErr);
  918. goto CleanUp;
  919. }
  920. //
  921. // now we use tszTargetPath buffer to construct the iuident.txt file
  922. //
  923. hr = PathCchCombine(tszTargetPath, ARRAYSIZE(tszTargetPath), ptszFileCacheDir, IDENTTXT);
  924. CleanUpIfFailedAndMsg(hr);
  925. //
  926. // check to see if this OS needs redirect ident
  927. //
  928. if (FAILED(hr = GetRedirectServerUrl(tszTargetPath, ptszIdentBaseUrl, INTERNET_MAX_URL_LENGTH)))
  929. {
  930. LOG_Error(_T("GetRedirectServerUrl(%s, %s, ...) failed (%#lx)"), tszTargetPath, ptszIdentBaseUrl, hr);
  931. break;
  932. }
  933. if (S_FALSE == hr || _T('\0') == ptszIdentBaseUrl[0])
  934. {
  935. LOG_Out(_T("no more redirection"));
  936. hr = S_OK;
  937. break;
  938. }
  939. if (WAIT_TIMEOUT != WaitForSingleObject(hQuitEvent, 0))
  940. {
  941. hr = E_ABORT;
  942. LOG_ErrorMsg(hr);
  943. break;
  944. }
  945. //
  946. // this OS should be redirect to get new ident.
  947. //
  948. iRedirectCounter--;
  949. }
  950. if (0 > iRedirectCounter)
  951. {
  952. // possible circular reference
  953. hr = E_FAIL;
  954. }
  955. CleanUp:
  956. return hr;
  957. }