2089 lines
54 KiB
C++
2089 lines
54 KiB
C++
|
//=======================================================================
|
||
|
//
|
||
|
// 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;
|
||
|
|
||
|
}
|