windows-nt/Source/XPSP1/NT/enduser/windows.com/wuv3/cdm/cdmp.cpp

2089 lines
54 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//=======================================================================
//
// 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 <windows.h>
#include <osdet.h>
#include <setupapi.h>
#include <shlwapi.h>
#include <softpub.h>
#include <ras.h>
#include <regstr.h>
#include <tchar.h>
#include <atlconv.h>
#include <winver.h>
#include <wustl.h>
#include <log.h>
#include <wuv3cdm.h>
#include <bucket.h>
#include <findoem.h>
#include <DrvInfo.h>
#include <newtrust.h>
#include <download.h>
#include <diamond.h>
#include <mscat.h>
#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; i<iMaskByteSize; i++)
pBitsResult[i] &= pBitMask[i];
}
bool GetOEMandLocalBitmask(
IN SHelper& helper,
OUT byte_buffer& bufOut
) {
LOG_block("GetOEMandLocalBitmask");
TCHAR szPath[MAX_PATH];
wsprintf(szPath, _T("%d/bitmask.cdm"), helper.puidCatalog);
byte_buffer bufBitmask;
if (!DownloadToBuffer(helper, szPath, bufBitmask))
return false;
PBITMASK pMask = (PBITMASK)(LPBYTE)bufBitmask;
int iMaskByteSize = (pMask->iRecordSize+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;
}