Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2088 lines
54 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: cdmp.cpp
  6. //
  7. // Owner: YanL
  8. //
  9. // Description:
  10. //
  11. // CDM auxiliary functions
  12. //
  13. // called by DownloadIsInternetAvailable()
  14. // GetDUNConnections
  15. // IsInternetConnectionWizardCompleted
  16. // IsInternetConnected
  17. //
  18. // called by DownloadGetUpdatedFiles()
  19. // FindDevInstID
  20. //
  21. // called by OpenCDMContext()
  22. // ProcessIdent
  23. // DownloadCdmCab
  24. //
  25. // called by DownloadUpdatedFiles()
  26. // GetDownloadPath
  27. // GetWindowsUpdateDirectory
  28. // LoadCdmnewDll
  29. //
  30. // called by GetPackage()
  31. // PrepareCatalog
  32. // ProcessOsdet
  33. // BuildExclusionsList
  34. // FindCatalog
  35. // FindUpdate
  36. // DeleteNode
  37. // URLPingReport
  38. //
  39. // called by InternalQueryDetectionFiles
  40. // DownloadToBuffer
  41. //
  42. // called by InternalLogDriverNotFound()
  43. // ProcessOsdetOffline
  44. // GetUniqueFileName
  45. // GetSKUString
  46. // CdmCanonicalizeUrl
  47. //
  48. // called by DllMain()
  49. // UpdateCdmDll
  50. //
  51. // called internally
  52. // IsInMap
  53. // GetOEMandLocalBitmask
  54. // DownloadToBuffer
  55. //
  56. // WU_VARIABLE_FIELD::
  57. // GetNext
  58. // Find
  59. // WU_VARIABLE_FIELD
  60. // GetSize
  61. //
  62. //=======================================================================
  63. #include <windows.h>
  64. #include <osdet.h>
  65. #include <setupapi.h>
  66. #include <shlwapi.h>
  67. #include <softpub.h>
  68. #include <ras.h>
  69. #include <regstr.h>
  70. #include <tchar.h>
  71. #include <atlconv.h>
  72. #include <winver.h>
  73. #include <wustl.h>
  74. #include <log.h>
  75. #include <wuv3cdm.h>
  76. #include <bucket.h>
  77. #include <findoem.h>
  78. #include <DrvInfo.h>
  79. #include <newtrust.h>
  80. #include <download.h>
  81. #include <diamond.h>
  82. #include <mscat.h>
  83. #include "cdm.h"
  84. #include "cdmp.h"
  85. static ULONG IsInMap(IN PCDM_HASHTABLE pHashTable, IN LPCTSTR pHwID);
  86. static bool GetOEMandLocalBitmask(IN SHelper& helper, OUT byte_buffer& bufOut);
  87. static bool FilesIdentical(IN LPCTSTR szFileName1, IN LPCTSTR szFileName2);
  88. inline bool FileExists(IN LPCTSTR pszFile) { return 0xFFFFFFFF != GetFileAttributes(pszFile); }
  89. // MSCAT32 support (CryptCAT API's)
  90. const TCHAR MSCAT32DLL[] = _T("mscat32.dll");
  91. const TCHAR CDMCAT[] = _T("cdm.cat");
  92. const TCHAR CDMDLL[] = _T("cdm.dll");
  93. const TCHAR CDMNEWDLL[] = _T("cdmnew.dll");
  94. const TCHAR IUCDMDLL[] = _T("iucdm.dll");
  95. // CryptCat Function Pointer Types
  96. typedef BOOL (*PFN_CryptCATAdminAcquireContext)(OUT HCATADMIN *phCatAdmin,
  97. IN const GUID *pgSubsystem,
  98. IN DWORD dwFlags);
  99. typedef HCATINFO (*PFN_CryptCATAdminAddCatalog)(IN HCATADMIN hCatAdmin,
  100. IN WCHAR *pwszCatalogFile,
  101. IN OPTIONAL WCHAR *pwszSelectBaseName,
  102. IN DWORD dwFlags);
  103. typedef BOOL (*PFN_CryptCATCatalogInfoFromContext)(IN HCATINFO hCatInfo,
  104. IN OUT CATALOG_INFO *psCatInfo,
  105. IN DWORD dwFlags);
  106. typedef BOOL (*PFN_CryptCATAdminReleaseCatalogContext)(IN HCATADMIN hCatAdmin,
  107. IN HCATINFO hCatInfo,
  108. IN DWORD dwFlags);
  109. typedef BOOL (*PFN_CryptCATAdminReleaseContext)(IN HCATADMIN hCatAdmin,
  110. IN DWORD dwFlags);
  111. // ----------------------------------------------------------------------------------
  112. //
  113. // functions to compare file versions borrowed from IU
  114. //
  115. // ----------------------------------------------------------------------------------
  116. // ----------------------------------------------------------------------------------
  117. //
  118. // define a type to hold file version data
  119. //
  120. // ----------------------------------------------------------------------------------
  121. typedef struct _FILE_VERSION
  122. {
  123. WORD Major;
  124. WORD Minor;
  125. WORD Build;
  126. WORD Ext;
  127. } FILE_VERSION, *LPFILE_VERSION;
  128. static BOOL GetFileVersion(LPCTSTR lpsFile, LPFILE_VERSION lpstVersion)
  129. {
  130. LOG_block("GetFileVersion()");
  131. DWORD dwVerInfoSize;
  132. DWORD dwHandle;
  133. DWORD dwVerNumber;
  134. LPVOID lpBuffer = NULL;
  135. UINT uiSize;
  136. VS_FIXEDFILEINFO* lpVSFixedFileInfo;
  137. if (NULL != lpstVersion)
  138. {
  139. //
  140. // if this pointer not null, we always try to initialize
  141. // this structure to 0, in order to reduce the change of
  142. // programming error, no matter the file exists or not.
  143. //
  144. ZeroMemory(lpstVersion, sizeof(FILE_VERSION));
  145. }
  146. if (NULL == lpsFile || NULL == lpstVersion)
  147. {
  148. LOG_error("E_INVALIDARG");
  149. return FALSE;
  150. }
  151. dwVerInfoSize = GetFileVersionInfoSize((LPTSTR)lpsFile, &dwHandle);
  152. if (0 == dwVerInfoSize)
  153. {
  154. DWORD dwErr = GetLastError();
  155. if (0 == dwErr)
  156. {
  157. LOG_error("File %s does not have version data.", lpsFile);
  158. }
  159. else
  160. {
  161. LOG_error("Error: 0x%08x", dwErr);
  162. }
  163. return FALSE;
  164. }
  165. if (NULL == (lpBuffer = (LPVOID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwVerInfoSize)))
  166. {
  167. LOG_error("Failed to allocate memory to get version info");
  168. return FALSE;
  169. }
  170. if (!GetFileVersionInfo((LPTSTR)lpsFile, dwHandle, dwVerInfoSize, lpBuffer))
  171. {
  172. LOG_error("GetFileVersionInfo: 0x%08x", GetLastError());
  173. HeapFree(GetProcessHeap(), 0, lpBuffer);
  174. return FALSE;
  175. }
  176. //
  177. // Get the value for Translation
  178. //
  179. if (!VerQueryValue(lpBuffer, _T("\\"), (LPVOID*)&lpVSFixedFileInfo, &uiSize) && (uiSize))
  180. {
  181. LOG_error("VerQueryValue: 0x%08x", GetLastError());
  182. HeapFree(GetProcessHeap(), 0, lpBuffer);
  183. return FALSE;
  184. }
  185. dwVerNumber = lpVSFixedFileInfo->dwFileVersionMS;
  186. lpstVersion->Major = HIWORD(dwVerNumber);
  187. lpstVersion->Minor = LOWORD(dwVerNumber);
  188. dwVerNumber = lpVSFixedFileInfo->dwFileVersionLS;
  189. lpstVersion->Build = HIWORD(dwVerNumber);
  190. lpstVersion->Ext = LOWORD(dwVerNumber);
  191. LOG_out("File %s found version %d.%d.%d.%d",
  192. lpsFile,
  193. lpstVersion->Major,
  194. lpstVersion->Minor,
  195. lpstVersion->Build,
  196. lpstVersion->Ext);
  197. HeapFree(GetProcessHeap(), 0, lpBuffer);
  198. return TRUE;
  199. }
  200. static int CompareVersions(const FILE_VERSION stVersion1, const FILE_VERSION stVersion2)
  201. {
  202. if ((short)stVersion1.Major < 0 || (short)stVersion2.Major < 0)
  203. {
  204. //
  205. // two empty version structure to compare, we call it equal
  206. //
  207. return 0;
  208. }
  209. if (stVersion1.Major != stVersion2.Major)
  210. {
  211. //
  212. // major diff, then we know the answer
  213. //
  214. return (stVersion1.Major < stVersion2.Major) ? -1 : 1;
  215. }
  216. else
  217. {
  218. if ((short)stVersion1.Minor < 0 || (short)stVersion2.Minor < 0)
  219. {
  220. //
  221. // if any minor missing, they equal
  222. //
  223. return 0;
  224. }
  225. if (stVersion1.Minor != stVersion2.Minor)
  226. {
  227. //
  228. // minor diff, then we know the answer
  229. //
  230. return (stVersion1.Minor < stVersion2.Minor) ? -1 : 1;
  231. }
  232. else
  233. {
  234. if ((short)stVersion1.Build < 0 || (short)stVersion2.Build < 0)
  235. {
  236. //
  237. // if any build is missing, they equal
  238. //
  239. return 0;
  240. }
  241. if (stVersion1.Build != stVersion2.Build)
  242. {
  243. //
  244. // if build diff then we are done
  245. //
  246. return (stVersion1.Build < stVersion2.Build) ? -1 : 1;
  247. }
  248. else
  249. {
  250. if ((short)stVersion1.Ext < 0 || (short)stVersion2.Ext < 0 || stVersion1.Ext == stVersion2.Ext)
  251. {
  252. //
  253. // if any ext is missing, or they equal, we are done
  254. //
  255. return 0;
  256. }
  257. else
  258. {
  259. return (stVersion1.Ext < stVersion2.Ext) ? -1 : 1;
  260. }
  261. }
  262. }
  263. }
  264. }
  265. // ----------------------------------------------------------------------------------
  266. //
  267. // return in pCompareResult:
  268. // -1: if file ver of 1st parameter < file ver of 2nd parameter
  269. // 0: if file ver of 1st parameter = file ver of 2nd parameter
  270. // +1: if file ver of 1st parameter > file ver of 2nd parameter
  271. //
  272. // ----------------------------------------------------------------------------------
  273. static HRESULT CompareFileVersions(LPCTSTR lpsFile1, LPCTSTR lpsFile2, int *pCompareResult)
  274. {
  275. LOG_block("CompareFileVersion()");
  276. FILE_VERSION stVer1 = {-1,-1,-1,-1}, stVer2 = {-1,-1,-1,-1};
  277. if (NULL == lpsFile1 || NULL == lpsFile2 || NULL == pCompareResult)
  278. {
  279. LOG_error("E_INVALIDARG");
  280. return E_INVALIDARG;
  281. }
  282. if (!GetFileVersion(lpsFile1, &stVer1))
  283. {
  284. LOG_error("E_INVALIDARG");
  285. return E_INVALIDARG;
  286. }
  287. if (!GetFileVersion(lpsFile2, &stVer2))
  288. {
  289. LOG_error("E_INVALIDARG");
  290. return E_INVALIDARG;
  291. }
  292. *pCompareResult = CompareVersions(stVer1, stVer2);
  293. return S_OK;
  294. }
  295. // NTRAID#NTBUG9-218586-2000/11/27-waltw FIX: CDM: Self Update broken by enhanced WFP
  296. //
  297. // Adapted from IUInstallSFPCatalogFile
  298. //
  299. // This function is used during the selfupdate process on systems that use SFP to make
  300. // sure that we can update the engine DLL.
  301. //
  302. #if !(defined(UNICODE) || defined(_UNICODE))
  303. #error This file must be compiled Unicode to insure we get a WCHAR string!
  304. #endif
  305. static HRESULT CDMInstallSFPCatalogFile(LPCWSTR pwszCatalogFile)
  306. {
  307. LOG_block("IUInstallSFPCatalogFile()");
  308. HRESULT hr = S_OK;
  309. HCATADMIN hCatAdmin;
  310. HCATINFO hCatInfo;
  311. CATALOG_INFO CatalogInfo;
  312. DWORD dwSize = 0;
  313. DWORD dwRet;
  314. TCHAR wszCatalogFile[MAX_PATH];
  315. // First Try to Get Pointers to the CryptCAT API's
  316. PFN_CryptCATAdminAcquireContext fpnCryptCATAdminAcquireContext = NULL;
  317. PFN_CryptCATAdminAddCatalog fpnCryptCATAdminAddCatalog = NULL;
  318. PFN_CryptCATCatalogInfoFromContext fpnCryptCATCatalogInfoFromContext = NULL;
  319. PFN_CryptCATAdminReleaseCatalogContext fpnCryptCATAdminReleaseCatalogContext = NULL;
  320. PFN_CryptCATAdminReleaseContext fpnCryptCATAdminReleaseContext = NULL;
  321. HMODULE hMSCat32 = LoadLibrary(MSCAT32DLL);
  322. if (NULL == hMSCat32)
  323. {
  324. // This is Whistler only code - we require mscat32
  325. hr = E_FAIL;
  326. goto CleanUp;
  327. }
  328. fpnCryptCATAdminAcquireContext = (PFN_CryptCATAdminAcquireContext) GetProcAddress(hMSCat32, "CryptCATAdminAcquireContext");
  329. fpnCryptCATAdminAddCatalog = (PFN_CryptCATAdminAddCatalog) GetProcAddress(hMSCat32, "CryptCATAdminAddCatalog");
  330. fpnCryptCATCatalogInfoFromContext = (PFN_CryptCATCatalogInfoFromContext) GetProcAddress(hMSCat32, "CryptCATCatalogInfoFromContext");
  331. fpnCryptCATAdminReleaseCatalogContext = (PFN_CryptCATAdminReleaseCatalogContext) GetProcAddress(hMSCat32, "CryptCATAdminReleaseCatalogContext");
  332. fpnCryptCATAdminReleaseContext = (PFN_CryptCATAdminReleaseContext) GetProcAddress(hMSCat32, "CryptCATAdminReleaseContext");
  333. if ((NULL == fpnCryptCATAdminAcquireContext) ||
  334. (NULL == fpnCryptCATAdminAddCatalog) ||
  335. (NULL == fpnCryptCATCatalogInfoFromContext) ||
  336. (NULL == fpnCryptCATAdminReleaseCatalogContext) ||
  337. (NULL == fpnCryptCATAdminReleaseContext))
  338. {
  339. LOG_error("Some CryptCAT API's were not available, even though mscat32.dll was Available");
  340. hr = E_FAIL;
  341. goto CleanUp;
  342. }
  343. if (!fpnCryptCATAdminAcquireContext(&hCatAdmin, NULL, 0))
  344. {
  345. dwRet = GetLastError();
  346. LOG_error("CryptCATAdminAcquireContext Failed, Error was: %d", dwRet);
  347. hr = HRESULT_FROM_WIN32(dwRet);
  348. goto CleanUp;
  349. }
  350. //
  351. // CryptCATAdminAddCatalog takes a non-const string so be safe
  352. //
  353. lstrcpy(wszCatalogFile, pwszCatalogFile);
  354. hCatInfo = fpnCryptCATAdminAddCatalog(hCatAdmin, wszCatalogFile, NULL, 0);
  355. if (!hCatInfo)
  356. {
  357. dwRet = GetLastError();
  358. LOG_error("CryptCATAdminAddCatalog Failed, Error was: %d", dwRet);
  359. hr = HRESULT_FROM_WIN32(dwRet);
  360. fpnCryptCATAdminReleaseContext(hCatAdmin, 0);
  361. goto CleanUp;
  362. }
  363. fpnCryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfo, 0);
  364. fpnCryptCATAdminReleaseContext(hCatAdmin, 0);
  365. CleanUp:
  366. if (NULL != hMSCat32)
  367. {
  368. FreeLibrary(hMSCat32);
  369. hMSCat32 = NULL;
  370. }
  371. return hr;
  372. }
  373. //=======================================================================
  374. //
  375. // called by DownloadIsInternetAvailable()
  376. //
  377. //=======================================================================
  378. //Returns the number of dial up networking connections that this client has created.
  379. int GetDUNConnections(
  380. void
  381. ) {
  382. RASENTRYNAME rname;
  383. rname.dwSize = sizeof(RASENTRYNAME);
  384. DWORD dwSize = sizeof(rname);
  385. DWORD dwEntries = 0;
  386. RasEnumEntries(NULL, NULL, &rname, &dwSize, &dwEntries);
  387. return dwSize/sizeof(RASENTRYNAME);
  388. }
  389. //HKEY_CURRENT_USER\Software\Microsoft\Internet Connection Wizard - Completed == 01 00 00 00
  390. //Determines if the internet connection Wizzard has been completed.
  391. bool IsInternetConnectionWizardCompleted(
  392. void
  393. ) {
  394. auto_hkey hKey;
  395. if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Internet Connection Wizard"), 0, KEY_READ, &hKey) != NO_ERROR)
  396. return false;
  397. DWORD dwValue = 0;
  398. DWORD dwSize = sizeof(dwValue);
  399. return NO_ERROR == RegQueryValueEx(hKey, _T("Completed"), NULL, NULL, (PBYTE)&dwValue, &dwSize) && 1 == dwValue;
  400. }
  401. //Determines if the Internet is already connected to this client.
  402. bool IsInternetConnected(
  403. void
  404. ) {
  405. DWORD dwFlags = INTERNET_CONNECTION_LAN | INTERNET_CONNECTION_PROXY | INTERNET_CONNECTION_MODEM;
  406. return InternetGetConnectedState(&dwFlags, 0) ? true : false;
  407. }
  408. //=======================================================================
  409. //
  410. // called by OpenCDMContext()
  411. //
  412. //=======================================================================
  413. // security verification
  414. bool ProcessIdent(
  415. IN CDownload& download,
  416. IN CDiamond& diamond, //pointer to diamond compress clas to use to expand ident.cab
  417. IN LPCTSTR szSecurityServerCur,
  418. OUT LPTSTR szSiteSever, //returned description server to use.
  419. OUT LPTSTR szDownloadServer //returned cab pool download server to use.
  420. ) {
  421. LOG_block("ProcessIdent");
  422. //We need to download ident.cab since it contains the server path
  423. //for cdm.dll and the catalog to use to get the cdm.dll from.
  424. TCHAR szIdentCab[MAX_PATH+1];
  425. GetWindowsUpdateDirectory(szIdentCab);
  426. PathAppend(szIdentCab, _T("identcdm.cab"));
  427. if (!download.Copy(_T("identcdm.cab"), szIdentCab))
  428. {
  429. LOG_error("Failed to download identcdm.cab");
  430. return false;
  431. }
  432. #ifdef _WUV3TEST
  433. //
  434. // For test builds, it is ok to show certificate if WinTrustUI reg key == 1
  435. // (see CheckWinTrust in newtrust.cpp for details)
  436. //
  437. if (FAILED(VerifyFile(szIdentCab, TRUE)))
  438. #else
  439. if (FAILED(VerifyFile(szIdentCab, FALSE)))
  440. #endif
  441. {
  442. LOG_error("signature verification failed");
  443. DeleteFile(szIdentCab);
  444. SetLastError(ERROR_ACCESS_DENIED);
  445. return false;
  446. }
  447. if (!diamond.IsValidCAB(szIdentCab))
  448. {
  449. LOG_error("'%s' is not a valid cab", szIdentCab);
  450. return false;
  451. }
  452. TCHAR szIdentIni[MAX_PATH];
  453. GetWindowsUpdateDirectory(szIdentIni);
  454. PathAppend(szIdentIni, _T("identcdm.ini"));
  455. DeleteFile(szIdentIni);
  456. byte_buffer bufMemOut;
  457. if (!diamond.Decompress(szIdentCab, szIdentIni))
  458. {
  459. LOG_error("'%s' is not a valid cab", szIdentCab);
  460. return false;
  461. }
  462. TCHAR szSecurityServer[MAX_PATH];
  463. if (0 == GetPrivateProfileString(
  464. _T("cdm"), _T("SecurityServer"), _T(""), szSecurityServer, sizeOfArray(szSecurityServer), szIdentIni
  465. )) {
  466. LOG_error("GetPrivateProfileString(cdm, SecurityServer) failed");
  467. return false;
  468. }
  469. //If this ident.cab did not come from the same server in the ident.cab then it
  470. //is invalid and we cannot download any drivers.
  471. if (0 != lstrcmpi(szSecurityServer, szSecurityServerCur))
  472. {
  473. LOG_error("SecurityServer '%s' is invalid", szSecurityServer);
  474. return false;
  475. }
  476. //
  477. // szSiteServer and szDownloadServer are allocated MAX_PATH characters by caller.
  478. //
  479. if (0 == GetPrivateProfileString(
  480. _T("cdm"), _T("SiteServer"), _T(""), szSiteSever, MAX_PATH, szIdentIni
  481. )) {
  482. LOG_error("GetPrivateProfileString(cdm, SiteSever) failed");
  483. return false;
  484. }
  485. if (0 == GetPrivateProfileString(
  486. _T("cdm"), _T("DownloadServer"), _T(""), szDownloadServer, MAX_PATH, szIdentIni
  487. )) {
  488. LOG_error("GetPrivateProfileString(cdm, DownloadServer) failed");
  489. return false;
  490. }
  491. return true;
  492. }
  493. // get new cdm.cab for potential update
  494. bool DownloadCdmCab(
  495. IN CDownload& download,
  496. IN CDiamond& diamond,
  497. OUT bool& fNeedUpdate // initialized to false by caller
  498. ) {
  499. LOG_block("DownloadCdmCab");
  500. bool fIsIUCab = false;
  501. #ifdef _WIN64
  502. static const TCHAR szCabNameServer[] = _T("cdm64.cab");
  503. static const TCHAR szIUCabNameServer[] = _T("iucdm64.cab");
  504. #else
  505. static const TCHAR szCabNameServer[] = _T("cdm32.cab");
  506. static const TCHAR szIUCabNameServer[] = _T("iucdm32.cab");
  507. #endif
  508. TCHAR szWUDir[MAX_PATH];
  509. GetWindowsUpdateDirectory(szWUDir);
  510. //
  511. // First, try to get the IU cab, but don't bail if it isn't there
  512. //
  513. TCHAR szCabNameLocal[MAX_PATH];
  514. PathCombine(szCabNameLocal, szWUDir, szIUCabNameServer);
  515. if (download.Copy(szIUCabNameServer, szCabNameLocal))
  516. {
  517. fIsIUCab = true;
  518. }
  519. else
  520. {
  521. //
  522. // It wasn't on the server or we didn't get it, go get the V3 version
  523. //
  524. LOG_out("download.Copy(%s) failed, try %s", szIUCabNameServer, szCabNameServer);
  525. PathCombine(szCabNameLocal, szWUDir, szCabNameServer);
  526. if (!download.Copy(szCabNameServer, szCabNameLocal))
  527. {
  528. LOG_out("download.Copy(%s) failed", szCabNameServer);
  529. return false;
  530. }
  531. if (GetLastError() == ERROR_ALREADY_EXISTS)
  532. {
  533. LOG_out("%s is good enough", szCabNameLocal);
  534. return true;
  535. }
  536. }
  537. //
  538. // We got a cab, decompress to get cdm.dll and cdm.cat
  539. //
  540. if (!diamond.Decompress(szCabNameLocal, _T("*")))
  541. {
  542. LOG_error("Decompress '%s' failed", szCabNameLocal);
  543. // maybe it was a bogus cab - nuke the cab from our local dir
  544. DeleteFile(szCabNameLocal);
  545. return false;
  546. }
  547. TCHAR szSysDir[MAX_PATH];
  548. if (0 == GetSystemDirectory(szSysDir, MAX_PATH))
  549. {
  550. LOG_error("GetSystemDirectory: 0x%08x", GetLastError());
  551. return false;
  552. }
  553. TCHAR szCurrentCdmDll[MAX_PATH];
  554. PathCombine(szCurrentCdmDll, szSysDir, CDMDLL);
  555. TCHAR szDownloadedCdmDll[MAX_PATH];
  556. PathCombine(szDownloadedCdmDll, szWUDir, CDMDLL);
  557. TCHAR szLocalCatPath[MAX_PATH];
  558. PathCombine(szLocalCatPath, szWUDir, CDMCAT);
  559. HRESULT hr;
  560. //
  561. // If cab isn't IU version of CDM check version
  562. //
  563. if (!fIsIUCab)
  564. {
  565. // NTRAID#NTBUG9-207976-2000/11/28-waltw Check version info and only update if downloaded
  566. // cdm.dll has a version > the existing cdm.dll.
  567. int nCompareResult;
  568. if FAILED(hr = CompareFileVersions(szDownloadedCdmDll, szCurrentCdmDll, &nCompareResult))
  569. {
  570. LOG_error("CompareFileVersions: 0x%08x", hr);
  571. return false;
  572. }
  573. if (0 >= nCompareResult)
  574. {
  575. LOG_error("Downloaded cdm.dll was smaller version than existing cdm.dll in system[32] folder");
  576. //
  577. // Clean up - they are the wrong version. No further action needed so return true.
  578. //
  579. DeleteFile(szDownloadedCdmDll);
  580. DeleteFile(szLocalCatPath);
  581. return true;
  582. }
  583. }
  584. // NTRAID#NTBUG9-218586-2000/11/27-waltw FIX: CDM: Self Update broken by enhanced WFP
  585. // Now we 'should' have two files from the cdmXx.cab in the WindowsUpdate Folder
  586. // One is the CDM.DLL, the other is the Catalog File CDM.CAT so
  587. // we can install the DLL on Whistler (a SystemFileProtected/WFP OS).
  588. hr = CDMInstallSFPCatalogFile(szLocalCatPath);
  589. DeleteFile(szLocalCatPath); // delete the CAT file, once its installed its copied to a new location.
  590. if (FAILED(hr))
  591. {
  592. // Since this is Whistler, we have to bail if we didn't install the catalog since we
  593. // know that cdm.dll is under SFP/WFP.
  594. return false;
  595. }
  596. /* copy cdm.dll to system directory as iucdm.dll or cdmnew.dll */
  597. TCHAR szCdmNewDll[MAX_PATH];
  598. PathCombine(szCdmNewDll, szSysDir, fIsIUCab ? IUCDMDLL : CDMNEWDLL);
  599. if (!CopyFile(szDownloadedCdmDll, szCdmNewDll, FALSE))
  600. {
  601. LOG_error("CopyFile(%s, %s) returns %d", szDownloadedCdmDll, szCdmNewDll, GetLastError());
  602. return false;
  603. }
  604. //
  605. // Now that it's copied, we can delete from the WU dir.
  606. //
  607. DeleteFile(szDownloadedCdmDll);
  608. //
  609. // Everything OK, indicate we need to call UpdateCdmDll() from DllMain
  610. //
  611. fNeedUpdate = true;
  612. #ifdef _WUV3TEST
  613. /* Test redirect*/{
  614. auto_hkey hkey;
  615. DWORD dwSelfUpdate = 1; // On by default
  616. DWORD dwSize = sizeof(dwSelfUpdate);
  617. if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUV3TEST, 0, KEY_READ, &hkey)) {
  618. RegQueryValueEx(hkey, _T("SelfUpdate"), 0, 0, (LPBYTE)&dwSelfUpdate, &dwSize);
  619. }
  620. if (0 == dwSelfUpdate)
  621. {
  622. LOG_out("New %s Has been downloaded but SELF UPDATE is OFF", szCabNameServer);
  623. fNeedUpdate = false;
  624. }
  625. else
  626. {
  627. LOG_out("New %s Has been downloaded", szCabNameServer);
  628. }
  629. }
  630. #endif
  631. return true;
  632. }
  633. //=======================================================================
  634. //
  635. // called by DownloadUpdatedFiles()
  636. //
  637. //=======================================================================
  638. //gets a path to the directory that cdm.dll will copy the install cabs to.
  639. //returns the length of the path.
  640. //Note: The input buffer must be at least MAX_PATH size.
  641. int GetDownloadPath(
  642. IN LPTSTR szPath //CDM Local directory where extracted files will be placed.
  643. ) {
  644. if(!GetTempPath(MAX_PATH, szPath))
  645. {
  646. lstrcpy(szPath,_T("C:\\temp\\"));
  647. CreateDirectory(szPath, NULL);
  648. }
  649. PathAppend(szPath, _T("CDMinstall"));
  650. CreateDirectory(szPath, NULL);
  651. return lstrlen(szPath) + 1;
  652. }
  653. //This function returns the location of the WindowsUpdate directory. All local
  654. //files are store in this directory. The szDir parameter needs to be at least
  655. //MAX_PATH.
  656. void GetWindowsUpdateDirectory(
  657. OUT LPTSTR szDir //returned WindowsUpdate directory
  658. ) {
  659. auto_hkey hkey;
  660. szDir[0] = '\0';
  661. if (RegOpenKey(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"), &hkey) == NO_ERROR)
  662. {
  663. DWORD cbPath = _MAX_PATH;
  664. RegQueryValueEx(hkey, _T("ProgramFilesDir"), NULL, NULL, (LPBYTE)szDir, &cbPath);
  665. }
  666. if (szDir[0] == '\0')
  667. {
  668. if (! GetWindowsDirectory(szDir, _MAX_PATH))
  669. {
  670. lstrcpy(szDir, _T("C"));
  671. }
  672. szDir[1] = '\0';
  673. StrCat(szDir, _T(":\\Program Files"));
  674. }
  675. StrCat(szDir, _T("\\WindowsUpdate\\"));
  676. //Create Windows Update directory if it does not exist
  677. CreateDirectory(szDir, NULL);
  678. return;
  679. }
  680. HINSTANCE LoadCdmnewDll()
  681. {
  682. // If there is cdmnew.dll in system directory use it
  683. TCHAR szCdmNewDll[MAX_PATH];
  684. GetSystemDirectory(szCdmNewDll, sizeOfArray(szCdmNewDll));
  685. PathAppend(szCdmNewDll, CDMNEWDLL);
  686. if (!FileExists(szCdmNewDll))
  687. return 0;
  688. TCHAR szCdmDll[MAX_PATH];
  689. GetSystemDirectory(szCdmDll, sizeOfArray(szCdmDll));
  690. PathAppend(szCdmDll, _T("cdm.dll"));
  691. if (FilesIdentical(szCdmNewDll, szCdmDll))
  692. {
  693. LOG_out1("remove cdmnew.dll after selfupdate");
  694. DeleteFile(szCdmNewDll);
  695. return 0;
  696. }
  697. HINSTANCE hlib = 0;
  698. #ifdef _WUV3TEST
  699. auto_hkey hkey;
  700. DWORD dwSelfUpdate = 1; // On by default
  701. DWORD dwSize = sizeof(dwSelfUpdate);
  702. if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUV3TEST, 0, KEY_READ, &hkey)) {
  703. RegQueryValueEx(hkey, _T("SelfUpdate"), 0, 0, (LPBYTE)&dwSelfUpdate, &dwSize);
  704. }
  705. if (0 == dwSelfUpdate)
  706. LOG_out1("SELF UPDATE is OFF - using current dll");
  707. else
  708. #endif
  709. hlib = LoadLibrary(szCdmNewDll);
  710. return hlib;
  711. }
  712. //=======================================================================
  713. //
  714. // called by GetPackage()
  715. //
  716. //=======================================================================
  717. DWORD PrepareCatalog(
  718. IN LPCTSTR pszSiteServer,
  719. IN OUT SHelper& helper
  720. ) {
  721. LOG_block("PrepareCatalog");
  722. if (NULL != pszSiteServer)
  723. {
  724. if (helper.download.Connect(pszSiteServer))
  725. {
  726. LOG_out("Connected to SiteServer '%s'", pszSiteServer);
  727. }
  728. else
  729. {
  730. LOG_error("No connection to SiteServer '%s'", pszSiteServer);
  731. return ERROR_GEN_FAILURE;
  732. }
  733. }
  734. if (!helper.diamond.valid())
  735. {
  736. LOG_error("cannot init diamond");
  737. return ERROR_GEN_FAILURE;
  738. }
  739. // Get system info
  740. helper.OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  741. GetVersionEx(&helper.OSVersionInfo);
  742. SYSTEM_INFO si;
  743. GetSystemInfo(&si);
  744. helper.dwArchitecture = si.wProcessorArchitecture;
  745. //Get the catalog path, platform e.t. to use
  746. DWORD dwError = ProcessOsdet(helper);
  747. if (NO_ERROR != dwError)
  748. return dwError;
  749. if (!FindCatalog(helper))
  750. {
  751. LOG_error("no catalog");
  752. dwError = GetLastError();
  753. if (ERROR_INVALID_FUNCTION == dwError)
  754. return ERROR_INVALID_FUNCTION;
  755. else
  756. return ERROR_FILE_NOT_FOUND;
  757. }
  758. BuildExclusionsList(helper);
  759. return NO_ERROR;
  760. }
  761. // get language and platform ID from osdet.dll
  762. DWORD ProcessOsdet(
  763. IN OUT SHelper& helper
  764. ) {
  765. LOG_block("ProcessOsdet");
  766. // give it a correct name
  767. TCHAR szOsdetDllLocal[MAX_PATH];
  768. GetWindowsUpdateDirectory(szOsdetDllLocal);
  769. PathAppend(szOsdetDllLocal, _T("osdet.dll"));
  770. if (helper.download.IsConnected())
  771. {
  772. #ifdef _WIN64
  773. static const TCHAR szOsdetCabSrv[] = _T("osdet.w64");
  774. #else
  775. static const TCHAR szOsdetCabSrv[] = _T("osdet.w32");
  776. #endif
  777. // Put it to the WU directory
  778. TCHAR szOsdetCabLocal[MAX_PATH];
  779. GetWindowsUpdateDirectory(szOsdetCabLocal);
  780. PathAppend(szOsdetCabLocal, szOsdetCabSrv);
  781. if (!helper.download.Copy(szOsdetCabSrv, szOsdetCabLocal))
  782. {
  783. DWORD dwError = GetLastError();
  784. LOG_error("download.Copy(%s) failed %d", szOsdetCabSrv, dwError);
  785. return dwError;
  786. }
  787. if (GetLastError() != ERROR_ALREADY_EXISTS)
  788. {
  789. if (helper.diamond.IsValidCAB(szOsdetCabLocal))
  790. {
  791. if (!helper.diamond.Decompress(szOsdetCabLocal, szOsdetDllLocal))
  792. {
  793. DWORD dwError = GetLastError();
  794. LOG_error("Decompress '%s' failed %d", szOsdetCabLocal, dwError);
  795. return dwError;
  796. }
  797. }
  798. else
  799. {
  800. CopyFile(szOsdetCabLocal, szOsdetDllLocal, FALSE);
  801. }
  802. }
  803. }
  804. auto_hlib hlib = LoadLibrary(szOsdetDllLocal);
  805. if (!hlib.valid())
  806. {
  807. LOG_error("error loading library %s", szOsdetDllLocal);
  808. return ERROR_INVALID_FUNCTION;
  809. }
  810. PFN_V3_GetLangID fpnV3_GetLangID = (PFN_V3_GetLangID)GetProcAddress(hlib, "V3_GetLangID");
  811. if (NULL == fpnV3_GetLangID)
  812. {
  813. LOG_error("cannot find function 'V3_GetLangID'");
  814. return ERROR_CALL_NOT_IMPLEMENTED;
  815. }
  816. helper.dwLangID = (*fpnV3_GetLangID)();
  817. PFN_V3_Detection pfnV3_Detection = (PFN_V3_Detection)GetProcAddress(hlib, "V3_Detection");
  818. if (NULL == pfnV3_Detection)
  819. {
  820. LOG_error("cannot find function 'V3_Detection'");
  821. return ERROR_CALL_NOT_IMPLEMENTED;
  822. }
  823. PDWORD pdwPlatformList = 0; //Detected Platform list.
  824. int iTotalPlatforms; //Total number of detected platforms.
  825. (*pfnV3_Detection)(&pdwPlatformList, &iTotalPlatforms);
  826. if (NULL != pdwPlatformList)
  827. {
  828. helper.enPlatform = (enumV3Platform)pdwPlatformList[0];
  829. CoTaskMemFree(pdwPlatformList);
  830. }
  831. else
  832. {
  833. helper.enPlatform = enV3_DefPlat;
  834. }
  835. return S_OK;
  836. }
  837. //borrowed from osdet.cpp
  838. static int aton(LPCTSTR ptr)
  839. {
  840. int i = 0;
  841. while ('0' <= *ptr && *ptr <= '9')
  842. {
  843. i = 10 * i + (int)(*ptr - '0');
  844. ptr ++;
  845. }
  846. return i;
  847. }
  848. //borrowed from osdet.cpp
  849. static WORD CorrectGetACP(void)
  850. {
  851. WORD wCodePage = 0;
  852. auto_hkey hkey;
  853. const TCHAR REGKEY_ACP[] = _T("ACP");
  854. const TCHAR REGPATH_CODEPAGE[] = _T("SYSTEM\\CurrentControlSet\\Control\\Nls\\CodePage");
  855. RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGPATH_CODEPAGE, 0, KEY_QUERY_VALUE, &hkey);
  856. DWORD type;
  857. TCHAR szCodePage[MAX_PATH];
  858. DWORD size = sizeof(szCodePage);
  859. if (NO_ERROR == RegQueryValueEx(hkey, REGKEY_ACP, 0, &type, (BYTE *)szCodePage, &size) &&
  860. type == REG_SZ)
  861. {
  862. wCodePage = (WORD)aton(szCodePage);
  863. }
  864. return wCodePage;
  865. }
  866. //borrowed from osdet.cpp
  867. static WORD CorrectGetOEMCP(void)
  868. {
  869. WORD wCodePage = 0;
  870. auto_hkey hkey;
  871. // Registry keys to determine special OS's and enabled OS's.
  872. const TCHAR REGPATH_CODEPAGE[] = _T("SYSTEM\\CurrentControlSet\\Control\\Nls\\CodePage");
  873. const TCHAR REGKEY_OEMCP[] = _T("OEMCP");
  874. RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGPATH_CODEPAGE, 0, KEY_QUERY_VALUE, &hkey);
  875. DWORD type;
  876. TCHAR szCodePage[MAX_PATH];
  877. DWORD size = sizeof(szCodePage);
  878. if (NO_ERROR == RegQueryValueEx(hkey, REGKEY_OEMCP, 0, &type, (BYTE *)szCodePage, &size) &&
  879. type == REG_SZ)
  880. {
  881. wCodePage = (WORD)aton(szCodePage);
  882. }
  883. return wCodePage;
  884. }
  885. //borrowed from osdet.cpp
  886. static LANGID MapLangID(LANGID langid)
  887. {
  888. switch (PRIMARYLANGID(langid))
  889. {
  890. case LANG_ARABIC:
  891. langid = MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA);
  892. break;
  893. case LANG_CHINESE:
  894. if (SUBLANGID(langid) != SUBLANG_CHINESE_TRADITIONAL)
  895. langid = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
  896. break;
  897. case LANG_DUTCH:
  898. langid = MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH);
  899. break;
  900. case LANG_GERMAN:
  901. langid = MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN);
  902. break;
  903. case LANG_ENGLISH:
  904. if (SUBLANGID(langid) != SUBLANG_ENGLISH_UK)
  905. langid = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
  906. break;
  907. case LANG_FRENCH:
  908. langid = MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH);
  909. break;
  910. case LANG_ITALIAN:
  911. langid = MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN);
  912. break;
  913. case LANG_KOREAN:
  914. langid = MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN);
  915. break;
  916. case LANG_NORWEGIAN:
  917. langid = MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL);
  918. break;
  919. case LANG_PORTUGUESE:
  920. // We support both SUBLANG_PORTUGUESE and SUBLANG_PORTUGUESE_BRAZILIAN
  921. break;
  922. case LANG_SPANISH:
  923. langid = MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH);
  924. break;
  925. case LANG_SWEDISH:
  926. langid = MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH);
  927. break;
  928. };
  929. return langid;
  930. }
  931. //borrowed from osdet.cpp
  932. static bool FIsNECMachine()
  933. {
  934. const TCHAR NT5_REGPATH_MACHTYPE[] = _T("HARDWARE\\DESCRIPTION\\System");
  935. const TCHAR NT5_REGKEY_MACHTYPE[] = _T("Identifier");
  936. const TCHAR REGVAL_MACHTYPE_NEC[] = _T("NEC PC-98");
  937. const PC98_KEYBOARD_ID = 0x0D;
  938. bool fNEC = false;
  939. OSVERSIONINFO osverinfo;
  940. #define LOOKUP_OEMID(keybdid) HIBYTE(LOWORD((keybdid)))
  941. osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  942. if (GetVersionEx(&osverinfo))
  943. {
  944. if (osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
  945. {
  946. HKEY hKey;
  947. DWORD type;
  948. TCHAR tszMachineType[50];
  949. DWORD size = sizeof(tszMachineType);
  950. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  951. NT5_REGPATH_MACHTYPE,
  952. 0,
  953. KEY_QUERY_VALUE,
  954. &hKey) == ERROR_SUCCESS)
  955. {
  956. if (RegQueryValueEx(hKey,
  957. NT5_REGKEY_MACHTYPE,
  958. 0,
  959. &type,
  960. (BYTE *)tszMachineType,
  961. &size) == ERROR_SUCCESS)
  962. {
  963. if (type == REG_SZ)
  964. {
  965. if (lstrcmp(tszMachineType, REGVAL_MACHTYPE_NEC) == 0)
  966. {
  967. fNEC = true;
  968. }
  969. }
  970. }
  971. RegCloseKey(hKey);
  972. }
  973. }
  974. else // enOSWin98
  975. {
  976. // All NEC machines have NEC keyboards for Win98. NEC
  977. // machine detection is based on this.
  978. if (LOOKUP_OEMID(GetKeyboardType(1)) == PC98_KEYBOARD_ID)
  979. {
  980. fNEC = true;
  981. }
  982. }
  983. }
  984. return fNEC;
  985. }
  986. // borrowed from osdet.cpp
  987. // return V3 language ID
  988. DWORD internalV3_GetLangID()
  989. {
  990. const LANGID LANGID_ENGLISH = 0x0409;
  991. const LANGID LANGID_GREEK = 0x0408;
  992. const LANGID LANGID_JAPANESE = 0x0411;
  993. const WORD CODEPAGE_ARABIC = 1256;
  994. const WORD CODEPAGE_HEBREW = 1255;
  995. const WORD CODEPAGE_THAI = 874;
  996. const WORD CODEPAGE_GREEK_IBM = 869;
  997. WORD wCodePage = 0;
  998. LANGID langidCurrent = GetSystemDefaultUILanguage();
  999. //
  1000. // special handling for languages
  1001. //
  1002. switch (langidCurrent)
  1003. {
  1004. case LANGID_ENGLISH:
  1005. // enabled langauges
  1006. wCodePage = CorrectGetACP();
  1007. if (CODEPAGE_ARABIC != wCodePage &&
  1008. CODEPAGE_HEBREW != wCodePage &&
  1009. CODEPAGE_THAI != wCodePage)
  1010. {
  1011. wCodePage = 0;
  1012. }
  1013. break;
  1014. case LANGID_GREEK:
  1015. // Greek IBM?
  1016. wCodePage = CorrectGetOEMCP();
  1017. if (wCodePage != CODEPAGE_GREEK_IBM)
  1018. {
  1019. // if its not Greek IBM we assume its MS. The language code for Greek MS does not include
  1020. // the code page
  1021. wCodePage = 0;
  1022. }
  1023. break;
  1024. case LANGID_JAPANESE:
  1025. if (FIsNECMachine())
  1026. {
  1027. wCodePage = 1;
  1028. }
  1029. break;
  1030. default:
  1031. // map language to the ones we support
  1032. langidCurrent = MapLangID(langidCurrent);
  1033. break;
  1034. }
  1035. return MAKELONG(langidCurrent, wCodePage);
  1036. }
  1037. //borrowed from osdet.cpp
  1038. //called by V3_Detection
  1039. static enumV3Platform DetectClientPlatform(void)
  1040. {
  1041. #ifdef _WIN64
  1042. return enV3_Wistler64;
  1043. #else
  1044. return enV3_Wistler;
  1045. #endif
  1046. }
  1047. //borrowed from osdet.cpp
  1048. void internalV3_Detection(
  1049. PINT *ppiPlatformIDs,
  1050. PINT piTotalIDs
  1051. )
  1052. {
  1053. //We use coTaskMemAlloc in order to be compatible with the V3 memory allocator.
  1054. //We don't want the V3 memory exception handling in this dll.
  1055. *ppiPlatformIDs = (PINT)CoTaskMemAlloc(sizeof(INT));
  1056. if ( !*ppiPlatformIDs )
  1057. {
  1058. *piTotalIDs = 0;
  1059. }
  1060. else
  1061. {
  1062. #ifdef _WUV3TEST
  1063. auto_hkey hkey;
  1064. if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUV3TEST, 0, KEY_READ, &hkey))
  1065. {
  1066. DWORD dwPlatform = 0;
  1067. DWORD dwSize = sizeof(dwPlatform);
  1068. if (NO_ERROR == RegQueryValueEx(hkey, _T("Platform"), 0, 0, (LPBYTE)&dwPlatform, &dwSize))
  1069. {
  1070. *ppiPlatformIDs[0] = (int)dwPlatform;
  1071. *piTotalIDs = 1;
  1072. return;
  1073. }
  1074. }
  1075. #endif
  1076. *ppiPlatformIDs[0] = (int)DetectClientPlatform();
  1077. *piTotalIDs = 1;
  1078. }
  1079. }
  1080. // get language and platform ID of local machine
  1081. // similiar to ProcessOsdet
  1082. // not using osdet.dll
  1083. // If return is not S_OK, it means this function fails
  1084. DWORD ProcessOsdetOffline(
  1085. IN OUT SHelper& helper
  1086. ) {
  1087. LOG_block("ProcessOsdetOffline");
  1088. LOG_out("Call internalV3_GetLangID()");
  1089. helper.dwLangID = internalV3_GetLangID();
  1090. PINT pdwPlatformList = 0; //Detected Platform list.
  1091. int iTotalPlatforms; //Total number of detected platforms.
  1092. LOG_out("Call internalV3_Detection()");
  1093. internalV3_Detection(&pdwPlatformList, &iTotalPlatforms);
  1094. if (NULL != pdwPlatformList)
  1095. {
  1096. helper.enPlatform = (enumV3Platform)pdwPlatformList[0];
  1097. CoTaskMemFree(pdwPlatformList);
  1098. }
  1099. else
  1100. {
  1101. helper.enPlatform = enV3_DefPlat;
  1102. }
  1103. return S_OK;
  1104. }
  1105. // process excluded puids from catalog.ini
  1106. bool BuildExclusionsList(
  1107. IN SHelper& helper
  1108. ) {
  1109. LOG_block("BuildExclusionsList");
  1110. static const TCHAR szSrvPath[MAX_PATH] = _T("catalog.ini");
  1111. TCHAR szCliPath[MAX_PATH];
  1112. GetWindowsUpdateDirectory(szCliPath);
  1113. PathAppend(szCliPath, szSrvPath);
  1114. if (helper.download.IsConnected())
  1115. {
  1116. if (!helper.download.Copy(szSrvPath, szCliPath))
  1117. {
  1118. LOG_out("catalog.ini is not there");
  1119. return false;
  1120. }
  1121. }
  1122. TCHAR szValue[256];
  1123. if (0 == GetPrivateProfileString(_T("exclude"), _T("puids"), _T(""), szValue, sizeOfArray(szValue), szCliPath))
  1124. {
  1125. LOG_out("nothing is excluded");
  1126. return false;
  1127. }
  1128. LPCTSTR szInt = szValue;
  1129. while(true)
  1130. {
  1131. helper.apuidExclude.push_back(_ttoi(szInt));
  1132. szInt = _tcschr(szInt, ',');
  1133. if (NULL == szInt)
  1134. break;
  1135. szInt ++;
  1136. }
  1137. return true;
  1138. }
  1139. // for the detected platform helper.enPlatform find catalog that has drivers
  1140. bool FindCatalog(
  1141. IN OUT SHelper& helper
  1142. ) {
  1143. LOG_block("FindCatalog");
  1144. byte_buffer bufCatList;
  1145. if (!DownloadToBuffer(helper, _T("inventory.cat"), bufCatList))
  1146. {
  1147. LOG_error("Download inventory.cat failed");
  1148. return NULL;
  1149. }
  1150. int cnCatalogs = bufCatList.size() / sizeof(CATALOGLIST);
  1151. PCATALOGLIST pCatalogs = (PCATALOGLIST)(LPBYTE)bufCatList;
  1152. for (int nCatalog = 0; nCatalog < cnCatalogs; nCatalog ++)
  1153. {
  1154. LOG_out("%4d - %6d - %#08X", pCatalogs[nCatalog].dwPlatform, pCatalogs[nCatalog].dwCatPuid, pCatalogs[nCatalog].dwFlags);
  1155. if (pCatalogs[nCatalog].dwPlatform == helper.enPlatform && (pCatalogs[nCatalog].dwFlags & CATLIST_DRIVERSPRESENT))
  1156. {
  1157. helper.puidCatalog = pCatalogs[nCatalog].dwCatPuid;
  1158. LOG_out("catalog is %d", helper.puidCatalog);
  1159. return true;
  1160. }
  1161. }
  1162. LOG_error("catalog is not found");
  1163. return false;
  1164. }
  1165. static bool IsExcluded(PUID puid, SHelper& helper)
  1166. {
  1167. for (int i = 0; i < helper.apuidExclude.size(); i ++)
  1168. {
  1169. if (helper.apuidExclude[i] == puid)
  1170. return true;
  1171. }
  1172. return false;
  1173. }
  1174. //Returns NULL if there is not an update for this package or
  1175. //the download package's bucket file if there is an update.
  1176. bool FindUpdate(
  1177. IN PDOWNLOADINFO pDownloadInfo, //download information structure describing package to be read from server
  1178. IN OUT SHelper& helper,
  1179. IN OUT byte_buffer& bufBucket
  1180. ) {
  1181. LOG_block("FindUpdate");
  1182. USES_CONVERSION;
  1183. // get bitmask
  1184. byte_buffer bufBitmask;
  1185. if (! GetOEMandLocalBitmask(helper, bufBitmask))
  1186. {
  1187. LOG_error("GetOEMandLocalBitmask() failed");
  1188. return false;
  1189. }
  1190. // Get CDM inventory
  1191. TCHAR szPath[MAX_PATH];
  1192. wsprintf(szPath, _T("%d/inventory.cdm"), helper.puidCatalog);
  1193. byte_buffer bufInventory;
  1194. if (!DownloadToBuffer(helper, szPath, bufInventory))
  1195. {
  1196. LOG_error("Dowload inventory failed");
  1197. return false;
  1198. }
  1199. PCDM_HASHTABLE pHashTable = (PCDM_HASHTABLE)(LPBYTE)bufInventory;
  1200. auto_pointer< IDrvInfo > pDrvInfo;
  1201. tchar_buffer bufHardwareIDs;
  1202. // we have two types of calls
  1203. if (pDownloadInfo->lpDeviceInstanceID)
  1204. {
  1205. if (!CDrvInfoEnum::GetDrvInfo(pDownloadInfo->lpDeviceInstanceID, &pDrvInfo))
  1206. {
  1207. LOG_error("CDrvInfoEnum::GetDrvInfo(%s) failed", pDownloadInfo->lpDeviceInstanceID);
  1208. return false;
  1209. }
  1210. }
  1211. if (NULL != pDownloadInfo->lpHardwareIDs)
  1212. {
  1213. // one hardware id for a package - eather printers or w9x if we cannot find device instance ID
  1214. // if architecture is not the same as current archtecture we need to prefix it
  1215. bufHardwareIDs.resize(lstrlenW(pDownloadInfo->lpHardwareIDs) + 6);
  1216. if (!bufHardwareIDs.valid())
  1217. return false;
  1218. int cnSize = bufHardwareIDs.size();
  1219. ZeroMemory(bufHardwareIDs, cnSize);
  1220. LPTSTR pszHardwareId = bufHardwareIDs;
  1221. if (pDownloadInfo->dwArchitecture != helper.dwArchitecture)
  1222. {
  1223. if (PROCESSOR_ARCHITECTURE_INTEL == pDownloadInfo->dwArchitecture)
  1224. {
  1225. static const TCHAR szIntel[] = PRINT_ENVIRONMENT_INTEL;
  1226. lstrcpy(pszHardwareId, szIntel);
  1227. pszHardwareId += lstrlen(szIntel);
  1228. cnSize -= lstrlen(szIntel);
  1229. }
  1230. else if (PROCESSOR_ARCHITECTURE_ALPHA == pDownloadInfo->dwArchitecture)
  1231. {
  1232. static const TCHAR szAlpha[] = PRINT_ENVIRONMENT_ALPHA;
  1233. lstrcpy(pszHardwareId, szAlpha);
  1234. pszHardwareId += lstrlen(szAlpha);
  1235. cnSize -= lstrlen(szAlpha);
  1236. }
  1237. }
  1238. lstrcpy(pszHardwareId, W2T((LPWSTR)pDownloadInfo->lpHardwareIDs));
  1239. }
  1240. else if (!pDrvInfo.valid() || !pDrvInfo->GetAllHardwareIDs(bufHardwareIDs))
  1241. {
  1242. LOG_error("!pDrvInfo.valid() || !pDrvInfo->GetAllHardwareIDs()");
  1243. return false;
  1244. }
  1245. // Check if we have MatchingDeviceId
  1246. tchar_buffer bufMatchingDeviceId;
  1247. if (pDrvInfo.valid())
  1248. pDrvInfo->GetMatchingDeviceId(bufMatchingDeviceId); // It's OK not to get it
  1249. // #ifdef _WUV3TEST
  1250. if (pDrvInfo.valid() && pDrvInfo->HasDriver())
  1251. {
  1252. if (bufMatchingDeviceId.valid())
  1253. LOG_out("driver installed on MatchingDeviceId %s", (LPCTSTR)bufMatchingDeviceId);
  1254. else
  1255. LOG_error("driver installed, but HWID is not available");
  1256. }
  1257. else
  1258. {
  1259. if (bufMatchingDeviceId.valid())
  1260. LOG_error("driver is not installed, but MatchingDeviceId is %s", (LPCTSTR)bufMatchingDeviceId);
  1261. else
  1262. LOG_out("no driver installed");
  1263. }
  1264. // #endif
  1265. // Updates
  1266. bool fMoreSpecific = true;
  1267. for (LPCTSTR szHardwareId = bufHardwareIDs; fMoreSpecific && *szHardwareId; szHardwareId += lstrlen(szHardwareId) + 1)
  1268. {
  1269. // MatchingDeviceID is the last one to pay attention to
  1270. fMoreSpecific = !bufMatchingDeviceId.valid() || 0 != lstrcmpi(szHardwareId, bufMatchingDeviceId);
  1271. ULONG ulHashIndex = IsInMap(pHashTable, szHardwareId);
  1272. if (-1 == ulHashIndex)
  1273. continue;
  1274. // read bucket file
  1275. TCHAR szPath[MAX_PATH];
  1276. wsprintf(szPath, _T("%d/%d.bkf"), helper.puidCatalog, ulHashIndex);
  1277. if (!DownloadToBuffer(helper, szPath, bufBucket))
  1278. {
  1279. LOG_error("No bucket where it has to be");
  1280. continue;
  1281. }
  1282. FILETIME ftDriverInstalled = {0,0};
  1283. if (!fMoreSpecific)
  1284. {
  1285. // Then it has to have a driver - Matching device ID is set
  1286. if (!pDrvInfo->GetDriverDate(ftDriverInstalled))
  1287. {
  1288. LOG_error("!pDrvInfo->GetDriverDate(ftDriverInstalled)");
  1289. return false;
  1290. }
  1291. }
  1292. DRIVER_MATCH_INFO DriverMatchInfo;
  1293. helper.puid = CDM_FindUpdateInBucket(szHardwareId, fMoreSpecific ? NULL : &ftDriverInstalled,
  1294. bufBucket, bufBucket.size(), bufBitmask, &helper.DriverMatchInfo);
  1295. if (0 == helper.puid)
  1296. continue;
  1297. if (IsExcluded(helper.puid, helper))
  1298. continue;
  1299. return true;
  1300. }
  1301. return false;
  1302. }
  1303. // delete the whole subtree starting from current directory
  1304. bool DeleteNode(LPCTSTR szDir)
  1305. {
  1306. LOG_block("Delnode");
  1307. TCHAR szFilePath[MAX_PATH];
  1308. lstrcpy(szFilePath, szDir);
  1309. PathAppend(szFilePath, TEXT("*.*"));
  1310. // Find the first file
  1311. WIN32_FIND_DATA fd;
  1312. auto_hfindfile hFindFile = FindFirstFile(szFilePath, &fd);
  1313. return_if_false(hFindFile.valid());
  1314. do
  1315. {
  1316. if (
  1317. !lstrcmpi(fd.cFileName, TEXT(".")) ||
  1318. !lstrcmpi(fd.cFileName, TEXT(".."))
  1319. ) continue;
  1320. // Make our path
  1321. lstrcpy(szFilePath, szDir);
  1322. PathAppend(szFilePath, fd.cFileName);
  1323. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ||
  1324. (fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
  1325. ) {
  1326. SetFileAttributes(szFilePath, FILE_ATTRIBUTE_NORMAL);
  1327. }
  1328. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1329. {
  1330. return_if_false(DeleteNode(szFilePath));
  1331. }
  1332. else
  1333. {
  1334. return_if_false(DeleteFile(szFilePath));
  1335. }
  1336. }
  1337. while (FindNextFile(hFindFile, &fd));// Find the next entry
  1338. hFindFile.release();
  1339. return_if_false(RemoveDirectory(szDir));
  1340. return true;
  1341. }
  1342. void URLPingReport(IN SHelper& helper, IN LPCTSTR pszStatus)
  1343. {
  1344. srand((int)GetTickCount());
  1345. // build the URL with parameters
  1346. TCHAR szURL[INTERNET_MAX_PATH_LENGTH];
  1347. _stprintf(szURL, _T("ident/wutrack.bin?PUID=%d&PLAT=%d&LOCALE=0x%08x&STATUS=%s&RID=%04x%04x"),
  1348. helper.puid, helper.enPlatform, helper.dwLangID,
  1349. pszStatus, rand(), rand());
  1350. byte_buffer bufTmp;
  1351. helper.download.Copy(szURL, bufTmp);
  1352. }
  1353. //=======================================================================
  1354. //
  1355. // called by InternalQueryDetectionFiles()
  1356. //
  1357. //=======================================================================
  1358. // helper to download to buffer and uncab is nessasary
  1359. inline bool FileToBuffer(LPCTSTR szFileName, byte_buffer& buf)
  1360. {
  1361. auto_hfile hFile = CreateFile(szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1362. if (!hFile.valid())
  1363. return false;
  1364. DWORD dwFileSize = GetFileSize(hFile, NULL);
  1365. buf.resize(dwFileSize);
  1366. if (!ReadFile(hFile, buf, dwFileSize, &dwFileSize, NULL))
  1367. return false;
  1368. return true;
  1369. }
  1370. bool DownloadToBuffer(
  1371. IN SHelper& helper,
  1372. IN LPCTSTR szPath,
  1373. OUT byte_buffer& bufOut
  1374. ) {
  1375. LOG_block("DownloadToBuffer");
  1376. // copy to local file to have a cached version
  1377. TCHAR szTitle[MAX_PATH];
  1378. lstrcpy(szTitle, szPath);
  1379. PathStripPath(szTitle);
  1380. TCHAR szLocalPath[MAX_PATH];
  1381. GetWindowsUpdateDirectory(szLocalPath);
  1382. PathAppend(szLocalPath, szTitle);
  1383. if (helper.download.IsConnected())
  1384. {
  1385. if (!helper.download.Copy(szPath, szLocalPath))
  1386. {
  1387. LOG_error("download.Copy(%s) failed", szPath);
  1388. return false;
  1389. }
  1390. }
  1391. if (helper.diamond.IsValidCAB(szLocalPath))
  1392. {
  1393. if (!helper.diamond.Decompress(szLocalPath, bufOut))
  1394. {
  1395. LOG_error("diamond.Decompress(%s) failed", szPath);
  1396. return false;
  1397. }
  1398. }
  1399. else
  1400. {
  1401. //else the oem table is in uncompressed format.
  1402. if (!FileToBuffer(szLocalPath, bufOut))
  1403. {
  1404. LOG_error("FileToBuffer(%s) failed", szPath);
  1405. SetLastError(ERROR_INVALID_FUNCTION); //we might not be ready yet
  1406. return false;
  1407. }
  1408. }
  1409. return true;
  1410. }
  1411. //=======================================================================
  1412. //
  1413. // called by DllMain()
  1414. //
  1415. //=======================================================================
  1416. bool UpdateCdmDll()
  1417. {
  1418. LOG_block("UpdateCDMDll");
  1419. TCHAR szCurrentDll[MAX_PATH];
  1420. GetSystemDirectory(szCurrentDll, sizeOfArray(szCurrentDll));
  1421. PathAppend(szCurrentDll, CDMDLL);
  1422. TCHAR szIUCdmDll[MAX_PATH];
  1423. GetSystemDirectory(szIUCdmDll, sizeOfArray(szCurrentDll));
  1424. PathAppend(szIUCdmDll, IUCDMDLL);
  1425. TCHAR szCdmNewDll[MAX_PATH];
  1426. GetSystemDirectory(szCdmNewDll, sizeOfArray(szCdmNewDll));
  1427. PathAppend(szCdmNewDll, CDMNEWDLL);
  1428. //To replace DLLs already loaded in memory on NT we can rename the file on
  1429. //disk to a temp name and copy the new dll over the old disk file image. The
  1430. //next time that the dll is loaded it will load the new image.
  1431. //
  1432. TCHAR szOldDll[MAX_PATH];
  1433. lstrcpy(szOldDll, szCurrentDll);
  1434. lstrcat(szOldDll, _T(".old"));
  1435. DeleteFile(szOldDll);
  1436. if (!MoveFile(szCurrentDll, szOldDll))
  1437. {
  1438. LOG_error("MoveFile(%s, %s) returns %d", szCurrentDll, szOldDll, GetLastError());
  1439. return false;
  1440. }
  1441. //
  1442. // If iucdm.dll exists, rename it to cdm.dll, else rename cdmnew.dll to cdm.dll
  1443. //
  1444. if (!MoveFile(FileExists(szIUCdmDll) ? szIUCdmDll : szCdmNewDll, szCurrentDll))
  1445. {
  1446. LOG_error("MoveFile(%s, %s) returns %d", szCdmNewDll, szCurrentDll, GetLastError());
  1447. MoveFile(szOldDll, szCurrentDll); // restore if update fails
  1448. return false;
  1449. }
  1450. return true;
  1451. }
  1452. //Called by InternalLogDriverNotFound(...)
  1453. //ASSUME: only runs in Whislter, not working on lower than W2k
  1454. //called by InternalLogDriverNotFound()
  1455. //Get SKU information in a string for running OS
  1456. //return S_FALSE if no matching information found
  1457. //return S_FALSE if buffer not big enough for possible return string
  1458. //return E_FAIL if error happens,
  1459. //return S_OK if success and the buffer will contain SKU string
  1460. //lpSKUBuffer: IN : buffer to store SKU string. Allocated and freed by caller
  1461. //dwSize: IN : size of lpSKUBuffer in bytes
  1462. HRESULT GetSKUString(
  1463. IN LPTSTR lpSKUBuffer,
  1464. IN DWORD dwSize
  1465. )
  1466. {
  1467. enumSKU eSKU;
  1468. OSVERSIONINFOEX osverEx;
  1469. LOG_block("GetSKUString");
  1470. ZeroMemory(&osverEx, sizeof(osverEx));
  1471. osverEx.dwOSVersionInfoSize = sizeof(osverEx);
  1472. if (!GetVersionEx((OSVERSIONINFO *) &osverEx))
  1473. {
  1474. LOG_error("GetVersionEx failed");
  1475. return E_FAIL;
  1476. }
  1477. eSKU = SKU_NOT_SPECIFIED;
  1478. if (VER_NT_SERVER == osverEx.wProductType)
  1479. {
  1480. if (osverEx.wSuiteMask & VER_SUITE_DATACENTER)
  1481. {
  1482. eSKU = SKU_DATACENTER_SERVER;
  1483. }
  1484. else
  1485. {
  1486. if (osverEx.wSuiteMask & VER_SUITE_ENTERPRISE)
  1487. {
  1488. eSKU = SKU_ADVANCED_SERVER;
  1489. }
  1490. else
  1491. {
  1492. eSKU = SKU_SERVER;
  1493. }
  1494. }
  1495. }
  1496. if (VER_NT_WORKSTATION == osverEx.wProductType)
  1497. {
  1498. if (osverEx.wSuiteMask & VER_SUITE_PERSONAL )
  1499. {
  1500. eSKU = SKU_PERSONAL;
  1501. }
  1502. else
  1503. {
  1504. eSKU = SKU_PROFESSIONAL;
  1505. }
  1506. }
  1507. if (dwSize < SKU_STRING_MIN_LENGTH)
  1508. {
  1509. LOG_error("buffer not big enough to store SKU information");
  1510. return S_FALSE; //buffer not big enough for possible return string
  1511. }
  1512. switch (eSKU)
  1513. {
  1514. case SKU_PERSONAL:
  1515. case SKU_PROFESSIONAL:
  1516. case SKU_SERVER:
  1517. case SKU_ADVANCED_SERVER:
  1518. case SKU_DATACENTER_SERVER:
  1519. lstrcpy(lpSKUBuffer, SKU_STRINGS[eSKU]);
  1520. break;
  1521. default: //not specified
  1522. LOG_error("Unrecognized SKU type");
  1523. lstrcpy(lpSKUBuffer, SKU_STRINGS[0]);
  1524. return S_FALSE;
  1525. }
  1526. return S_OK;
  1527. }
  1528. //called by InternalDriverNotFound(...)
  1529. //Find a file name not used so far into which hardware xml information will be inserted
  1530. //The file name will be in format hardware_xxx.xml where xxx is in range [1..MAX_INDEX_TO_SEARCH]
  1531. //The position file found last time is remembered and new search will start from the next position
  1532. //Caller is supposed to close handle and delete file
  1533. //tszDirPath IN : directory under which to look for unique file name. End with "\"
  1534. //lpBuffer IN : allocated and freed by caller. Buffer to store unique file name found
  1535. //dwSize IN : size of lpBuffer in bytes
  1536. //hFile OUT: store a handle to the opened file
  1537. //return S_OK if Unique File Name found
  1538. //return S_FALSE if buffer not big enough to hold unique file name
  1539. //return E_FAIL if all qualified file names already taken
  1540. HRESULT GetUniqueFileName(
  1541. IN LPTSTR tszDirPath,
  1542. IN LPTSTR lpBuffer,
  1543. IN DWORD dwSize,
  1544. OUT HANDLE &hFile
  1545. )
  1546. {
  1547. TCHAR tszPath[MAX_PATH];
  1548. static DWORD dwFileIndex = 1;
  1549. int nCount = 0;
  1550. const TCHAR FILENAME[] = _T("Hardware_");
  1551. const TCHAR FILEEXT[] = _T("xml");
  1552. LOG_block("GetFileNameGenerator");
  1553. LOG_out("Directory to search unique file names: %s", tszDirPath);
  1554. hFile = NULL;
  1555. do
  1556. {
  1557. _stprintf(tszPath, _T("%s%s%d.%s"), tszDirPath, FILENAME, dwFileIndex, FILEEXT);
  1558. LOG_out("check existing of %s", tszPath);
  1559. hFile = CreateFile(tszPath, NULL, NULL, NULL, CREATE_NEW, NULL, NULL);
  1560. if (INVALID_HANDLE_VALUE == hFile)
  1561. { //file exists
  1562. dwFileIndex ++;
  1563. nCount ++;
  1564. if (dwFileIndex > MAX_INDEX_TO_SEARCH)
  1565. {
  1566. dwFileIndex = 1;
  1567. }
  1568. }
  1569. else
  1570. {
  1571. break; //first available file name found
  1572. }
  1573. }while(nCount < MAX_INDEX_TO_SEARCH );
  1574. if (nCount == MAX_INDEX_TO_SEARCH )
  1575. {
  1576. LOG_out("All %d file names have been taken", nCount);
  1577. return E_FAIL;
  1578. }
  1579. _stprintf(tszPath, _T("%s%d.%s"), FILENAME, dwFileIndex, FILEEXT);
  1580. if (dwSize < (_tcslen(tszPath) + 1) * sizeof(TCHAR))
  1581. {
  1582. LOG_out("buffer not big enough to hold unique file name");
  1583. CloseHandle(hFile);
  1584. DeleteFile(tszPath);
  1585. return S_FALSE;
  1586. }
  1587. lstrcpy(lpBuffer, tszPath);
  1588. LOG_out("unique file name %s found", lpBuffer);
  1589. dwFileIndex++; //next time skip file name found this time
  1590. if (dwFileIndex > MAX_INDEX_TO_SEARCH)
  1591. {
  1592. dwFileIndex = 1;
  1593. }
  1594. return S_OK;
  1595. }
  1596. /*
  1597. Called by InternalLogDriverNotFound(...)
  1598. canonicalize a url
  1599. resize tchBuf if not big enough
  1600. lpszUrl: IN address of the string that contains the Url to canonicalize
  1601. tchBuf : OUT buffer that receives the resulting canonicalized URL
  1602. dwLen : IN size of the tchBuf
  1603. dwFlags: IN any flag applicable to InternetCanonicalizeUrl(...)
  1604. Return : S_OK if url canonicalization succeed
  1605. E_FAIL if url canonicalization failed
  1606. */
  1607. HRESULT CdmCanonicalizeUrl(
  1608. IN LPCTSTR lpszUrl,
  1609. OUT tchar_buffer &tchBuf,
  1610. IN DWORD dwLen,
  1611. IN DWORD dwFlags)
  1612. {
  1613. LOG_block("CdmCanonicalizeUrl");
  1614. BOOL fBufferResized = FALSE;
  1615. while (!InternetCanonicalizeUrl(lpszUrl, (LPTSTR) tchBuf, &dwLen, dwFlags))
  1616. {
  1617. if (fBufferResized || ERROR_INSUFFICIENT_BUFFER != GetLastError())
  1618. {
  1619. LOG_error("InternetCanonicalizeUrl Failed ");
  1620. return E_FAIL;
  1621. }
  1622. else
  1623. {
  1624. LOG_out("buffer resized");
  1625. tchBuf.resize((dwLen+1));
  1626. fBufferResized = TRUE;
  1627. }
  1628. }
  1629. return S_OK;
  1630. }
  1631. //=======================================================================
  1632. //
  1633. // called internally
  1634. //
  1635. //=======================================================================
  1636. // Check if given PNPID is current hash table mapping.
  1637. //if PnpID is in hash table then return index
  1638. ULONG IsInMap(
  1639. IN PCDM_HASHTABLE pHashTable, //hash table to be used to check and see if item is available.
  1640. IN LPCTSTR pHwID //hardware id to be retrieved
  1641. ) {
  1642. LOG_block("IsInMap");
  1643. if(NULL != pHwID && 0 != pHwID[0])
  1644. {
  1645. ULONG ulTableEntry = CDM_HwID2Hash(pHwID, pHashTable->hdr.iTableSize);
  1646. if(GETBIT(pHashTable->pData, ulTableEntry))
  1647. {
  1648. LOG_out("%s (hash %d) is found", pHwID, ulTableEntry);
  1649. return ulTableEntry;
  1650. }
  1651. else
  1652. {
  1653. LOG_error("%s (hash %d) is not found", pHwID, ulTableEntry);
  1654. }
  1655. }
  1656. else
  1657. {
  1658. LOG_error("pHwID is empty");
  1659. }
  1660. return -1;
  1661. }
  1662. //This method performs a logical AND operation between an array of bits and a bitmask bit array.
  1663. inline void AndBitmasks(
  1664. PBYTE pBitsResult, //result array for the AND operation
  1665. PBYTE pBitMask, //source array bitmask
  1666. int iMaskByteSize //bitmask size in bytes
  1667. ) {
  1668. for(int i=0; i<iMaskByteSize; i++)
  1669. pBitsResult[i] &= pBitMask[i];
  1670. }
  1671. bool GetOEMandLocalBitmask(
  1672. IN SHelper& helper,
  1673. OUT byte_buffer& bufOut
  1674. ) {
  1675. LOG_block("GetOEMandLocalBitmask");
  1676. TCHAR szPath[MAX_PATH];
  1677. wsprintf(szPath, _T("%d/bitmask.cdm"), helper.puidCatalog);
  1678. byte_buffer bufBitmask;
  1679. if (!DownloadToBuffer(helper, szPath, bufBitmask))
  1680. return false;
  1681. PBITMASK pMask = (PBITMASK)(LPBYTE)bufBitmask;
  1682. int iMaskByteSize = (pMask->iRecordSize+7)/8;
  1683. bufOut.resize(iMaskByteSize);
  1684. if (!bufOut.valid())
  1685. return false;
  1686. memset(bufOut, 0xFF, iMaskByteSize);
  1687. // Initial inventory
  1688. // AndBitmasks(bufOut, pMask->GetBitMaskPtr(BITMASK_GLOBAL_INDEX), iMaskByteSize);
  1689. //AND in OEM bitmask, we pick first hit since bitmasks are returned
  1690. //from most specific to least specific.
  1691. int nCurrentOEM = pMask->iOemCount; // out of range value
  1692. {
  1693. byte_buffer bufOEM;
  1694. if (!DownloadToBuffer(helper, _T("oeminfo.bin"), bufOEM))
  1695. return false;
  1696. DWORD dwOemId = GetMachinePnPID(bufOEM);
  1697. if (0 != dwOemId)
  1698. {
  1699. for (int nOEM = 0; nOEM < pMask->iOemCount; nOEM++)
  1700. {
  1701. if (dwOemId == pMask->bmID[nOEM])
  1702. break;
  1703. }
  1704. nCurrentOEM = nOEM;
  1705. }
  1706. }
  1707. int nBitmapIndex = (pMask->iOemCount == nCurrentOEM
  1708. ? BITMASK_OEM_DEFAULT // if we did not find an OEM bitmask specific to this client then use the default OEM mask.
  1709. : nCurrentOEM+2 // bitmask is offset from GLOBAL and DEFAULT bitmasks
  1710. );
  1711. AndBitmasks(bufOut, pMask->GetBitMaskPtr(nBitmapIndex), iMaskByteSize);
  1712. //And in LOCALE bitmask
  1713. for(int iLocal = 0; iLocal < pMask->iLocaleCount; iLocal++)
  1714. {
  1715. if (pMask->bmID[pMask->iOemCount+iLocal] == helper.dwLangID)
  1716. {
  1717. //We need to add in the oem count to get to the first local
  1718. AndBitmasks(bufOut, pMask->GetBitMaskPtr(pMask->iOemCount+iLocal+2), iMaskByteSize);
  1719. return true;
  1720. }
  1721. }
  1722. LOG_error("language %08X is not found", helper.dwLangID);
  1723. return false; //locale is not found
  1724. }
  1725. /////////////////////////////////////////////////////////////////////////////////
  1726. // Variable field functions
  1727. /////////////////////////////////////////////////////////////////////////////////
  1728. //The GetNext function returns a pointer to the next variable array item in a
  1729. //variable chain. If the next variable item does not exit then this method
  1730. //return NULL.
  1731. PWU_VARIABLE_FIELD WU_VARIABLE_FIELD::GetNext(
  1732. void
  1733. ) {
  1734. PWU_VARIABLE_FIELD pv;
  1735. //walk though the varaible field array associated with this data item
  1736. //and return the requested item or NULL if the item is not found.
  1737. pv = this;
  1738. if (pv->id == WU_VARIABLE_END)
  1739. return NULL;
  1740. pv = (PWU_VARIABLE_FIELD)((PBYTE)pv + pv->len);
  1741. return pv;
  1742. }
  1743. //find a variable item in a variable item chain.
  1744. PWU_VARIABLE_FIELD WU_VARIABLE_FIELD::Find(
  1745. short id //id of variable size field to search for in the variable size chain.
  1746. ) {
  1747. LOG_block("WU_VARIABLE_FIELD::Find");
  1748. PWU_VARIABLE_FIELD pv;
  1749. //walk though the varaible field array associated with this data item
  1750. //and return the requested item or NULL if the item is not found.
  1751. pv = this;
  1752. //If this variable record only contains an end record then we
  1753. //need to handle it specially since the normal find loop
  1754. //updates the pv pointer before the end check is made so if
  1755. //end is the first field it can be missed.
  1756. if (pv->id == WU_VARIABLE_END)
  1757. return (id == WU_VARIABLE_END) ? pv : (PWU_VARIABLE_FIELD)NULL;
  1758. do
  1759. {
  1760. if (pv->id == id)
  1761. return pv;
  1762. pv = (PWU_VARIABLE_FIELD)((PBYTE)pv + pv->len);
  1763. } while(pv->id != WU_VARIABLE_END);
  1764. //case where caller asked to search for the WU_VARIABLE_END field
  1765. if (pv->id == id)
  1766. return pv;
  1767. return (PWU_VARIABLE_FIELD)NULL;
  1768. }
  1769. //Variable size field constructor.
  1770. WU_VARIABLE_FIELD::WU_VARIABLE_FIELD(
  1771. void
  1772. ) {
  1773. id = WU_VARIABLE_END;
  1774. len = sizeof(id) + sizeof(len);
  1775. }
  1776. //returns the total size of a variable field
  1777. int WU_VARIABLE_FIELD::GetSize(
  1778. void
  1779. ) {
  1780. PWU_VARIABLE_FIELD pv;
  1781. int iSize;
  1782. iSize = 0;
  1783. pv = this;
  1784. while(pv->id != WU_VARIABLE_END)
  1785. {
  1786. iSize += pv->len;
  1787. pv = (PWU_VARIABLE_FIELD)((PBYTE)pv + pv->len);
  1788. }
  1789. iSize += pv->len;
  1790. return iSize;
  1791. }
  1792. static bool FilesIdentical(
  1793. IN LPCTSTR szFileName1,
  1794. IN LPCTSTR szFileName2
  1795. ) {
  1796. auto_hfile hFile1 = CreateFile(szFileName1, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1797. if (!hFile1.valid())
  1798. return false;
  1799. auto_hfile hFile2 = CreateFile(szFileName2, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1800. if (!hFile2.valid())
  1801. return false;
  1802. if(GetFileSize(hFile1, NULL) != GetFileSize(hFile2, NULL))
  1803. return false;
  1804. FILETIME ft1;
  1805. if (!GetFileTime(hFile1, NULL, NULL, &ft1))
  1806. return false;
  1807. FILETIME ft2;
  1808. if (!GetFileTime(hFile2, NULL, NULL, &ft2))
  1809. return false;
  1810. return CompareFileTime(&ft1, &ft2) == 0;
  1811. }