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.

1154 lines
32 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: cdm.cpp
  6. //
  7. // Owner: YanL
  8. //
  9. // Description:
  10. //
  11. // Functions exported by CDM
  12. //
  13. // DownloadIsInternetAvailable
  14. // OpenCDMContext
  15. // OpenCDMContextEx
  16. // QueryDetectionFiles
  17. // FindMatchingDriver
  18. // DownloadUpdatedFiles
  19. // DetFilesDownloaded
  20. // LogDriverNotFound
  21. // CloseCDMContext
  22. // GetPackage
  23. // InternalQueryDetectionFiles
  24. // InternalFindMatchingDriver
  25. // InternalDetFilesDownloaded
  26. // InternalLogDriverNotFound
  27. //
  28. //=======================================================================
  29. #include <windows.h>
  30. #include <osdet.h>
  31. #include <setupapi.h>
  32. #include <shlwapi.h>
  33. #include <tchar.h>
  34. #include <wustl.h>
  35. #include <log.h>
  36. #include <wuv3cdm.h>
  37. #include <bucket.h>
  38. #include <newtrust.h>
  39. #include <download.h>
  40. #include <diamond.h>
  41. #include <atlconv.h>
  42. #define _ASSERTE(expr) ((void)0)
  43. #include <atlconv.cpp>
  44. #include "cdm.h"
  45. #include "cdmp.h"
  46. #include <drvinfo.h>
  47. #include <cfgmgr32.h>
  48. #include <shellapi.h>
  49. typedef struct _CONTEXTHANDLE
  50. {
  51. bool fCloseConnection; //Tracks if the connection to the internet was opened by CDM.DLL
  52. bool fNeedUpdate; //TRUE if we need to update CDM.DLL when its connection is closed.
  53. TCHAR szSiteServer[MAX_PATH]; //Description server name.
  54. TCHAR szDownloadServer[MAX_PATH]; //Download server name.
  55. } CONTEXTHANDLE, *PCONTEXTHANDLE;
  56. static frozen_array<CONTEXTHANDLE> g_handleArray;
  57. static HMODULE g_hModule;
  58. static bool g_fNeedUpdate; //Flag that indicates that cdm.dll needs updating.
  59. static int GetHandleIndex(IN HANDLE hConnection);
  60. BOOL APIENTRY DllMain(
  61. HANDLE hModule,
  62. DWORD ul_reason_for_call,
  63. LPVOID /*lpReserved*/
  64. ) {
  65. switch (ul_reason_for_call)
  66. {
  67. case DLL_PROCESS_ATTACH:
  68. g_fNeedUpdate = FALSE;
  69. g_hModule = (HMODULE)hModule; // to return to findoem;
  70. break;
  71. case DLL_THREAD_ATTACH:
  72. case DLL_THREAD_DETACH:
  73. break;
  74. case DLL_PROCESS_DETACH:
  75. //If we have downloaded a new dll then we need to update it.
  76. //Note: passing a global to a function is bad form as it can
  77. //cause problems. The only reason that I'm doing this is so
  78. //that the UpdateCDMDll API can be moved to other programs
  79. //since this ability to make a dll or exe self updating is
  80. //very usefull.
  81. if (g_fNeedUpdate)
  82. g_fNeedUpdate = !UpdateCdmDll();
  83. break;
  84. }
  85. return TRUE;
  86. }
  87. //This function determines if this client can connect to the internet.
  88. BOOL DownloadIsInternetAvailable(
  89. void
  90. ) {
  91. LOG_block("DownloadIsInternetAvailable");
  92. int iDun = GetDUNConnections();
  93. bool bWizard = IsInternetConnectionWizardCompleted();
  94. bool bConnect = IsInternetConnected();
  95. if (!bConnect && iDun <= 0)
  96. {
  97. LOG_error("if (!!bConnect && iDun <= 0) return false");
  98. return false;
  99. }
  100. if (!bWizard)
  101. {
  102. LOG_error("if (!bWizard) return false");
  103. return false;
  104. }
  105. LOG_out("return true");
  106. return true;
  107. }
  108. //This function Opens an internet connection for download. This connection
  109. //context information is tracked though the returned handle.
  110. //This functon returns a handle a CDM file download context if successful or
  111. //NULL if not. If this function fails GetLastError() can be used to return
  112. //the error code indicating the reason for failure.
  113. HANDLE WINAPI OpenCDMContext(
  114. IN HWND /*hwnd*/ //Window handle to use for any UI that needs to be presented.
  115. ) {
  116. LOG_block("OpenCDMContext");
  117. return OpenCDMContextEx(TRUE);
  118. }
  119. HANDLE WINAPI OpenCDMContextEx(
  120. IN BOOL fConnectIfNotConnected
  121. ) {
  122. LOG_block("OpenCDMContextEx");
  123. //Initialize context handle array entry and mark it as is use.
  124. CONTEXTHANDLE cth;
  125. ZeroMemory(&cth, sizeof(cth));
  126. bool fConnected = IsInternetConnected();
  127. #ifdef _WUV3TEST
  128. if (fConnected)
  129. {
  130. // catalog spoofing
  131. DWORD dwIsInternetConnected = 1;
  132. DWORD dwSize = sizeof(dwIsInternetConnected);
  133. auto_hkey hkey;
  134. if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUV3TEST, 0, KEY_READ, &hkey)) {
  135. RegQueryValueEx(hkey, _T("IsInternetConnected"), 0, 0, (LPBYTE)&dwIsInternetConnected, &dwSize);
  136. }
  137. // only then do normal
  138. if (0 == dwIsInternetConnected)
  139. {
  140. fConnected = false;
  141. }
  142. }
  143. #endif
  144. if (fConnectIfNotConnected || fConnected)
  145. {
  146. //Assume that we do not need to connect to the internet
  147. cth.fCloseConnection = !IsInternetConnected();
  148. //If we are not already connected to the internet and
  149. //we fail in the attempt then we cannot download any
  150. //drivers so quit.
  151. if (InternetAttemptConnect(0) != NO_ERROR)
  152. {
  153. LOG_error("No internet connection");
  154. return 0;
  155. }
  156. TCHAR szSecurityServer[MAX_PATH] = {0};
  157. lstrcpy(szSecurityServer, SZ_SECURITY_SERVER);
  158. /* Test redirect*/{
  159. auto_hkey hkey;
  160. if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate"), 0, KEY_READ, &hkey)) {
  161. DWORD dwSize = sizeof(szSecurityServer);
  162. RegQueryValueEx(hkey, _T("SecurityServer"), 0, 0, (LPBYTE)&szSecurityServer, &dwSize);
  163. }
  164. }
  165. //Connect to and get server context.
  166. CDownload download;
  167. if (download.Connect(szSecurityServer))
  168. {
  169. LOG_out("Connected to SecurityServer '%s'", szSecurityServer);
  170. }
  171. else
  172. {
  173. LOG_error("No connection to SecurityServer '%s'", szSecurityServer);
  174. return 0;
  175. }
  176. //Init download
  177. CDiamond diamond;
  178. if (!diamond.valid()) {
  179. SetLastError(ERROR_GEN_FAILURE);
  180. LOG_error("cannot init diamond");
  181. return 0;
  182. }
  183. // do security url verification and get server locations
  184. if (!ProcessIdent(download, diamond, szSecurityServer, cth.szSiteServer, cth.szDownloadServer))
  185. {
  186. SetLastError(ERROR_ACCESS_DENIED);
  187. LOG_error("invalid identcdm.cab");
  188. return 0;
  189. }
  190. // reconnect fo Site server if we need to
  191. if (0 != lstrcmpi(cth.szSiteServer, szSecurityServer))
  192. {
  193. if (download.Connect(cth.szSiteServer))
  194. {
  195. LOG_out("Connected to SiteServer '%s'", cth.szSiteServer);
  196. }
  197. else
  198. {
  199. LOG_error("No connection to SiteServer '%s'", cth.szSiteServer);
  200. return 0;
  201. }
  202. }
  203. else
  204. {
  205. LOG_out("SiteServer is %s", szSecurityServer);
  206. }
  207. if (!DownloadCdmCab(download, diamond, cth.fNeedUpdate))
  208. {
  209. LOG_error("Failed to download cdm.cab");
  210. return 0;
  211. }
  212. }
  213. return LongToHandle(g_handleArray.add(cth) + 1);
  214. }
  215. //This function downloads the specified CDM package. The hConnection handle must have
  216. //been returned from the OpenCDMContext() API.
  217. //
  218. //This function Returns TRUE if download is successful GetLastError() will return
  219. //the error code indicating the reason that the call failed.
  220. BOOL WINAPI DownloadUpdatedFiles(
  221. IN HANDLE hConnection, //Connection handle from OpenCDMContext() API.
  222. IN HWND hwnd, //Window handle for call context
  223. IN PDOWNLOADINFO pDownloadInfo, //download information structure describing
  224. //package to be read from server
  225. OUT LPWSTR lpDownloadPath, //local computer directory location of the
  226. //downloaded files
  227. IN UINT uSize, //size of the download path buffer. If this
  228. //buffer is to small to contain the complete
  229. //path and file name no file will be downloaded.
  230. //The PUINT puReguiredSize parameter can be checked
  231. //to determine the size of buffer necessary to
  232. //perform the download.
  233. OUT PUINT puRequiredSize //required lpDownloadPath buffer size. This
  234. //parameter is filled in with the minimum size
  235. //that is required to place the complete path
  236. //file name of the downloaded file. If this
  237. //parameter is NULL no size is returned.
  238. ) {
  239. LOG_block("DownloadUpdatedFiles");
  240. int index = GetHandleIndex(hConnection);
  241. if (-1 == index)
  242. {
  243. LOG_error("invalid handle");
  244. SetLastError(ERROR_INVALID_HANDLE);
  245. return FALSE;
  246. }
  247. if (NULL == puRequiredSize)
  248. {
  249. LOG_error("puRequiredSize == NULL");
  250. SetLastError(ERROR_INVALID_PARAMETER);
  251. return FALSE;
  252. }
  253. //Check and see if the download path is large enough to contain the return
  254. //directory where we will put the download cab files.
  255. TCHAR szTmpPath[MAX_PATH];
  256. int iLengthNeeded = GetDownloadPath(szTmpPath);
  257. if (lpDownloadPath == NULL || iLengthNeeded > (int)uSize)
  258. {
  259. LOG_error("uSize < then needed");
  260. *puRequiredSize = iLengthNeeded;
  261. SetLastError(ERROR_BUFFER_OVERFLOW);
  262. return FALSE;
  263. }
  264. // Declared locally
  265. typedef long (*PFN_GETPACKAGE)(PCONTEXTHANDLE pContextHandle, PDOWNLOADINFO pDownloadInfo, LPTSTR lpDownloadPath);
  266. PFN_GETPACKAGE pfnGetPackage = NULL;//Entry point in cdm.dll that actually performs the download
  267. // If there is cdmnew.dll in system directory use it
  268. auto_hlib hlib = LoadCdmnewDll();
  269. if (hlib.valid())
  270. {
  271. pfnGetPackage = (PFN_GETPACKAGE)GetProcAddress(hlib,"GetPackage");
  272. if (NULL == pfnGetPackage)
  273. {
  274. //if we cannot find our download function we need to return fail and not attempt
  275. //to download the update package.
  276. LOG_error("cannot find function 'GetPackage'");
  277. return FALSE;
  278. }
  279. LOG_out("Calling GetPackage() from cdmnew.dll");
  280. }
  281. else
  282. {
  283. // Declared locally
  284. long GetPackage(IN PCONTEXTHANDLE pContextHandle, IN PDOWNLOADINFO pDownloadInfo, OUT LPTSTR lpDownloadPath);
  285. pfnGetPackage = GetPackage;
  286. LOG_out("Calling internal GetPackage()");
  287. }
  288. int iError = (pfnGetPackage)(&g_handleArray[index], pDownloadInfo, szTmpPath);
  289. if (iError != NO_ERROR)
  290. {
  291. SetLastError(iError);
  292. return FALSE;
  293. }
  294. *puRequiredSize = iLengthNeeded;
  295. lstrcpyW(lpDownloadPath, T2W(szTmpPath));
  296. return TRUE;
  297. }
  298. //This API closes the internet connection opened with the OpenCDMContext() API.
  299. //If CDM did not open the internet connection this API simply returns. The CDM
  300. //context handle must have been the same handle that was returned from
  301. //the OpenCDMContext() API.
  302. //
  303. //This call cannot fail. If the pConnection handle is invalid this function
  304. //simply ignores it.
  305. VOID WINAPI CloseCDMContext (
  306. IN HANDLE hConnection //CDM Connection handle returned with OpenCDMContext.
  307. ) {
  308. LOG_block("CloseCDMContext");
  309. int index = GetHandleIndex(hConnection);
  310. if ( -1 == index)
  311. {
  312. LOG_error("invalid handle");
  313. return;
  314. }
  315. //If CDM.DLL opened this internet connection and if this connection is
  316. //for a modem then we need to close the internet connection. Note:
  317. //the Open context function only sets fCloseConnection for modem
  318. //connections.
  319. if (g_handleArray[index].fCloseConnection)
  320. InternetAutodialHangup(0);
  321. if (g_handleArray[index].fNeedUpdate)
  322. {
  323. //if any dll needs to be updated then
  324. //we set the global update flag. This will
  325. //force cdm.dll to be replaced when the last
  326. //process detaches.
  327. g_fNeedUpdate = true;
  328. }
  329. g_handleArray.remove(index);
  330. }
  331. int WINAPI QueryDetectionFiles(
  332. IN HANDLE hConnection,
  333. IN void* pCallbackParam,
  334. IN PFN_QueryDetectionFilesCallback pCallback
  335. ) {
  336. LOG_block("QueryDetectionFiles");
  337. int index = GetHandleIndex(hConnection);
  338. if (-1 == index)
  339. {
  340. LOG_error("invalid handle");
  341. SetLastError(ERROR_INVALID_HANDLE);
  342. return FALSE;
  343. }
  344. // Call external/internal implementetion
  345. typedef int (*PFN_InternalQueryDetectionFiles)(IN PCONTEXTHANDLE pContextHandle, IN void* pCallbackParam, IN PFN_QueryDetectionFilesCallback pCallback);
  346. PFN_InternalQueryDetectionFiles pfnInternalQueryDetectionFiles = NULL;
  347. auto_hlib hlib = LoadCdmnewDll();
  348. if (hlib.valid())
  349. {
  350. pfnInternalQueryDetectionFiles = (PFN_InternalQueryDetectionFiles)GetProcAddress(hlib, "InternalQueryDetectionFiles");
  351. if (NULL == pfnInternalQueryDetectionFiles)
  352. {
  353. LOG_error("cannot find function 'InternalQueryDetectionFiles'");
  354. return FALSE;
  355. }
  356. LOG_out("Calling InternalQueryDetectionFiles() from cdmnew.dll");
  357. }
  358. else
  359. {
  360. // Declared locally
  361. int InternalQueryDetectionFiles(IN PCONTEXTHANDLE pContextHandle, IN void* pCallbackParam, IN PFN_QueryDetectionFilesCallback pCallback);
  362. pfnInternalQueryDetectionFiles = InternalQueryDetectionFiles;
  363. LOG_out("Calling internal InternalQueryDetectionFiles()");
  364. }
  365. return (pfnInternalQueryDetectionFiles)(&g_handleArray[index], pCallbackParam, pCallback);
  366. }
  367. void WINAPI DetFilesDownloaded(
  368. IN HANDLE hConnection
  369. ) {
  370. LOG_block("DetFilesDownloaded");
  371. int index = GetHandleIndex(hConnection);
  372. if (-1 == index)
  373. {
  374. LOG_error("invalid handle");
  375. return;
  376. }
  377. // Call external/internal implementetion
  378. typedef void (*PFN_InternalDetFilesDownloaded)(IN PCONTEXTHANDLE pContextHandle);
  379. PFN_InternalDetFilesDownloaded pfnInternalDetFilesDownloaded = NULL;
  380. auto_hlib hlib = LoadCdmnewDll();
  381. if (hlib.valid())
  382. {
  383. pfnInternalDetFilesDownloaded = (PFN_InternalDetFilesDownloaded)GetProcAddress(hlib, "InternalDetFilesDownloaded");
  384. if (NULL == pfnInternalDetFilesDownloaded)
  385. {
  386. LOG_error("cannot find function 'InternalDetFilesDownloaded'");
  387. return;
  388. }
  389. LOG_out("Calling InternalDetFilesDownloaded() from cdmnew.dll");
  390. }
  391. else
  392. {
  393. // Declared locally
  394. void InternalDetFilesDownloaded(IN PCONTEXTHANDLE pContextHandle);
  395. pfnInternalDetFilesDownloaded = InternalDetFilesDownloaded;
  396. LOG_out("Calling internal InternalDetFilesDownloaded()");
  397. }
  398. (pfnInternalDetFilesDownloaded)(&g_handleArray[index]);
  399. }
  400. // supports offline logging
  401. // hConnection NOT used at all
  402. // no network connection or osdet.dll needed for languauge, SKU, platform detection
  403. void WINAPI LogDriverNotFound(
  404. IN HANDLE hConnection,
  405. IN LPCWSTR lpDeviceInstanceID,
  406. IN DWORD dwFlags
  407. ) {
  408. LOG_block("LogDriverNotFound");
  409. // Call external/internal implementetion
  410. typedef void (*PFN_InternalLogDriverNotFound)(IN PCONTEXTHANDLE pContextHandle, IN LPCWSTR lpDeviceInstanceID, IN DWORD dwFlags);
  411. PFN_InternalLogDriverNotFound pfnInternalLogDriverNotFound = NULL;
  412. CONTEXTHANDLE cth;
  413. ZeroMemory(&cth, sizeof(cth));
  414. auto_hlib hlib = LoadCdmnewDll();
  415. if (hlib.valid())
  416. {
  417. pfnInternalLogDriverNotFound = (PFN_InternalLogDriverNotFound)GetProcAddress(hlib, "InternalLogDriverNotFound");
  418. if (NULL == pfnInternalLogDriverNotFound)
  419. {
  420. LOG_error("cannot find function 'InternalLogDriverNotFound'");
  421. return;
  422. }
  423. LOG_out("Calling InternalLogDriverNotFound() from cdmnew.dll");
  424. }
  425. else
  426. {
  427. // Declared locally
  428. void InternalLogDriverNotFound(IN PCONTEXTHANDLE pContextHandle, IN LPCWSTR lpDeviceInstanceID, IN DWORD dwFlags);
  429. pfnInternalLogDriverNotFound = InternalLogDriverNotFound;
  430. LOG_out("Calling internal InternalLogDriverNotFound()");
  431. }
  432. // pass in dummy contexthandle
  433. (pfnInternalLogDriverNotFound)(&cth, lpDeviceInstanceID, dwFlags);
  434. }
  435. BOOL WINAPI FindMatchingDriver(
  436. IN HANDLE hConnection,
  437. IN PDOWNLOADINFO pDownloadInfo,
  438. OUT PWUDRIVERINFO pWuDriverInfo
  439. ) {
  440. LOG_block("FindMatchingDriver");
  441. int index = GetHandleIndex(hConnection);
  442. if (-1 == index)
  443. {
  444. LOG_error("invalid handle");
  445. SetLastError(ERROR_INVALID_HANDLE);
  446. return FALSE;
  447. }
  448. // Call external/internal implementetion
  449. typedef BOOL (*PFN_InternalFindMatchingDriver)(IN PCONTEXTHANDLE pContextHandle, IN PDOWNLOADINFO pDownloadInfo, OUT PWUDRIVERINFO pWuDriverInfo);
  450. PFN_InternalFindMatchingDriver pfnInternalFindMatchingDriver = NULL;
  451. auto_hlib hlib = LoadCdmnewDll();
  452. if (hlib.valid())
  453. {
  454. pfnInternalFindMatchingDriver = (PFN_InternalFindMatchingDriver)GetProcAddress(hlib,"InternalFindMatchingDriver");
  455. if (NULL == pfnInternalFindMatchingDriver)
  456. {
  457. LOG_error("cannot find function 'InternalFindMatchingDriver'");
  458. return FALSE;
  459. }
  460. LOG_out("Calling InternalFindMatchingDriver() from cdmnew.dll");
  461. }
  462. else
  463. {
  464. // Declared locally
  465. BOOL InternalFindMatchingDriver(IN PCONTEXTHANDLE pContextHandle, IN PDOWNLOADINFO pDownloadInfo, OUT PWUDRIVERINFO pWuDriverInfo);
  466. pfnInternalFindMatchingDriver = InternalFindMatchingDriver;
  467. LOG_out("Calling internal InternalFindMatchingDriver()");
  468. }
  469. return (pfnInternalFindMatchingDriver)(&g_handleArray[index], pDownloadInfo, pWuDriverInfo);
  470. }
  471. //This function is called to download the actual package. What happens is that the
  472. //cdm.dll is copied from the server. This dll is then dynamically loaded by the
  473. //DownloadGetUpdatedFiles() API and called. This allows the most recent cdm.dll
  474. //to be used even if the client has an out dated version on their system.
  475. //
  476. //If this function is successfull then it returns NO_ERROR. If the case of a
  477. //failure this function returns an error code.
  478. long GetPackage(
  479. IN PCONTEXTHANDLE pContextHandle, //Pointer Context handle structure that contains the server and dll information needed to perform the download.
  480. IN PDOWNLOADINFO pDownloadInfo, //download information structure describing package to be read from server
  481. OUT LPTSTR lpDownloadPath //Poitner to local directory on the client computer system where the downloaded files are to be stored.
  482. ) {
  483. LOG_block("GetPackage");
  484. USES_CONVERSION;
  485. SHelper helper;
  486. //
  487. // NTRAID#NTBUG9-185297-2000/11/21-waltw Fixed: bufBucket must have same scope as SHelper
  488. //
  489. byte_buffer bufBucket;
  490. DWORD dwError = PrepareCatalog(pContextHandle->szSiteServer, helper);
  491. if (NO_ERROR != dwError)
  492. {
  493. SetLastError(dwError);
  494. return FALSE;
  495. }
  496. //Clear out any files that might be in the temp download directory.
  497. if (!DeleteNode(lpDownloadPath))
  498. {
  499. LOG_out("DeleteNode(%s) failed last error %d", lpDownloadPath, GetLastError());
  500. }
  501. if (!CreateDirectory(lpDownloadPath, NULL))
  502. {
  503. LOG_out("CreateDirectory(%s) failed last error %d", lpDownloadPath, GetLastError());
  504. }
  505. bool fPlist = (
  506. NULL != pDownloadInfo->lpHardwareIDs &&
  507. 0 == lstrcmpiW(L"3FBF5B30-DEB4-11D1-AC97-00A0C903492B", pDownloadInfo->lpHardwareIDs)
  508. );
  509. // Get to and from information
  510. TCHAR szCabLocalFile[MAX_PATH];
  511. GetWindowsUpdateDirectory(szCabLocalFile);
  512. if (fPlist) {
  513. TCHAR szCabServerFile[MAX_PATH];
  514. wsprintf(szCabServerFile, _T("%d_%#08x.plist"), helper.enPlatform, helper.dwLangID);
  515. LOG_out("getting PLIST %s", szCabServerFile);
  516. PathAppend(szCabLocalFile, szCabServerFile);
  517. // Now we can say that we are ready
  518. if (!helper.download.Copy(szCabServerFile, szCabLocalFile))
  519. {
  520. LOG_error("%s failed to download", szCabServerFile);
  521. return ERROR_FILE_NOT_FOUND;
  522. }
  523. }
  524. else
  525. {
  526. TCHAR szCabFileTitle[MAX_PATH];
  527. if (!FindUpdate(pDownloadInfo, helper, bufBucket))
  528. {
  529. LOG_error("no update has been found");
  530. return ERROR_FILE_NOT_FOUND;
  531. }
  532. LOG_out("PUID %d is found", helper.puid);
  533. CDownload downloadCabpool;
  534. if (downloadCabpool.Connect(pContextHandle->szDownloadServer))
  535. {
  536. LOG_out("Connected to DownloadServer '%s'", pContextHandle->szDownloadServer);
  537. }
  538. else
  539. {
  540. LOG_error("No connection to DownloadServer '%s'", pContextHandle->szDownloadServer);
  541. return ERROR_GEN_FAILURE;
  542. }
  543. TCHAR szCabServerFile[MAX_PATH];
  544. lstrcpy(szCabServerFile, _T("CabPool/"));
  545. lstrcat(szCabServerFile, A2T(helper.DriverMatchInfo.pszCabFileTitle));
  546. PathAppend(szCabLocalFile, A2T(helper.DriverMatchInfo.pszCabFileTitle));
  547. // Now we can say that we are ready
  548. if (!downloadCabpool.Copy(szCabServerFile, szCabLocalFile))
  549. {
  550. LOG_error("%s failed to download", szCabServerFile);
  551. URLPingReport(helper, URLPING_FAILED);
  552. return ERROR_FILE_NOT_FOUND;
  553. }
  554. // Verify if it's not webntprn.cab
  555. HRESULT hr = VerifyFile(szCabLocalFile, FALSE);
  556. if (FAILED(hr))
  557. {
  558. LOG_error("signature verification failed");
  559. DeleteFile(szCabLocalFile);
  560. URLPingReport(helper, URLPING_FAILED);
  561. return hr;
  562. }
  563. }
  564. TCHAR szDownloadFiles[MAX_PATH];
  565. lstrcpy(szDownloadFiles, lpDownloadPath);
  566. PathAppend(szDownloadFiles, _T("*"));
  567. if (!helper.diamond.Decompress(szCabLocalFile, szDownloadFiles))
  568. {
  569. LOG_error("Decompress failed");
  570. if (!fPlist)
  571. URLPingReport(helper, URLPING_FAILED);
  572. return ERROR_FILE_NOT_FOUND;
  573. }
  574. LOG_out("Download to %s completed OK", lpDownloadPath);
  575. DeleteFile(szCabLocalFile);
  576. if (!fPlist)
  577. URLPingReport(helper, URLPING_SUCCESS);
  578. return S_OK;
  579. }
  580. static void UrlAppend(LPTSTR pszURL, LPCTSTR pszPath)
  581. {
  582. if ('/' != pszURL[lstrlen(pszURL) - 1])
  583. lstrcat(pszURL, _T("/"));
  584. lstrcat(pszURL, pszPath);
  585. }
  586. inline bool IsNewer(
  587. IN LPCTSTR szFileName1,
  588. IN LPCTSTR szFileName2
  589. ) {
  590. LOG_block("IsNewer");
  591. auto_hfile hFile1 = CreateFile(szFileName1, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  592. if (!hFile1.valid())
  593. {
  594. LOG_error("CreateFile(%s, ...) failed, error %d", szFileName1, GetLastError());
  595. return true;
  596. }
  597. auto_hfile hFile2 = CreateFile(szFileName2, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  598. if (!hFile2.valid())
  599. {
  600. LOG_error("CreateFile(%s, ...) failed, error %d", szFileName2, GetLastError());
  601. return false;
  602. }
  603. FILETIME ft1;
  604. if (!GetFileTime(hFile1, NULL, NULL, &ft1))
  605. {
  606. LOG_error("GetFileTime(%s, ...) failed, error %d", szFileName1, GetLastError());
  607. return true;
  608. }
  609. FILETIME ft2;
  610. if (!GetFileTime(hFile2, NULL, NULL, &ft2))
  611. {
  612. LOG_error("GetFileTime(%s, ...) failed, error %d", szFileName2, GetLastError());
  613. return false;
  614. }
  615. return CompareFileTime(&ft1, &ft2) < 0;
  616. }
  617. void DoCallback(
  618. IN void* pCallbackParam, IN PFN_QueryDetectionFilesCallback pCallback,
  619. SHelper& helper, LPCTSTR pszSiteServer, LPCTSTR pszFileTitle, bool fInCatalog = true
  620. ) {
  621. USES_CONVERSION;
  622. TCHAR szCatalog[32];
  623. wsprintf(szCatalog, _T("%d"), helper.puidCatalog);
  624. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  625. lstrcpy(szURL, pszSiteServer);
  626. if (fInCatalog)
  627. UrlAppend(szURL, szCatalog);
  628. UrlAppend(szURL, pszFileTitle);
  629. TCHAR szLocalFile[MAX_PATH];
  630. GetWindowsUpdateDirectory(szLocalFile);
  631. PathAppend(szLocalFile, pszFileTitle);
  632. pCallback(pCallbackParam, T2W(szURL), T2W(szLocalFile));
  633. }
  634. int InternalQueryDetectionFiles(IN PCONTEXTHANDLE pContextHandle, IN void* pCallbackParam, IN PFN_QueryDetectionFilesCallback pCallback)
  635. {
  636. LOG_block("InternalQueryDetectionFiles");
  637. SHelper helper;
  638. DWORD dwError = PrepareCatalog(pContextHandle->szSiteServer, helper);
  639. if (NO_ERROR != dwError)
  640. {
  641. SetLastError(dwError);
  642. return -1;
  643. }
  644. #if 0
  645. // Get CDM inventory
  646. TCHAR szPath[MAX_PATH];
  647. wsprintf(szPath, _T("%d/%d.cab"), helper.puidCatalog, helper.puidCatalog);
  648. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  649. lstrcpy(szURL, pContextHandle->szSiteServer);
  650. UrlAppend(szURL, szPath);
  651. GetWindowsUpdateDirectory(szPath);
  652. PathAppend(szPath, _T("buckets.cab"));
  653. pCallback(pCallbackParam, T2W(szURL), T2W(szPath));
  654. return 1;
  655. #else
  656. // Get CDM inventory
  657. TCHAR szPath[MAX_PATH];
  658. wsprintf(szPath, _T("%d/inventory.cdm"), helper.puidCatalog);
  659. byte_buffer bufInventory;
  660. if (!DownloadToBuffer(helper, szPath, bufInventory))
  661. {
  662. LOG_error("Dowload inventory failed");
  663. return -1;
  664. }
  665. //Here we need a trick to determine if we need to do anything: we do if inventory.cdm is a newer then inventory.cdm.last
  666. GetWindowsUpdateDirectory(szPath);
  667. PathAppend(szPath, _T("inventory.cdm"));
  668. TCHAR szPathLast[MAX_PATH];
  669. lstrcpy(szPathLast, szPath);
  670. lstrcat(szPathLast, _T(".last"));
  671. if (!IsNewer(szPathLast, szPath))
  672. {
  673. LOG_out("inventory.cdm is up to date");
  674. return 0;
  675. }
  676. CopyFile(szPath, szPathLast, FALSE);
  677. PCDM_HASHTABLE pHashTable = (PCDM_HASHTABLE)(LPBYTE)bufInventory;
  678. int nCount = 0;
  679. DoCallback(pCallbackParam, pCallback, helper, pContextHandle->szSiteServer, _T("oeminfo.bin"), false);
  680. nCount ++;
  681. DoCallback(pCallbackParam, pCallback, helper, pContextHandle->szSiteServer, _T("bitmask.cdm"));
  682. nCount ++;
  683. for (ULONG ulHashIndex = 0; ulHashIndex < pHashTable->hdr.iTableSize; ulHashIndex ++)
  684. {
  685. if(GETBIT(pHashTable->pData, ulHashIndex))
  686. {
  687. TCHAR szTitle[16];
  688. wsprintf(szTitle, _T("%d.bkf"), ulHashIndex);
  689. DoCallback(pCallbackParam, pCallback, helper, pContextHandle->szSiteServer, szTitle);
  690. nCount ++;
  691. }
  692. }
  693. return nCount;
  694. #endif
  695. }
  696. void InternalDetFilesDownloaded(IN PCONTEXTHANDLE pContextHandle)
  697. {
  698. LOG_block("InternalDetFilesDownloaded");
  699. #if 0
  700. TCHAR szPath[MAX_PATH];
  701. GetWindowsUpdateDirectory(szPath);
  702. PathAppend(szPath, _T("buckets.cab"));
  703. CDiamond diamond;
  704. diamond.Decompress(szPath, _T("*"));
  705. #endif
  706. }
  707. // pContextHandle not used.
  708. // dwFlags could be either 0 or BEGINLOGFLAG
  709. void InternalLogDriverNotFound(IN PCONTEXTHANDLE pContextHandle, IN LPCWSTR lpDeviceInstanceID, IN DWORD dwFlags)
  710. {
  711. LOG_block("InternalLogDriverNotFound");
  712. LOG_out("DeviceInstanceID is %s", lpDeviceInstanceID);
  713. using std::vector;
  714. DWORD bytes;
  715. //auto_pointer<IDrvInfo> pDrvInfo;
  716. tchar_buffer bufText;
  717. TCHAR tszFilename[MAX_PATH];
  718. TCHAR tszUniqueFilename[MAX_PATH];
  719. TCHAR tszBuffer[32];
  720. DEVINST devinst;
  721. HRESULT hr = E_FAIL;
  722. bool fXmlFileError = false;
  723. static vector<WCHAR*> vDIDList; //device instance id list
  724. LPWSTR pDID = NULL; //Device Instance ID
  725. FILE * fOut = NULL; //for XML file
  726. SHelper helper;
  727. HANDLE hFile = NULL;
  728. lstrcpy(tszFilename, _T("")); //initialize tszFilename
  729. if (lpDeviceInstanceID != NULL)
  730. { //append the new device instance id into internal list
  731. pDID = (LPWSTR) malloc((wcslen(lpDeviceInstanceID)+1) * sizeof(WCHAR));
  732. if (NULL == pDID)
  733. {
  734. LOG_error("memory allocation failed for new DeviceInstanceID");
  735. }
  736. else
  737. {
  738. lstrcpyW(pDID, lpDeviceInstanceID);
  739. vDIDList.push_back(pDID);
  740. LOG_out("new DeviceInstanceID added to internal list");
  741. }
  742. }
  743. if (0 == (dwFlags & BEGINLOGFLAG) || 0 == vDIDList.size())
  744. { // not last log request or nothing to log
  745. LOG_out("Won't log to hardware_XXX.xml");
  746. return;
  747. }
  748. GetWindowsUpdateDirectory(tszFilename);
  749. hr = GetUniqueFileName(tszFilename,tszUniqueFilename, MAX_PATH, hFile);
  750. if (S_OK != hr)
  751. {
  752. LOG_error("fail to get unique file name");
  753. fXmlFileError = true;
  754. goto CloseXML;
  755. }
  756. lstrcat(tszFilename, tszUniqueFilename);
  757. CloseHandle(hFile);
  758. fOut = _tfopen(tszFilename, _T("wb"));
  759. if (! fOut)
  760. {
  761. LOG_error("_tfopen failed");
  762. fXmlFileError = true;
  763. DeleteFile(tszFilename);
  764. goto CloseXML;
  765. }
  766. LOG_out("Logging to %s", tszFilename);
  767. // Don't need to get langID and platformID from catalog
  768. // get it offline using osdet.dll
  769. if (S_OK != ProcessOsdetOffline(helper))
  770. {
  771. LOG_error("platform and language detection failed");
  772. fXmlFileError = true;
  773. goto CloseXML;
  774. }
  775. _tstrdate(tszBuffer);
  776. #ifdef _UNICODE
  777. fwprintf(fOut, _T("%c"), (int) 0xFEFF);
  778. #else
  779. #error _UNICODE must be defined for InternalLogDriverNotFound
  780. #endif
  781. TCHAR tszSKU[SKU_STRING_MAX_LENGTH];
  782. hr = GetSKUString(tszSKU, SKU_STRING_MAX_LENGTH);
  783. if (S_OK != hr)
  784. {
  785. LOG_error("Fail to get SKU string");
  786. fXmlFileError = true;
  787. goto CloseXML;
  788. }
  789. if (0 > _ftprintf(fOut, _T("<?xml version=\"1.0\"?>\r\n<inventory date=\"%s\" locale=\"%p\" platform=\"%d\" sku=\"%s\">\r\n"), tszBuffer, helper.dwLangID, helper.enPlatform, tszSKU))
  790. {
  791. fXmlFileError = true;
  792. goto CloseXML;
  793. }
  794. for (int i = 0; i < vDIDList.size(); i++)
  795. {
  796. pDID = vDIDList[i];
  797. //
  798. // NTBUG9#151928 - Log both hardware and compatible IDs of the device that matches lpDeviceInstanceID
  799. //
  800. LOG_out("Log device instance with id %s", pDID);
  801. if (CR_SUCCESS == CM_Locate_DevNode(&devinst, (LPWSTR) pDID, 0))
  802. {
  803. if (0 > _ftprintf(fOut, _T("\t<device>\r\n")))
  804. {
  805. fXmlFileError = true;
  806. goto CloseXML;
  807. }
  808. //
  809. // Log device description
  810. //
  811. ULONG ulLength = 0;
  812. if (CR_BUFFER_SMALL == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_DEVICEDESC, NULL, NULL, &ulLength, 0))
  813. {
  814. bufText.resize(ulLength);
  815. if (bufText.valid() &&
  816. CR_SUCCESS == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_DEVICEDESC, NULL, bufText, &ulLength, 0))
  817. {
  818. if (0 > _ftprintf(fOut, _T("\t\t<description><![CDATA[%s]]></description>\r\n"), (LPCTSTR) bufText))
  819. {
  820. fXmlFileError = true;
  821. goto CloseXML;
  822. }
  823. }
  824. }
  825. //
  826. // Log all the hardware IDs
  827. //
  828. ulLength = 0;
  829. if (CR_BUFFER_SMALL == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_HARDWAREID, NULL, NULL, &ulLength, 0))
  830. {
  831. bufText.resize(ulLength);
  832. if (bufText.valid() &&
  833. CR_SUCCESS == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_HARDWAREID, NULL, bufText, &ulLength, 0))
  834. {
  835. for (TCHAR* pszNextID = (TCHAR*) bufText; *pszNextID; pszNextID += (lstrlen(pszNextID) + 1))
  836. {
  837. if (0 > _ftprintf(fOut, _T("\t\t<hwid><![CDATA[%s]]></hwid>\r\n"), (LPCTSTR) pszNextID))
  838. {
  839. fXmlFileError = true;
  840. goto CloseXML;
  841. }
  842. }
  843. }
  844. }
  845. //
  846. // Log all the compatible IDs
  847. //
  848. ulLength = 0;
  849. if (CR_BUFFER_SMALL == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_COMPATIBLEIDS, NULL, NULL, &ulLength, 0))
  850. {
  851. bufText.resize(ulLength);
  852. if (bufText.valid() &&
  853. CR_SUCCESS == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_COMPATIBLEIDS, NULL, bufText, &ulLength, 0))
  854. {
  855. for (TCHAR* pszNextID = (TCHAR*) bufText; *pszNextID; pszNextID += (lstrlen(pszNextID) + 1))
  856. {
  857. if (0 > _ftprintf(fOut, _T("\t\t<compid><![CDATA[%s]]></compid>\r\n"), (LPCTSTR) pszNextID))
  858. {
  859. fXmlFileError = true;
  860. goto CloseXML;
  861. }
  862. }
  863. }
  864. }
  865. if (0 > _ftprintf(fOut, _T("\t</device>\r\n")))
  866. {
  867. fXmlFileError = true;
  868. goto CloseXML;
  869. }
  870. }
  871. } //for
  872. if(0 > _ftprintf(fOut, _T("</inventory>\r\n")))
  873. {
  874. fXmlFileError = true;
  875. }
  876. CloseXML:
  877. if (fOut != NULL) fclose(fOut);
  878. for (int i = 0; i < vDIDList.size(); i++)
  879. {//free memory
  880. free(vDIDList[i]);
  881. }
  882. vDIDList.clear();
  883. //
  884. // Open Help Center only if we have valid xml
  885. //
  886. if (!fXmlFileError)
  887. {
  888. // open help center
  889. const static TCHAR szBase[] = _T("hcp://services/layout/contentonly?topic=hcp://system/dfs/uplddrvinfo.htm%3f"); //hardcode '?' escaping
  890. tchar_buffer tchCName(MAX_PATH); //file name canonicalized once
  891. tchar_buffer tchC2Name(INTERNET_MAX_URL_LENGTH); //file name canonicalized twice
  892. tchar_buffer tchFinalUrl;
  893. DWORD dwLen = 0;
  894. BOOL fBufferResized = FALSE;
  895. GetWindowsUpdateDirectory(tszFilename);
  896. lstrcat(tszFilename, tszUniqueFilename);
  897. LOG_out("Canonicalize %s", tszFilename);
  898. if (FAILED(CdmCanonicalizeUrl(tszFilename, tchCName, MAX_PATH, 0)))
  899. {
  900. goto CleanUp;
  901. }
  902. LOG_out("File name canonicalized %s", (LPTSTR) tchCName);
  903. LOG_out("Canonicalize file name %s AGAIN", (LPTSTR)tchCName);
  904. if (FAILED(CdmCanonicalizeUrl((LPCTSTR)tchCName, tchC2Name, INTERNET_MAX_URL_LENGTH, ICU_ENCODE_PERCENT)))
  905. {
  906. goto CleanUp;
  907. }
  908. LOG_out("File name canonicalized twice %s", (LPTSTR)tchC2Name);
  909. //need one extra character space
  910. //for the ending null
  911. tchFinalUrl.resize(lstrlen(szBase) + lstrlen((LPCTSTR) tchC2Name) + 1);
  912. if (!tchFinalUrl.valid())
  913. {
  914. LOG_error("Out of memory for FinalUrl buffer");
  915. goto CleanUp;
  916. }
  917. wsprintf(tchFinalUrl, _T("%s%s"), szBase, (LPCTSTR) tchC2Name);
  918. LOG_out("Opening HelpCenter: \"%s\"", (LPCTSTR) tchFinalUrl);
  919. ShellExecute(NULL, NULL, (LPCTSTR) tchFinalUrl, NULL, NULL, SW_SHOWNORMAL);
  920. return; //keep the file and return
  921. }
  922. //remove the file generated
  923. CleanUp:
  924. if (fOut != NULL)
  925. {
  926. DeleteFile(tszFilename);
  927. fOut = NULL;
  928. }
  929. return;
  930. }
  931. BOOL InternalFindMatchingDriver(IN PCONTEXTHANDLE pContextHandle, IN PDOWNLOADINFO pDownloadInfo, OUT PWUDRIVERINFO pWuDriverInfo)
  932. {
  933. LOG_block("InternalFindMatchingDriver");
  934. bool fConnected = IsInternetConnected();
  935. #ifdef _WUV3TEST
  936. if (fConnected)
  937. {
  938. // catalog spoofing
  939. DWORD dwIsInternetConnected = 1;
  940. DWORD dwSize = sizeof(dwIsInternetConnected);
  941. auto_hkey hkey;
  942. if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUV3TEST, 0, KEY_READ, &hkey)) {
  943. RegQueryValueEx(hkey, _T("IsInternetConnected"), 0, 0, (LPBYTE)&dwIsInternetConnected, &dwSize);
  944. }
  945. // only then do normal
  946. if (0 == dwIsInternetConnected)
  947. {
  948. fConnected = false;
  949. }
  950. }
  951. #endif
  952. SHelper helper;
  953. //
  954. // NTRAID#NTBUG9-185297-2000/11/21-waltw Fixed: bufBucket must have same scope as SHelper
  955. //
  956. byte_buffer bufBucket;
  957. DWORD dwError = PrepareCatalog(fConnected ? pContextHandle->szSiteServer : NULL, helper);
  958. if (NO_ERROR != dwError)
  959. {
  960. SetLastError(dwError);
  961. return FALSE;
  962. }
  963. if (!FindUpdate(pDownloadInfo, helper, bufBucket))
  964. {
  965. LOG_out("NO UPDATE IS FOUND");
  966. return FALSE;
  967. }
  968. LOG_out("PUID %d IS FOUND", helper.puid);
  969. // Fill out info
  970. if (
  971. 0 == MultiByteToWideChar(CP_ACP, 0, helper.DriverMatchInfo.pszHardwareID, -1, pWuDriverInfo->wszHardwareID, HWID_LEN) ||
  972. 0 == MultiByteToWideChar(CP_ACP, 0, helper.DriverMatchInfo.pszDescription, -1, pWuDriverInfo->wszDescription, LINE_LEN) ||
  973. 0 == MultiByteToWideChar(CP_ACP, 0, helper.DriverMatchInfo.pszMfgName, -1, pWuDriverInfo->wszMfgName, LINE_LEN) ||
  974. 0 == MultiByteToWideChar(CP_ACP, 0, helper.DriverMatchInfo.pszProviderName, -1, pWuDriverInfo->wszProviderName, LINE_LEN) ||
  975. 0 == MultiByteToWideChar(CP_ACP, 0, helper.DriverMatchInfo.pszDriverVer, -1, pWuDriverInfo->wszDriverVer, LINE_LEN)
  976. ) {
  977. LOG_error("MultiByteToWideChar failed");
  978. return FALSE;
  979. }
  980. return TRUE;
  981. }
  982. //This API gets the context handle array index from a connection handle.
  983. //The connection context handle is checked if found invalid then -1 is
  984. //returned. Otherwise the index that this handle references is returned.
  985. int GetHandleIndex(
  986. IN HANDLE hConnection //CDM Connect handle
  987. ) {
  988. int index = HandleToLong(hConnection) - 1;
  989. //If handle is invalid or not in use then return as nothing to do.
  990. if (!g_handleArray.valid_index(index))
  991. return -1;
  992. return index;
  993. }
  994. // for findoem
  995. HMODULE GetModule()
  996. {
  997. return g_hModule;
  998. }