//======================================================================= // // Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved. // // File: cdmp.cpp // // Owner: YanL // // Description: // // CDM auxiliary functions // // called by DownloadIsInternetAvailable() // GetDUNConnections // IsInternetConnectionWizardCompleted // IsInternetConnected // // called by DownloadGetUpdatedFiles() // FindDevInstID // // called by OpenCDMContext() // ProcessIdent // DownloadCdmCab // // called by DownloadUpdatedFiles() // GetDownloadPath // GetWindowsUpdateDirectory // LoadCdmnewDll // // called by GetPackage() // PrepareCatalog // ProcessOsdet // BuildExclusionsList // FindCatalog // FindUpdate // DeleteNode // URLPingReport // // called by InternalQueryDetectionFiles // DownloadToBuffer // // called by InternalLogDriverNotFound() // ProcessOsdetOffline // GetUniqueFileName // GetSKUString // CdmCanonicalizeUrl // // called by DllMain() // UpdateCdmDll // // called internally // IsInMap // GetOEMandLocalBitmask // DownloadToBuffer // // WU_VARIABLE_FIELD:: // GetNext // Find // WU_VARIABLE_FIELD // GetSize // //======================================================================= #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cdm.h" #include "cdmp.h" static ULONG IsInMap(IN PCDM_HASHTABLE pHashTable, IN LPCTSTR pHwID); static bool GetOEMandLocalBitmask(IN SHelper& helper, OUT byte_buffer& bufOut); static bool FilesIdentical(IN LPCTSTR szFileName1, IN LPCTSTR szFileName2); inline bool FileExists(IN LPCTSTR pszFile) { return 0xFFFFFFFF != GetFileAttributes(pszFile); } // MSCAT32 support (CryptCAT API's) const TCHAR MSCAT32DLL[] = _T("mscat32.dll"); const TCHAR CDMCAT[] = _T("cdm.cat"); const TCHAR CDMDLL[] = _T("cdm.dll"); const TCHAR CDMNEWDLL[] = _T("cdmnew.dll"); const TCHAR IUCDMDLL[] = _T("iucdm.dll"); // CryptCat Function Pointer Types typedef BOOL (*PFN_CryptCATAdminAcquireContext)(OUT HCATADMIN *phCatAdmin, IN const GUID *pgSubsystem, IN DWORD dwFlags); typedef HCATINFO (*PFN_CryptCATAdminAddCatalog)(IN HCATADMIN hCatAdmin, IN WCHAR *pwszCatalogFile, IN OPTIONAL WCHAR *pwszSelectBaseName, IN DWORD dwFlags); typedef BOOL (*PFN_CryptCATCatalogInfoFromContext)(IN HCATINFO hCatInfo, IN OUT CATALOG_INFO *psCatInfo, IN DWORD dwFlags); typedef BOOL (*PFN_CryptCATAdminReleaseCatalogContext)(IN HCATADMIN hCatAdmin, IN HCATINFO hCatInfo, IN DWORD dwFlags); typedef BOOL (*PFN_CryptCATAdminReleaseContext)(IN HCATADMIN hCatAdmin, IN DWORD dwFlags); // ---------------------------------------------------------------------------------- // // functions to compare file versions borrowed from IU // // ---------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------- // // define a type to hold file version data // // ---------------------------------------------------------------------------------- typedef struct _FILE_VERSION { WORD Major; WORD Minor; WORD Build; WORD Ext; } FILE_VERSION, *LPFILE_VERSION; static BOOL GetFileVersion(LPCTSTR lpsFile, LPFILE_VERSION lpstVersion) { LOG_block("GetFileVersion()"); DWORD dwVerInfoSize; DWORD dwHandle; DWORD dwVerNumber; LPVOID lpBuffer = NULL; UINT uiSize; VS_FIXEDFILEINFO* lpVSFixedFileInfo; if (NULL != lpstVersion) { // // if this pointer not null, we always try to initialize // this structure to 0, in order to reduce the change of // programming error, no matter the file exists or not. // ZeroMemory(lpstVersion, sizeof(FILE_VERSION)); } if (NULL == lpsFile || NULL == lpstVersion) { LOG_error("E_INVALIDARG"); return FALSE; } dwVerInfoSize = GetFileVersionInfoSize((LPTSTR)lpsFile, &dwHandle); if (0 == dwVerInfoSize) { DWORD dwErr = GetLastError(); if (0 == dwErr) { LOG_error("File %s does not have version data.", lpsFile); } else { LOG_error("Error: 0x%08x", dwErr); } return FALSE; } if (NULL == (lpBuffer = (LPVOID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwVerInfoSize))) { LOG_error("Failed to allocate memory to get version info"); return FALSE; } if (!GetFileVersionInfo((LPTSTR)lpsFile, dwHandle, dwVerInfoSize, lpBuffer)) { LOG_error("GetFileVersionInfo: 0x%08x", GetLastError()); HeapFree(GetProcessHeap(), 0, lpBuffer); return FALSE; } // // Get the value for Translation // if (!VerQueryValue(lpBuffer, _T("\\"), (LPVOID*)&lpVSFixedFileInfo, &uiSize) && (uiSize)) { LOG_error("VerQueryValue: 0x%08x", GetLastError()); HeapFree(GetProcessHeap(), 0, lpBuffer); return FALSE; } dwVerNumber = lpVSFixedFileInfo->dwFileVersionMS; lpstVersion->Major = HIWORD(dwVerNumber); lpstVersion->Minor = LOWORD(dwVerNumber); dwVerNumber = lpVSFixedFileInfo->dwFileVersionLS; lpstVersion->Build = HIWORD(dwVerNumber); lpstVersion->Ext = LOWORD(dwVerNumber); LOG_out("File %s found version %d.%d.%d.%d", lpsFile, lpstVersion->Major, lpstVersion->Minor, lpstVersion->Build, lpstVersion->Ext); HeapFree(GetProcessHeap(), 0, lpBuffer); return TRUE; } static int CompareVersions(const FILE_VERSION stVersion1, const FILE_VERSION stVersion2) { if ((short)stVersion1.Major < 0 || (short)stVersion2.Major < 0) { // // two empty version structure to compare, we call it equal // return 0; } if (stVersion1.Major != stVersion2.Major) { // // major diff, then we know the answer // return (stVersion1.Major < stVersion2.Major) ? -1 : 1; } else { if ((short)stVersion1.Minor < 0 || (short)stVersion2.Minor < 0) { // // if any minor missing, they equal // return 0; } if (stVersion1.Minor != stVersion2.Minor) { // // minor diff, then we know the answer // return (stVersion1.Minor < stVersion2.Minor) ? -1 : 1; } else { if ((short)stVersion1.Build < 0 || (short)stVersion2.Build < 0) { // // if any build is missing, they equal // return 0; } if (stVersion1.Build != stVersion2.Build) { // // if build diff then we are done // return (stVersion1.Build < stVersion2.Build) ? -1 : 1; } else { if ((short)stVersion1.Ext < 0 || (short)stVersion2.Ext < 0 || stVersion1.Ext == stVersion2.Ext) { // // if any ext is missing, or they equal, we are done // return 0; } else { return (stVersion1.Ext < stVersion2.Ext) ? -1 : 1; } } } } } // ---------------------------------------------------------------------------------- // // return in pCompareResult: // -1: if file ver of 1st parameter < file ver of 2nd parameter // 0: if file ver of 1st parameter = file ver of 2nd parameter // +1: if file ver of 1st parameter > file ver of 2nd parameter // // ---------------------------------------------------------------------------------- static HRESULT CompareFileVersions(LPCTSTR lpsFile1, LPCTSTR lpsFile2, int *pCompareResult) { LOG_block("CompareFileVersion()"); FILE_VERSION stVer1 = {-1,-1,-1,-1}, stVer2 = {-1,-1,-1,-1}; if (NULL == lpsFile1 || NULL == lpsFile2 || NULL == pCompareResult) { LOG_error("E_INVALIDARG"); return E_INVALIDARG; } if (!GetFileVersion(lpsFile1, &stVer1)) { LOG_error("E_INVALIDARG"); return E_INVALIDARG; } if (!GetFileVersion(lpsFile2, &stVer2)) { LOG_error("E_INVALIDARG"); return E_INVALIDARG; } *pCompareResult = CompareVersions(stVer1, stVer2); return S_OK; } // NTRAID#NTBUG9-218586-2000/11/27-waltw FIX: CDM: Self Update broken by enhanced WFP // // Adapted from IUInstallSFPCatalogFile // // This function is used during the selfupdate process on systems that use SFP to make // sure that we can update the engine DLL. // #if !(defined(UNICODE) || defined(_UNICODE)) #error This file must be compiled Unicode to insure we get a WCHAR string! #endif static HRESULT CDMInstallSFPCatalogFile(LPCWSTR pwszCatalogFile) { LOG_block("IUInstallSFPCatalogFile()"); HRESULT hr = S_OK; HCATADMIN hCatAdmin; HCATINFO hCatInfo; CATALOG_INFO CatalogInfo; DWORD dwSize = 0; DWORD dwRet; TCHAR wszCatalogFile[MAX_PATH]; // First Try to Get Pointers to the CryptCAT API's PFN_CryptCATAdminAcquireContext fpnCryptCATAdminAcquireContext = NULL; PFN_CryptCATAdminAddCatalog fpnCryptCATAdminAddCatalog = NULL; PFN_CryptCATCatalogInfoFromContext fpnCryptCATCatalogInfoFromContext = NULL; PFN_CryptCATAdminReleaseCatalogContext fpnCryptCATAdminReleaseCatalogContext = NULL; PFN_CryptCATAdminReleaseContext fpnCryptCATAdminReleaseContext = NULL; HMODULE hMSCat32 = LoadLibrary(MSCAT32DLL); if (NULL == hMSCat32) { // This is Whistler only code - we require mscat32 hr = E_FAIL; goto CleanUp; } fpnCryptCATAdminAcquireContext = (PFN_CryptCATAdminAcquireContext) GetProcAddress(hMSCat32, "CryptCATAdminAcquireContext"); fpnCryptCATAdminAddCatalog = (PFN_CryptCATAdminAddCatalog) GetProcAddress(hMSCat32, "CryptCATAdminAddCatalog"); fpnCryptCATCatalogInfoFromContext = (PFN_CryptCATCatalogInfoFromContext) GetProcAddress(hMSCat32, "CryptCATCatalogInfoFromContext"); fpnCryptCATAdminReleaseCatalogContext = (PFN_CryptCATAdminReleaseCatalogContext) GetProcAddress(hMSCat32, "CryptCATAdminReleaseCatalogContext"); fpnCryptCATAdminReleaseContext = (PFN_CryptCATAdminReleaseContext) GetProcAddress(hMSCat32, "CryptCATAdminReleaseContext"); if ((NULL == fpnCryptCATAdminAcquireContext) || (NULL == fpnCryptCATAdminAddCatalog) || (NULL == fpnCryptCATCatalogInfoFromContext) || (NULL == fpnCryptCATAdminReleaseCatalogContext) || (NULL == fpnCryptCATAdminReleaseContext)) { LOG_error("Some CryptCAT API's were not available, even though mscat32.dll was Available"); hr = E_FAIL; goto CleanUp; } if (!fpnCryptCATAdminAcquireContext(&hCatAdmin, NULL, 0)) { dwRet = GetLastError(); LOG_error("CryptCATAdminAcquireContext Failed, Error was: %d", dwRet); hr = HRESULT_FROM_WIN32(dwRet); goto CleanUp; } // // CryptCATAdminAddCatalog takes a non-const string so be safe // lstrcpy(wszCatalogFile, pwszCatalogFile); hCatInfo = fpnCryptCATAdminAddCatalog(hCatAdmin, wszCatalogFile, NULL, 0); if (!hCatInfo) { dwRet = GetLastError(); LOG_error("CryptCATAdminAddCatalog Failed, Error was: %d", dwRet); hr = HRESULT_FROM_WIN32(dwRet); fpnCryptCATAdminReleaseContext(hCatAdmin, 0); goto CleanUp; } fpnCryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfo, 0); fpnCryptCATAdminReleaseContext(hCatAdmin, 0); CleanUp: if (NULL != hMSCat32) { FreeLibrary(hMSCat32); hMSCat32 = NULL; } return hr; } //======================================================================= // // called by DownloadIsInternetAvailable() // //======================================================================= //Returns the number of dial up networking connections that this client has created. int GetDUNConnections( void ) { RASENTRYNAME rname; rname.dwSize = sizeof(RASENTRYNAME); DWORD dwSize = sizeof(rname); DWORD dwEntries = 0; RasEnumEntries(NULL, NULL, &rname, &dwSize, &dwEntries); return dwSize/sizeof(RASENTRYNAME); } //HKEY_CURRENT_USER\Software\Microsoft\Internet Connection Wizard - Completed == 01 00 00 00 //Determines if the internet connection Wizzard has been completed. bool IsInternetConnectionWizardCompleted( void ) { auto_hkey hKey; if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Internet Connection Wizard"), 0, KEY_READ, &hKey) != NO_ERROR) return false; DWORD dwValue = 0; DWORD dwSize = sizeof(dwValue); return NO_ERROR == RegQueryValueEx(hKey, _T("Completed"), NULL, NULL, (PBYTE)&dwValue, &dwSize) && 1 == dwValue; } //Determines if the Internet is already connected to this client. bool IsInternetConnected( void ) { DWORD dwFlags = INTERNET_CONNECTION_LAN | INTERNET_CONNECTION_PROXY | INTERNET_CONNECTION_MODEM; return InternetGetConnectedState(&dwFlags, 0) ? true : false; } //======================================================================= // // called by OpenCDMContext() // //======================================================================= // security verification bool ProcessIdent( IN CDownload& download, IN CDiamond& diamond, //pointer to diamond compress clas to use to expand ident.cab IN LPCTSTR szSecurityServerCur, OUT LPTSTR szSiteSever, //returned description server to use. OUT LPTSTR szDownloadServer //returned cab pool download server to use. ) { LOG_block("ProcessIdent"); //We need to download ident.cab since it contains the server path //for cdm.dll and the catalog to use to get the cdm.dll from. TCHAR szIdentCab[MAX_PATH+1]; GetWindowsUpdateDirectory(szIdentCab); PathAppend(szIdentCab, _T("identcdm.cab")); if (!download.Copy(_T("identcdm.cab"), szIdentCab)) { LOG_error("Failed to download identcdm.cab"); return false; } #ifdef _WUV3TEST // // For test builds, it is ok to show certificate if WinTrustUI reg key == 1 // (see CheckWinTrust in newtrust.cpp for details) // if (FAILED(VerifyFile(szIdentCab, TRUE))) #else if (FAILED(VerifyFile(szIdentCab, FALSE))) #endif { LOG_error("signature verification failed"); DeleteFile(szIdentCab); SetLastError(ERROR_ACCESS_DENIED); return false; } if (!diamond.IsValidCAB(szIdentCab)) { LOG_error("'%s' is not a valid cab", szIdentCab); return false; } TCHAR szIdentIni[MAX_PATH]; GetWindowsUpdateDirectory(szIdentIni); PathAppend(szIdentIni, _T("identcdm.ini")); DeleteFile(szIdentIni); byte_buffer bufMemOut; if (!diamond.Decompress(szIdentCab, szIdentIni)) { LOG_error("'%s' is not a valid cab", szIdentCab); return false; } TCHAR szSecurityServer[MAX_PATH]; if (0 == GetPrivateProfileString( _T("cdm"), _T("SecurityServer"), _T(""), szSecurityServer, sizeOfArray(szSecurityServer), szIdentIni )) { LOG_error("GetPrivateProfileString(cdm, SecurityServer) failed"); return false; } //If this ident.cab did not come from the same server in the ident.cab then it //is invalid and we cannot download any drivers. if (0 != lstrcmpi(szSecurityServer, szSecurityServerCur)) { LOG_error("SecurityServer '%s' is invalid", szSecurityServer); return false; } // // szSiteServer and szDownloadServer are allocated MAX_PATH characters by caller. // if (0 == GetPrivateProfileString( _T("cdm"), _T("SiteServer"), _T(""), szSiteSever, MAX_PATH, szIdentIni )) { LOG_error("GetPrivateProfileString(cdm, SiteSever) failed"); return false; } if (0 == GetPrivateProfileString( _T("cdm"), _T("DownloadServer"), _T(""), szDownloadServer, MAX_PATH, szIdentIni )) { LOG_error("GetPrivateProfileString(cdm, DownloadServer) failed"); return false; } return true; } // get new cdm.cab for potential update bool DownloadCdmCab( IN CDownload& download, IN CDiamond& diamond, OUT bool& fNeedUpdate // initialized to false by caller ) { LOG_block("DownloadCdmCab"); bool fIsIUCab = false; #ifdef _WIN64 static const TCHAR szCabNameServer[] = _T("cdm64.cab"); static const TCHAR szIUCabNameServer[] = _T("iucdm64.cab"); #else static const TCHAR szCabNameServer[] = _T("cdm32.cab"); static const TCHAR szIUCabNameServer[] = _T("iucdm32.cab"); #endif TCHAR szWUDir[MAX_PATH]; GetWindowsUpdateDirectory(szWUDir); // // First, try to get the IU cab, but don't bail if it isn't there // TCHAR szCabNameLocal[MAX_PATH]; PathCombine(szCabNameLocal, szWUDir, szIUCabNameServer); if (download.Copy(szIUCabNameServer, szCabNameLocal)) { fIsIUCab = true; } else { // // It wasn't on the server or we didn't get it, go get the V3 version // LOG_out("download.Copy(%s) failed, try %s", szIUCabNameServer, szCabNameServer); PathCombine(szCabNameLocal, szWUDir, szCabNameServer); if (!download.Copy(szCabNameServer, szCabNameLocal)) { LOG_out("download.Copy(%s) failed", szCabNameServer); return false; } if (GetLastError() == ERROR_ALREADY_EXISTS) { LOG_out("%s is good enough", szCabNameLocal); return true; } } // // We got a cab, decompress to get cdm.dll and cdm.cat // if (!diamond.Decompress(szCabNameLocal, _T("*"))) { LOG_error("Decompress '%s' failed", szCabNameLocal); // maybe it was a bogus cab - nuke the cab from our local dir DeleteFile(szCabNameLocal); return false; } TCHAR szSysDir[MAX_PATH]; if (0 == GetSystemDirectory(szSysDir, MAX_PATH)) { LOG_error("GetSystemDirectory: 0x%08x", GetLastError()); return false; } TCHAR szCurrentCdmDll[MAX_PATH]; PathCombine(szCurrentCdmDll, szSysDir, CDMDLL); TCHAR szDownloadedCdmDll[MAX_PATH]; PathCombine(szDownloadedCdmDll, szWUDir, CDMDLL); TCHAR szLocalCatPath[MAX_PATH]; PathCombine(szLocalCatPath, szWUDir, CDMCAT); HRESULT hr; // // If cab isn't IU version of CDM check version // if (!fIsIUCab) { // NTRAID#NTBUG9-207976-2000/11/28-waltw Check version info and only update if downloaded // cdm.dll has a version > the existing cdm.dll. int nCompareResult; if FAILED(hr = CompareFileVersions(szDownloadedCdmDll, szCurrentCdmDll, &nCompareResult)) { LOG_error("CompareFileVersions: 0x%08x", hr); return false; } if (0 >= nCompareResult) { LOG_error("Downloaded cdm.dll was smaller version than existing cdm.dll in system[32] folder"); // // Clean up - they are the wrong version. No further action needed so return true. // DeleteFile(szDownloadedCdmDll); DeleteFile(szLocalCatPath); return true; } } // NTRAID#NTBUG9-218586-2000/11/27-waltw FIX: CDM: Self Update broken by enhanced WFP // Now we 'should' have two files from the cdmXx.cab in the WindowsUpdate Folder // One is the CDM.DLL, the other is the Catalog File CDM.CAT so // we can install the DLL on Whistler (a SystemFileProtected/WFP OS). hr = CDMInstallSFPCatalogFile(szLocalCatPath); DeleteFile(szLocalCatPath); // delete the CAT file, once its installed its copied to a new location. if (FAILED(hr)) { // Since this is Whistler, we have to bail if we didn't install the catalog since we // know that cdm.dll is under SFP/WFP. return false; } /* copy cdm.dll to system directory as iucdm.dll or cdmnew.dll */ TCHAR szCdmNewDll[MAX_PATH]; PathCombine(szCdmNewDll, szSysDir, fIsIUCab ? IUCDMDLL : CDMNEWDLL); if (!CopyFile(szDownloadedCdmDll, szCdmNewDll, FALSE)) { LOG_error("CopyFile(%s, %s) returns %d", szDownloadedCdmDll, szCdmNewDll, GetLastError()); return false; } // // Now that it's copied, we can delete from the WU dir. // DeleteFile(szDownloadedCdmDll); // // Everything OK, indicate we need to call UpdateCdmDll() from DllMain // fNeedUpdate = true; #ifdef _WUV3TEST /* Test redirect*/{ auto_hkey hkey; DWORD dwSelfUpdate = 1; // On by default DWORD dwSize = sizeof(dwSelfUpdate); if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUV3TEST, 0, KEY_READ, &hkey)) { RegQueryValueEx(hkey, _T("SelfUpdate"), 0, 0, (LPBYTE)&dwSelfUpdate, &dwSize); } if (0 == dwSelfUpdate) { LOG_out("New %s Has been downloaded but SELF UPDATE is OFF", szCabNameServer); fNeedUpdate = false; } else { LOG_out("New %s Has been downloaded", szCabNameServer); } } #endif return true; } //======================================================================= // // called by DownloadUpdatedFiles() // //======================================================================= //gets a path to the directory that cdm.dll will copy the install cabs to. //returns the length of the path. //Note: The input buffer must be at least MAX_PATH size. int GetDownloadPath( IN LPTSTR szPath //CDM Local directory where extracted files will be placed. ) { if(!GetTempPath(MAX_PATH, szPath)) { lstrcpy(szPath,_T("C:\\temp\\")); CreateDirectory(szPath, NULL); } PathAppend(szPath, _T("CDMinstall")); CreateDirectory(szPath, NULL); return lstrlen(szPath) + 1; } //This function returns the location of the WindowsUpdate directory. All local //files are store in this directory. The szDir parameter needs to be at least //MAX_PATH. void GetWindowsUpdateDirectory( OUT LPTSTR szDir //returned WindowsUpdate directory ) { auto_hkey hkey; szDir[0] = '\0'; if (RegOpenKey(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"), &hkey) == NO_ERROR) { DWORD cbPath = _MAX_PATH; RegQueryValueEx(hkey, _T("ProgramFilesDir"), NULL, NULL, (LPBYTE)szDir, &cbPath); } if (szDir[0] == '\0') { if (! GetWindowsDirectory(szDir, _MAX_PATH)) { lstrcpy(szDir, _T("C")); } szDir[1] = '\0'; StrCat(szDir, _T(":\\Program Files")); } StrCat(szDir, _T("\\WindowsUpdate\\")); //Create Windows Update directory if it does not exist CreateDirectory(szDir, NULL); return; } HINSTANCE LoadCdmnewDll() { // If there is cdmnew.dll in system directory use it TCHAR szCdmNewDll[MAX_PATH]; GetSystemDirectory(szCdmNewDll, sizeOfArray(szCdmNewDll)); PathAppend(szCdmNewDll, CDMNEWDLL); if (!FileExists(szCdmNewDll)) return 0; TCHAR szCdmDll[MAX_PATH]; GetSystemDirectory(szCdmDll, sizeOfArray(szCdmDll)); PathAppend(szCdmDll, _T("cdm.dll")); if (FilesIdentical(szCdmNewDll, szCdmDll)) { LOG_out1("remove cdmnew.dll after selfupdate"); DeleteFile(szCdmNewDll); return 0; } HINSTANCE hlib = 0; #ifdef _WUV3TEST auto_hkey hkey; DWORD dwSelfUpdate = 1; // On by default DWORD dwSize = sizeof(dwSelfUpdate); if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUV3TEST, 0, KEY_READ, &hkey)) { RegQueryValueEx(hkey, _T("SelfUpdate"), 0, 0, (LPBYTE)&dwSelfUpdate, &dwSize); } if (0 == dwSelfUpdate) LOG_out1("SELF UPDATE is OFF - using current dll"); else #endif hlib = LoadLibrary(szCdmNewDll); return hlib; } //======================================================================= // // called by GetPackage() // //======================================================================= DWORD PrepareCatalog( IN LPCTSTR pszSiteServer, IN OUT SHelper& helper ) { LOG_block("PrepareCatalog"); if (NULL != pszSiteServer) { if (helper.download.Connect(pszSiteServer)) { LOG_out("Connected to SiteServer '%s'", pszSiteServer); } else { LOG_error("No connection to SiteServer '%s'", pszSiteServer); return ERROR_GEN_FAILURE; } } if (!helper.diamond.valid()) { LOG_error("cannot init diamond"); return ERROR_GEN_FAILURE; } // Get system info helper.OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&helper.OSVersionInfo); SYSTEM_INFO si; GetSystemInfo(&si); helper.dwArchitecture = si.wProcessorArchitecture; //Get the catalog path, platform e.t. to use DWORD dwError = ProcessOsdet(helper); if (NO_ERROR != dwError) return dwError; if (!FindCatalog(helper)) { LOG_error("no catalog"); dwError = GetLastError(); if (ERROR_INVALID_FUNCTION == dwError) return ERROR_INVALID_FUNCTION; else return ERROR_FILE_NOT_FOUND; } BuildExclusionsList(helper); return NO_ERROR; } // get language and platform ID from osdet.dll DWORD ProcessOsdet( IN OUT SHelper& helper ) { LOG_block("ProcessOsdet"); // give it a correct name TCHAR szOsdetDllLocal[MAX_PATH]; GetWindowsUpdateDirectory(szOsdetDllLocal); PathAppend(szOsdetDllLocal, _T("osdet.dll")); if (helper.download.IsConnected()) { #ifdef _WIN64 static const TCHAR szOsdetCabSrv[] = _T("osdet.w64"); #else static const TCHAR szOsdetCabSrv[] = _T("osdet.w32"); #endif // Put it to the WU directory TCHAR szOsdetCabLocal[MAX_PATH]; GetWindowsUpdateDirectory(szOsdetCabLocal); PathAppend(szOsdetCabLocal, szOsdetCabSrv); if (!helper.download.Copy(szOsdetCabSrv, szOsdetCabLocal)) { DWORD dwError = GetLastError(); LOG_error("download.Copy(%s) failed %d", szOsdetCabSrv, dwError); return dwError; } if (GetLastError() != ERROR_ALREADY_EXISTS) { if (helper.diamond.IsValidCAB(szOsdetCabLocal)) { if (!helper.diamond.Decompress(szOsdetCabLocal, szOsdetDllLocal)) { DWORD dwError = GetLastError(); LOG_error("Decompress '%s' failed %d", szOsdetCabLocal, dwError); return dwError; } } else { CopyFile(szOsdetCabLocal, szOsdetDllLocal, FALSE); } } } auto_hlib hlib = LoadLibrary(szOsdetDllLocal); if (!hlib.valid()) { LOG_error("error loading library %s", szOsdetDllLocal); return ERROR_INVALID_FUNCTION; } PFN_V3_GetLangID fpnV3_GetLangID = (PFN_V3_GetLangID)GetProcAddress(hlib, "V3_GetLangID"); if (NULL == fpnV3_GetLangID) { LOG_error("cannot find function 'V3_GetLangID'"); return ERROR_CALL_NOT_IMPLEMENTED; } helper.dwLangID = (*fpnV3_GetLangID)(); PFN_V3_Detection pfnV3_Detection = (PFN_V3_Detection)GetProcAddress(hlib, "V3_Detection"); if (NULL == pfnV3_Detection) { LOG_error("cannot find function 'V3_Detection'"); return ERROR_CALL_NOT_IMPLEMENTED; } PDWORD pdwPlatformList = 0; //Detected Platform list. int iTotalPlatforms; //Total number of detected platforms. (*pfnV3_Detection)(&pdwPlatformList, &iTotalPlatforms); if (NULL != pdwPlatformList) { helper.enPlatform = (enumV3Platform)pdwPlatformList[0]; CoTaskMemFree(pdwPlatformList); } else { helper.enPlatform = enV3_DefPlat; } return S_OK; } //borrowed from osdet.cpp static int aton(LPCTSTR ptr) { int i = 0; while ('0' <= *ptr && *ptr <= '9') { i = 10 * i + (int)(*ptr - '0'); ptr ++; } return i; } //borrowed from osdet.cpp static WORD CorrectGetACP(void) { WORD wCodePage = 0; auto_hkey hkey; const TCHAR REGKEY_ACP[] = _T("ACP"); const TCHAR REGPATH_CODEPAGE[] = _T("SYSTEM\\CurrentControlSet\\Control\\Nls\\CodePage"); RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGPATH_CODEPAGE, 0, KEY_QUERY_VALUE, &hkey); DWORD type; TCHAR szCodePage[MAX_PATH]; DWORD size = sizeof(szCodePage); if (NO_ERROR == RegQueryValueEx(hkey, REGKEY_ACP, 0, &type, (BYTE *)szCodePage, &size) && type == REG_SZ) { wCodePage = (WORD)aton(szCodePage); } return wCodePage; } //borrowed from osdet.cpp static WORD CorrectGetOEMCP(void) { WORD wCodePage = 0; auto_hkey hkey; // Registry keys to determine special OS's and enabled OS's. const TCHAR REGPATH_CODEPAGE[] = _T("SYSTEM\\CurrentControlSet\\Control\\Nls\\CodePage"); const TCHAR REGKEY_OEMCP[] = _T("OEMCP"); RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGPATH_CODEPAGE, 0, KEY_QUERY_VALUE, &hkey); DWORD type; TCHAR szCodePage[MAX_PATH]; DWORD size = sizeof(szCodePage); if (NO_ERROR == RegQueryValueEx(hkey, REGKEY_OEMCP, 0, &type, (BYTE *)szCodePage, &size) && type == REG_SZ) { wCodePage = (WORD)aton(szCodePage); } return wCodePage; } //borrowed from osdet.cpp static LANGID MapLangID(LANGID langid) { switch (PRIMARYLANGID(langid)) { case LANG_ARABIC: langid = MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA); break; case LANG_CHINESE: if (SUBLANGID(langid) != SUBLANG_CHINESE_TRADITIONAL) langid = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED); break; case LANG_DUTCH: langid = MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH); break; case LANG_GERMAN: langid = MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN); break; case LANG_ENGLISH: if (SUBLANGID(langid) != SUBLANG_ENGLISH_UK) langid = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); break; case LANG_FRENCH: langid = MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH); break; case LANG_ITALIAN: langid = MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN); break; case LANG_KOREAN: langid = MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN); break; case LANG_NORWEGIAN: langid = MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL); break; case LANG_PORTUGUESE: // We support both SUBLANG_PORTUGUESE and SUBLANG_PORTUGUESE_BRAZILIAN break; case LANG_SPANISH: langid = MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH); break; case LANG_SWEDISH: langid = MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH); break; }; return langid; } //borrowed from osdet.cpp static bool FIsNECMachine() { const TCHAR NT5_REGPATH_MACHTYPE[] = _T("HARDWARE\\DESCRIPTION\\System"); const TCHAR NT5_REGKEY_MACHTYPE[] = _T("Identifier"); const TCHAR REGVAL_MACHTYPE_NEC[] = _T("NEC PC-98"); const PC98_KEYBOARD_ID = 0x0D; bool fNEC = false; OSVERSIONINFO osverinfo; #define LOOKUP_OEMID(keybdid) HIBYTE(LOWORD((keybdid))) osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osverinfo)) { if (osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { HKEY hKey; DWORD type; TCHAR tszMachineType[50]; DWORD size = sizeof(tszMachineType); if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, NT5_REGPATH_MACHTYPE, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) { if (RegQueryValueEx(hKey, NT5_REGKEY_MACHTYPE, 0, &type, (BYTE *)tszMachineType, &size) == ERROR_SUCCESS) { if (type == REG_SZ) { if (lstrcmp(tszMachineType, REGVAL_MACHTYPE_NEC) == 0) { fNEC = true; } } } RegCloseKey(hKey); } } else // enOSWin98 { // All NEC machines have NEC keyboards for Win98. NEC // machine detection is based on this. if (LOOKUP_OEMID(GetKeyboardType(1)) == PC98_KEYBOARD_ID) { fNEC = true; } } } return fNEC; } // borrowed from osdet.cpp // return V3 language ID DWORD internalV3_GetLangID() { const LANGID LANGID_ENGLISH = 0x0409; const LANGID LANGID_GREEK = 0x0408; const LANGID LANGID_JAPANESE = 0x0411; const WORD CODEPAGE_ARABIC = 1256; const WORD CODEPAGE_HEBREW = 1255; const WORD CODEPAGE_THAI = 874; const WORD CODEPAGE_GREEK_IBM = 869; WORD wCodePage = 0; LANGID langidCurrent = GetSystemDefaultUILanguage(); // // special handling for languages // switch (langidCurrent) { case LANGID_ENGLISH: // enabled langauges wCodePage = CorrectGetACP(); if (CODEPAGE_ARABIC != wCodePage && CODEPAGE_HEBREW != wCodePage && CODEPAGE_THAI != wCodePage) { wCodePage = 0; } break; case LANGID_GREEK: // Greek IBM? wCodePage = CorrectGetOEMCP(); if (wCodePage != CODEPAGE_GREEK_IBM) { // if its not Greek IBM we assume its MS. The language code for Greek MS does not include // the code page wCodePage = 0; } break; case LANGID_JAPANESE: if (FIsNECMachine()) { wCodePage = 1; } break; default: // map language to the ones we support langidCurrent = MapLangID(langidCurrent); break; } return MAKELONG(langidCurrent, wCodePage); } //borrowed from osdet.cpp //called by V3_Detection static enumV3Platform DetectClientPlatform(void) { #ifdef _WIN64 return enV3_Wistler64; #else return enV3_Wistler; #endif } //borrowed from osdet.cpp void internalV3_Detection( PINT *ppiPlatformIDs, PINT piTotalIDs ) { //We use coTaskMemAlloc in order to be compatible with the V3 memory allocator. //We don't want the V3 memory exception handling in this dll. *ppiPlatformIDs = (PINT)CoTaskMemAlloc(sizeof(INT)); if ( !*ppiPlatformIDs ) { *piTotalIDs = 0; } else { #ifdef _WUV3TEST auto_hkey hkey; if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUV3TEST, 0, KEY_READ, &hkey)) { DWORD dwPlatform = 0; DWORD dwSize = sizeof(dwPlatform); if (NO_ERROR == RegQueryValueEx(hkey, _T("Platform"), 0, 0, (LPBYTE)&dwPlatform, &dwSize)) { *ppiPlatformIDs[0] = (int)dwPlatform; *piTotalIDs = 1; return; } } #endif *ppiPlatformIDs[0] = (int)DetectClientPlatform(); *piTotalIDs = 1; } } // get language and platform ID of local machine // similiar to ProcessOsdet // not using osdet.dll // If return is not S_OK, it means this function fails DWORD ProcessOsdetOffline( IN OUT SHelper& helper ) { LOG_block("ProcessOsdetOffline"); LOG_out("Call internalV3_GetLangID()"); helper.dwLangID = internalV3_GetLangID(); PINT pdwPlatformList = 0; //Detected Platform list. int iTotalPlatforms; //Total number of detected platforms. LOG_out("Call internalV3_Detection()"); internalV3_Detection(&pdwPlatformList, &iTotalPlatforms); if (NULL != pdwPlatformList) { helper.enPlatform = (enumV3Platform)pdwPlatformList[0]; CoTaskMemFree(pdwPlatformList); } else { helper.enPlatform = enV3_DefPlat; } return S_OK; } // process excluded puids from catalog.ini bool BuildExclusionsList( IN SHelper& helper ) { LOG_block("BuildExclusionsList"); static const TCHAR szSrvPath[MAX_PATH] = _T("catalog.ini"); TCHAR szCliPath[MAX_PATH]; GetWindowsUpdateDirectory(szCliPath); PathAppend(szCliPath, szSrvPath); if (helper.download.IsConnected()) { if (!helper.download.Copy(szSrvPath, szCliPath)) { LOG_out("catalog.ini is not there"); return false; } } TCHAR szValue[256]; if (0 == GetPrivateProfileString(_T("exclude"), _T("puids"), _T(""), szValue, sizeOfArray(szValue), szCliPath)) { LOG_out("nothing is excluded"); return false; } LPCTSTR szInt = szValue; while(true) { helper.apuidExclude.push_back(_ttoi(szInt)); szInt = _tcschr(szInt, ','); if (NULL == szInt) break; szInt ++; } return true; } // for the detected platform helper.enPlatform find catalog that has drivers bool FindCatalog( IN OUT SHelper& helper ) { LOG_block("FindCatalog"); byte_buffer bufCatList; if (!DownloadToBuffer(helper, _T("inventory.cat"), bufCatList)) { LOG_error("Download inventory.cat failed"); return NULL; } int cnCatalogs = bufCatList.size() / sizeof(CATALOGLIST); PCATALOGLIST pCatalogs = (PCATALOGLIST)(LPBYTE)bufCatList; for (int nCatalog = 0; nCatalog < cnCatalogs; nCatalog ++) { LOG_out("%4d - %6d - %#08X", pCatalogs[nCatalog].dwPlatform, pCatalogs[nCatalog].dwCatPuid, pCatalogs[nCatalog].dwFlags); if (pCatalogs[nCatalog].dwPlatform == helper.enPlatform && (pCatalogs[nCatalog].dwFlags & CATLIST_DRIVERSPRESENT)) { helper.puidCatalog = pCatalogs[nCatalog].dwCatPuid; LOG_out("catalog is %d", helper.puidCatalog); return true; } } LOG_error("catalog is not found"); return false; } static bool IsExcluded(PUID puid, SHelper& helper) { for (int i = 0; i < helper.apuidExclude.size(); i ++) { if (helper.apuidExclude[i] == puid) return true; } return false; } //Returns NULL if there is not an update for this package or //the download package's bucket file if there is an update. bool FindUpdate( IN PDOWNLOADINFO pDownloadInfo, //download information structure describing package to be read from server IN OUT SHelper& helper, IN OUT byte_buffer& bufBucket ) { LOG_block("FindUpdate"); USES_CONVERSION; // get bitmask byte_buffer bufBitmask; if (! GetOEMandLocalBitmask(helper, bufBitmask)) { LOG_error("GetOEMandLocalBitmask() failed"); return false; } // Get CDM inventory TCHAR szPath[MAX_PATH]; wsprintf(szPath, _T("%d/inventory.cdm"), helper.puidCatalog); byte_buffer bufInventory; if (!DownloadToBuffer(helper, szPath, bufInventory)) { LOG_error("Dowload inventory failed"); return false; } PCDM_HASHTABLE pHashTable = (PCDM_HASHTABLE)(LPBYTE)bufInventory; auto_pointer< IDrvInfo > pDrvInfo; tchar_buffer bufHardwareIDs; // we have two types of calls if (pDownloadInfo->lpDeviceInstanceID) { if (!CDrvInfoEnum::GetDrvInfo(pDownloadInfo->lpDeviceInstanceID, &pDrvInfo)) { LOG_error("CDrvInfoEnum::GetDrvInfo(%s) failed", pDownloadInfo->lpDeviceInstanceID); return false; } } if (NULL != pDownloadInfo->lpHardwareIDs) { // one hardware id for a package - eather printers or w9x if we cannot find device instance ID // if architecture is not the same as current archtecture we need to prefix it bufHardwareIDs.resize(lstrlenW(pDownloadInfo->lpHardwareIDs) + 6); if (!bufHardwareIDs.valid()) return false; int cnSize = bufHardwareIDs.size(); ZeroMemory(bufHardwareIDs, cnSize); LPTSTR pszHardwareId = bufHardwareIDs; if (pDownloadInfo->dwArchitecture != helper.dwArchitecture) { if (PROCESSOR_ARCHITECTURE_INTEL == pDownloadInfo->dwArchitecture) { static const TCHAR szIntel[] = PRINT_ENVIRONMENT_INTEL; lstrcpy(pszHardwareId, szIntel); pszHardwareId += lstrlen(szIntel); cnSize -= lstrlen(szIntel); } else if (PROCESSOR_ARCHITECTURE_ALPHA == pDownloadInfo->dwArchitecture) { static const TCHAR szAlpha[] = PRINT_ENVIRONMENT_ALPHA; lstrcpy(pszHardwareId, szAlpha); pszHardwareId += lstrlen(szAlpha); cnSize -= lstrlen(szAlpha); } } lstrcpy(pszHardwareId, W2T((LPWSTR)pDownloadInfo->lpHardwareIDs)); } else if (!pDrvInfo.valid() || !pDrvInfo->GetAllHardwareIDs(bufHardwareIDs)) { LOG_error("!pDrvInfo.valid() || !pDrvInfo->GetAllHardwareIDs()"); return false; } // Check if we have MatchingDeviceId tchar_buffer bufMatchingDeviceId; if (pDrvInfo.valid()) pDrvInfo->GetMatchingDeviceId(bufMatchingDeviceId); // It's OK not to get it // #ifdef _WUV3TEST if (pDrvInfo.valid() && pDrvInfo->HasDriver()) { if (bufMatchingDeviceId.valid()) LOG_out("driver installed on MatchingDeviceId %s", (LPCTSTR)bufMatchingDeviceId); else LOG_error("driver installed, but HWID is not available"); } else { if (bufMatchingDeviceId.valid()) LOG_error("driver is not installed, but MatchingDeviceId is %s", (LPCTSTR)bufMatchingDeviceId); else LOG_out("no driver installed"); } // #endif // Updates bool fMoreSpecific = true; for (LPCTSTR szHardwareId = bufHardwareIDs; fMoreSpecific && *szHardwareId; szHardwareId += lstrlen(szHardwareId) + 1) { // MatchingDeviceID is the last one to pay attention to fMoreSpecific = !bufMatchingDeviceId.valid() || 0 != lstrcmpi(szHardwareId, bufMatchingDeviceId); ULONG ulHashIndex = IsInMap(pHashTable, szHardwareId); if (-1 == ulHashIndex) continue; // read bucket file TCHAR szPath[MAX_PATH]; wsprintf(szPath, _T("%d/%d.bkf"), helper.puidCatalog, ulHashIndex); if (!DownloadToBuffer(helper, szPath, bufBucket)) { LOG_error("No bucket where it has to be"); continue; } FILETIME ftDriverInstalled = {0,0}; if (!fMoreSpecific) { // Then it has to have a driver - Matching device ID is set if (!pDrvInfo->GetDriverDate(ftDriverInstalled)) { LOG_error("!pDrvInfo->GetDriverDate(ftDriverInstalled)"); return false; } } DRIVER_MATCH_INFO DriverMatchInfo; helper.puid = CDM_FindUpdateInBucket(szHardwareId, fMoreSpecific ? NULL : &ftDriverInstalled, bufBucket, bufBucket.size(), bufBitmask, &helper.DriverMatchInfo); if (0 == helper.puid) continue; if (IsExcluded(helper.puid, helper)) continue; return true; } return false; } // delete the whole subtree starting from current directory bool DeleteNode(LPCTSTR szDir) { LOG_block("Delnode"); TCHAR szFilePath[MAX_PATH]; lstrcpy(szFilePath, szDir); PathAppend(szFilePath, TEXT("*.*")); // Find the first file WIN32_FIND_DATA fd; auto_hfindfile hFindFile = FindFirstFile(szFilePath, &fd); return_if_false(hFindFile.valid()); do { if ( !lstrcmpi(fd.cFileName, TEXT(".")) || !lstrcmpi(fd.cFileName, TEXT("..")) ) continue; // Make our path lstrcpy(szFilePath, szDir); PathAppend(szFilePath, fd.cFileName); if ((fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) || (fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ) { SetFileAttributes(szFilePath, FILE_ATTRIBUTE_NORMAL); } if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { return_if_false(DeleteNode(szFilePath)); } else { return_if_false(DeleteFile(szFilePath)); } } while (FindNextFile(hFindFile, &fd));// Find the next entry hFindFile.release(); return_if_false(RemoveDirectory(szDir)); return true; } void URLPingReport(IN SHelper& helper, IN LPCTSTR pszStatus) { srand((int)GetTickCount()); // build the URL with parameters TCHAR szURL[INTERNET_MAX_PATH_LENGTH]; _stprintf(szURL, _T("ident/wutrack.bin?PUID=%d&PLAT=%d&LOCALE=0x%08x&STATUS=%s&RID=%04x%04x"), helper.puid, helper.enPlatform, helper.dwLangID, pszStatus, rand(), rand()); byte_buffer bufTmp; helper.download.Copy(szURL, bufTmp); } //======================================================================= // // called by InternalQueryDetectionFiles() // //======================================================================= // helper to download to buffer and uncab is nessasary inline bool FileToBuffer(LPCTSTR szFileName, byte_buffer& buf) { auto_hfile hFile = CreateFile(szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (!hFile.valid()) return false; DWORD dwFileSize = GetFileSize(hFile, NULL); buf.resize(dwFileSize); if (!ReadFile(hFile, buf, dwFileSize, &dwFileSize, NULL)) return false; return true; } bool DownloadToBuffer( IN SHelper& helper, IN LPCTSTR szPath, OUT byte_buffer& bufOut ) { LOG_block("DownloadToBuffer"); // copy to local file to have a cached version TCHAR szTitle[MAX_PATH]; lstrcpy(szTitle, szPath); PathStripPath(szTitle); TCHAR szLocalPath[MAX_PATH]; GetWindowsUpdateDirectory(szLocalPath); PathAppend(szLocalPath, szTitle); if (helper.download.IsConnected()) { if (!helper.download.Copy(szPath, szLocalPath)) { LOG_error("download.Copy(%s) failed", szPath); return false; } } if (helper.diamond.IsValidCAB(szLocalPath)) { if (!helper.diamond.Decompress(szLocalPath, bufOut)) { LOG_error("diamond.Decompress(%s) failed", szPath); return false; } } else { //else the oem table is in uncompressed format. if (!FileToBuffer(szLocalPath, bufOut)) { LOG_error("FileToBuffer(%s) failed", szPath); SetLastError(ERROR_INVALID_FUNCTION); //we might not be ready yet return false; } } return true; } //======================================================================= // // called by DllMain() // //======================================================================= bool UpdateCdmDll() { LOG_block("UpdateCDMDll"); TCHAR szCurrentDll[MAX_PATH]; GetSystemDirectory(szCurrentDll, sizeOfArray(szCurrentDll)); PathAppend(szCurrentDll, CDMDLL); TCHAR szIUCdmDll[MAX_PATH]; GetSystemDirectory(szIUCdmDll, sizeOfArray(szCurrentDll)); PathAppend(szIUCdmDll, IUCDMDLL); TCHAR szCdmNewDll[MAX_PATH]; GetSystemDirectory(szCdmNewDll, sizeOfArray(szCdmNewDll)); PathAppend(szCdmNewDll, CDMNEWDLL); //To replace DLLs already loaded in memory on NT we can rename the file on //disk to a temp name and copy the new dll over the old disk file image. The //next time that the dll is loaded it will load the new image. // TCHAR szOldDll[MAX_PATH]; lstrcpy(szOldDll, szCurrentDll); lstrcat(szOldDll, _T(".old")); DeleteFile(szOldDll); if (!MoveFile(szCurrentDll, szOldDll)) { LOG_error("MoveFile(%s, %s) returns %d", szCurrentDll, szOldDll, GetLastError()); return false; } // // If iucdm.dll exists, rename it to cdm.dll, else rename cdmnew.dll to cdm.dll // if (!MoveFile(FileExists(szIUCdmDll) ? szIUCdmDll : szCdmNewDll, szCurrentDll)) { LOG_error("MoveFile(%s, %s) returns %d", szCdmNewDll, szCurrentDll, GetLastError()); MoveFile(szOldDll, szCurrentDll); // restore if update fails return false; } return true; } //Called by InternalLogDriverNotFound(...) //ASSUME: only runs in Whislter, not working on lower than W2k //called by InternalLogDriverNotFound() //Get SKU information in a string for running OS //return S_FALSE if no matching information found //return S_FALSE if buffer not big enough for possible return string //return E_FAIL if error happens, //return S_OK if success and the buffer will contain SKU string //lpSKUBuffer: IN : buffer to store SKU string. Allocated and freed by caller //dwSize: IN : size of lpSKUBuffer in bytes HRESULT GetSKUString( IN LPTSTR lpSKUBuffer, IN DWORD dwSize ) { enumSKU eSKU; OSVERSIONINFOEX osverEx; LOG_block("GetSKUString"); ZeroMemory(&osverEx, sizeof(osverEx)); osverEx.dwOSVersionInfoSize = sizeof(osverEx); if (!GetVersionEx((OSVERSIONINFO *) &osverEx)) { LOG_error("GetVersionEx failed"); return E_FAIL; } eSKU = SKU_NOT_SPECIFIED; if (VER_NT_SERVER == osverEx.wProductType) { if (osverEx.wSuiteMask & VER_SUITE_DATACENTER) { eSKU = SKU_DATACENTER_SERVER; } else { if (osverEx.wSuiteMask & VER_SUITE_ENTERPRISE) { eSKU = SKU_ADVANCED_SERVER; } else { eSKU = SKU_SERVER; } } } if (VER_NT_WORKSTATION == osverEx.wProductType) { if (osverEx.wSuiteMask & VER_SUITE_PERSONAL ) { eSKU = SKU_PERSONAL; } else { eSKU = SKU_PROFESSIONAL; } } if (dwSize < SKU_STRING_MIN_LENGTH) { LOG_error("buffer not big enough to store SKU information"); return S_FALSE; //buffer not big enough for possible return string } switch (eSKU) { case SKU_PERSONAL: case SKU_PROFESSIONAL: case SKU_SERVER: case SKU_ADVANCED_SERVER: case SKU_DATACENTER_SERVER: lstrcpy(lpSKUBuffer, SKU_STRINGS[eSKU]); break; default: //not specified LOG_error("Unrecognized SKU type"); lstrcpy(lpSKUBuffer, SKU_STRINGS[0]); return S_FALSE; } return S_OK; } //called by InternalDriverNotFound(...) //Find a file name not used so far into which hardware xml information will be inserted //The file name will be in format hardware_xxx.xml where xxx is in range [1..MAX_INDEX_TO_SEARCH] //The position file found last time is remembered and new search will start from the next position //Caller is supposed to close handle and delete file //tszDirPath IN : directory under which to look for unique file name. End with "\" //lpBuffer IN : allocated and freed by caller. Buffer to store unique file name found //dwSize IN : size of lpBuffer in bytes //hFile OUT: store a handle to the opened file //return S_OK if Unique File Name found //return S_FALSE if buffer not big enough to hold unique file name //return E_FAIL if all qualified file names already taken HRESULT GetUniqueFileName( IN LPTSTR tszDirPath, IN LPTSTR lpBuffer, IN DWORD dwSize, OUT HANDLE &hFile ) { TCHAR tszPath[MAX_PATH]; static DWORD dwFileIndex = 1; int nCount = 0; const TCHAR FILENAME[] = _T("Hardware_"); const TCHAR FILEEXT[] = _T("xml"); LOG_block("GetFileNameGenerator"); LOG_out("Directory to search unique file names: %s", tszDirPath); hFile = NULL; do { _stprintf(tszPath, _T("%s%s%d.%s"), tszDirPath, FILENAME, dwFileIndex, FILEEXT); LOG_out("check existing of %s", tszPath); hFile = CreateFile(tszPath, NULL, NULL, NULL, CREATE_NEW, NULL, NULL); if (INVALID_HANDLE_VALUE == hFile) { //file exists dwFileIndex ++; nCount ++; if (dwFileIndex > MAX_INDEX_TO_SEARCH) { dwFileIndex = 1; } } else { break; //first available file name found } }while(nCount < MAX_INDEX_TO_SEARCH ); if (nCount == MAX_INDEX_TO_SEARCH ) { LOG_out("All %d file names have been taken", nCount); return E_FAIL; } _stprintf(tszPath, _T("%s%d.%s"), FILENAME, dwFileIndex, FILEEXT); if (dwSize < (_tcslen(tszPath) + 1) * sizeof(TCHAR)) { LOG_out("buffer not big enough to hold unique file name"); CloseHandle(hFile); DeleteFile(tszPath); return S_FALSE; } lstrcpy(lpBuffer, tszPath); LOG_out("unique file name %s found", lpBuffer); dwFileIndex++; //next time skip file name found this time if (dwFileIndex > MAX_INDEX_TO_SEARCH) { dwFileIndex = 1; } return S_OK; } /* Called by InternalLogDriverNotFound(...) canonicalize a url resize tchBuf if not big enough lpszUrl: IN address of the string that contains the Url to canonicalize tchBuf : OUT buffer that receives the resulting canonicalized URL dwLen : IN size of the tchBuf dwFlags: IN any flag applicable to InternetCanonicalizeUrl(...) Return : S_OK if url canonicalization succeed E_FAIL if url canonicalization failed */ HRESULT CdmCanonicalizeUrl( IN LPCTSTR lpszUrl, OUT tchar_buffer &tchBuf, IN DWORD dwLen, IN DWORD dwFlags) { LOG_block("CdmCanonicalizeUrl"); BOOL fBufferResized = FALSE; while (!InternetCanonicalizeUrl(lpszUrl, (LPTSTR) tchBuf, &dwLen, dwFlags)) { if (fBufferResized || ERROR_INSUFFICIENT_BUFFER != GetLastError()) { LOG_error("InternetCanonicalizeUrl Failed "); return E_FAIL; } else { LOG_out("buffer resized"); tchBuf.resize((dwLen+1)); fBufferResized = TRUE; } } return S_OK; } //======================================================================= // // called internally // //======================================================================= // Check if given PNPID is current hash table mapping. //if PnpID is in hash table then return index ULONG IsInMap( IN PCDM_HASHTABLE pHashTable, //hash table to be used to check and see if item is available. IN LPCTSTR pHwID //hardware id to be retrieved ) { LOG_block("IsInMap"); if(NULL != pHwID && 0 != pHwID[0]) { ULONG ulTableEntry = CDM_HwID2Hash(pHwID, pHashTable->hdr.iTableSize); if(GETBIT(pHashTable->pData, ulTableEntry)) { LOG_out("%s (hash %d) is found", pHwID, ulTableEntry); return ulTableEntry; } else { LOG_error("%s (hash %d) is not found", pHwID, ulTableEntry); } } else { LOG_error("pHwID is empty"); } return -1; } //This method performs a logical AND operation between an array of bits and a bitmask bit array. inline void AndBitmasks( PBYTE pBitsResult, //result array for the AND operation PBYTE pBitMask, //source array bitmask int iMaskByteSize //bitmask size in bytes ) { for(int i=0; iiRecordSize+7)/8; bufOut.resize(iMaskByteSize); if (!bufOut.valid()) return false; memset(bufOut, 0xFF, iMaskByteSize); // Initial inventory // AndBitmasks(bufOut, pMask->GetBitMaskPtr(BITMASK_GLOBAL_INDEX), iMaskByteSize); //AND in OEM bitmask, we pick first hit since bitmasks are returned //from most specific to least specific. int nCurrentOEM = pMask->iOemCount; // out of range value { byte_buffer bufOEM; if (!DownloadToBuffer(helper, _T("oeminfo.bin"), bufOEM)) return false; DWORD dwOemId = GetMachinePnPID(bufOEM); if (0 != dwOemId) { for (int nOEM = 0; nOEM < pMask->iOemCount; nOEM++) { if (dwOemId == pMask->bmID[nOEM]) break; } nCurrentOEM = nOEM; } } int nBitmapIndex = (pMask->iOemCount == nCurrentOEM ? BITMASK_OEM_DEFAULT // if we did not find an OEM bitmask specific to this client then use the default OEM mask. : nCurrentOEM+2 // bitmask is offset from GLOBAL and DEFAULT bitmasks ); AndBitmasks(bufOut, pMask->GetBitMaskPtr(nBitmapIndex), iMaskByteSize); //And in LOCALE bitmask for(int iLocal = 0; iLocal < pMask->iLocaleCount; iLocal++) { if (pMask->bmID[pMask->iOemCount+iLocal] == helper.dwLangID) { //We need to add in the oem count to get to the first local AndBitmasks(bufOut, pMask->GetBitMaskPtr(pMask->iOemCount+iLocal+2), iMaskByteSize); return true; } } LOG_error("language %08X is not found", helper.dwLangID); return false; //locale is not found } ///////////////////////////////////////////////////////////////////////////////// // Variable field functions ///////////////////////////////////////////////////////////////////////////////// //The GetNext function returns a pointer to the next variable array item in a //variable chain. If the next variable item does not exit then this method //return NULL. PWU_VARIABLE_FIELD WU_VARIABLE_FIELD::GetNext( void ) { PWU_VARIABLE_FIELD pv; //walk though the varaible field array associated with this data item //and return the requested item or NULL if the item is not found. pv = this; if (pv->id == WU_VARIABLE_END) return NULL; pv = (PWU_VARIABLE_FIELD)((PBYTE)pv + pv->len); return pv; } //find a variable item in a variable item chain. PWU_VARIABLE_FIELD WU_VARIABLE_FIELD::Find( short id //id of variable size field to search for in the variable size chain. ) { LOG_block("WU_VARIABLE_FIELD::Find"); PWU_VARIABLE_FIELD pv; //walk though the varaible field array associated with this data item //and return the requested item or NULL if the item is not found. pv = this; //If this variable record only contains an end record then we //need to handle it specially since the normal find loop //updates the pv pointer before the end check is made so if //end is the first field it can be missed. if (pv->id == WU_VARIABLE_END) return (id == WU_VARIABLE_END) ? pv : (PWU_VARIABLE_FIELD)NULL; do { if (pv->id == id) return pv; pv = (PWU_VARIABLE_FIELD)((PBYTE)pv + pv->len); } while(pv->id != WU_VARIABLE_END); //case where caller asked to search for the WU_VARIABLE_END field if (pv->id == id) return pv; return (PWU_VARIABLE_FIELD)NULL; } //Variable size field constructor. WU_VARIABLE_FIELD::WU_VARIABLE_FIELD( void ) { id = WU_VARIABLE_END; len = sizeof(id) + sizeof(len); } //returns the total size of a variable field int WU_VARIABLE_FIELD::GetSize( void ) { PWU_VARIABLE_FIELD pv; int iSize; iSize = 0; pv = this; while(pv->id != WU_VARIABLE_END) { iSize += pv->len; pv = (PWU_VARIABLE_FIELD)((PBYTE)pv + pv->len); } iSize += pv->len; return iSize; } static bool FilesIdentical( IN LPCTSTR szFileName1, IN LPCTSTR szFileName2 ) { auto_hfile hFile1 = CreateFile(szFileName1, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (!hFile1.valid()) return false; auto_hfile hFile2 = CreateFile(szFileName2, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (!hFile2.valid()) return false; if(GetFileSize(hFile1, NULL) != GetFileSize(hFile2, NULL)) return false; FILETIME ft1; if (!GetFileTime(hFile1, NULL, NULL, &ft1)) return false; FILETIME ft2; if (!GetFileTime(hFile2, NULL, NULL, &ft2)) return false; return CompareFileTime(&ft1, &ft2) == 0; }