windows-nt/Source/XPSP1/NT/enduser/windows.com/lib/urlagent/urlagent.cpp
2020-09-26 16:20:57 +08:00

1306 lines
33 KiB
C++

//***********************************************************************************
//
// Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
//
// File: UrlAgent.cpp
//
// Description:
//
// This class encapsulates the logic about where to get the right logic
// for various purposes, including the case of running WU in corporate
// environments.
//
// An object based on this class should be created first, then call
// GetOriginalIdentServer() function to get where to download ident,
// then download ident, then call PopulateData() function to read
// all URL related data.
//
// Created by:
// Charles Ma
//
// Date Creatd:
// Oct 19, 2001
//
//***********************************************************************************
#include <windows.h>
#include <iucommon.h>
#include <osdet.h>
#include <logging.h>
#include <fileUtil.h>
#include <memutil.h>
#include <shlwapi.h>
#include <UrlAgent.h>
#include <MISTSAFE.h>
#include <wusafefn.h>
#ifndef INTERNET_MAX_URL_LENGTH
#define INTERNET_MAX_URL_LENGTH 2200
#endif
//
// starting size of url array
//
const int C_INIT_URL_ARRAY_SIZE = 4; // for time being,we only have this many clients
//
// define the default original ident url
//
const TCHAR C_DEFAULT_IDENT_URL[] = _T("http://windowsupdate.microsoft.com/v4/");
//
// define reg keys to get ident server override for debugging
//
const TCHAR REGKEY_IDENT_SERV[] = _T("IdentServer");
const TCHAR REGKEY_IUCTL[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\IUControl");
const TCHAR REGVAL_ISBETA[] = _T("IsBeta");
//
// define reg keys used by related policies
//
//
// define policy location
//
const TCHAR REGKEY_CORPWU_POLICY[] = _T("Software\\Policies\\Microsoft\\Windows\\WindowsUpdate");
//
// define ident and selfupdate server, and ping server
//
const TCHAR REGKEY_CORPWU_WUSERVER[] = _T("WUServer");
const TCHAR REGKEY_CORPWU_PINGSERVER[] = _T("WUStatusServer");
//
// define the boolean (DWORD) value under each client
//
const TCHAR REGKEY_USEWUSERVER[] = _T("UseWUServer");
//
// define ident data
//
const TCHAR IDENT_SECTION_PINGSERVER[] = _T("IUPingServer"); // section name in ident
const TCHAR IDENT_ENTRY_SERVERURL[] = _T("ServerUrl"); // ping server entry name
const TCHAR IDENT_SECITON_IUSERVERCACHE[] = _T("IUServerCache"); // query server section
const TCHAR IDENT_ENTRY_QUERYSEVERINDEX[] = _T("QueryServerIndex"); // suffix of client entry
const TCHAR IDENT_ENTRY_BETAQUERYSERVERINDEX[] = _T("BetaQueryServerIndex"); // for beta server
const TCHAR IDENT_ENTRY_SERVER[] = _T("Server"); // prefix of server entry
// main IU selfupdate keys
const TCHAR IDENT_IUSELFUPDATE[] = _T("IUSelfUpdate");
const TCHAR IDENT_IUBETASELFUPDATE[] = _T("IUBetaSelfUpdate");
const TCHAR IDENT_STRUCTUREKEY[] = _T("StructureKey");
// IU selfupdate architecture flags
const TCHAR IDENT_ARCH[] = _T("ARCH");
const TCHAR IDENT_OS[] = _T("OS");
const TCHAR IDENT_LOCALE[] = _T("LOCALE");
const TCHAR IDENT_CHARTYPE[] = _T("CHARTYPE");
// IU selfupdate sections
const TCHAR IDENT_IUARCH[] = _T("IUArch");
const TCHAR IDENT_IUOS[] = _T("IUOS");
const TCHAR IDENT_IULOCALE[] = _T("IULocale");
const TCHAR IDENT_IUCHARTYPE[] = _T("IUCharType");
// IU selfupdate arch keys
const TCHAR IDENT_X86[] = _T("x86");
const TCHAR IDENT_IA64[] = _T("ia64");
// IU selfupdate chartypes
const TCHAR IDENT_ANSI[] = _T("ansi");
const TCHAR IDENT_UNICODE[] = _T("unicode");
const TCHAR SLASHENGINECAB[] = _T("/iuengine.cab");
// AU specific:
const TCHAR CLIENT_AU[] = _T("AU");
const TCHAR CLIENT_AU_DRIVER[] = _T("AUDriver");
// *********************************************************************
//
// begin of class implementation
//
// *********************************************************************
CUrlAgent::CUrlAgent(void)
: m_fPopulated(FALSE),
m_pszOrigIdentUrl(NULL),
m_pszInternetPingUrl(NULL),
m_pszIntranetPingUrl(NULL),
m_pszWUServer(NULL),
m_ArrayUrls(NULL),
m_nArrayUrlCount(0),
m_nArraySize(0),
m_nOrigIdentUrlBufSize(0),
m_fIdentFromPolicy(FALSE)
{
HKEY hKey = NULL;
DWORD dwRegCheckResult = 0;
DWORD dwSize = 0, dwType, dwValue;
LOG_Block("CUrlAgent::CUrlAgent()");
//
// always try to get original ident server url
//
m_hProcHeap = GetProcessHeap();
if (NULL != m_hProcHeap)
{
m_nOrigIdentUrlBufSize = __max(
MAX_PATH, // reg based?
sizeof(C_DEFAULT_IDENT_URL)/sizeof(TCHAR)); // default
m_pszOrigIdentUrl = (LPTSTR)
HeapAlloc(
m_hProcHeap, // allocate from process heap
HEAP_ZERO_MEMORY,
sizeof(TCHAR) * m_nOrigIdentUrlBufSize);
if (NULL != m_pszOrigIdentUrl)
{
//
// first, check to see if there is debug override
//
dwRegCheckResult= RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, 0, KEY_READ, &hKey);
if (ERROR_SUCCESS == dwRegCheckResult)
{
dwSize = sizeof(TCHAR) * m_nOrigIdentUrlBufSize;
dwRegCheckResult = RegQueryValueEx(hKey, REGKEY_IDENT_SERV, NULL, &dwType, (LPBYTE)m_pszOrigIdentUrl, &dwSize);
if (ERROR_SUCCESS == dwRegCheckResult)
{
if (REG_SZ == dwType)
{
LOG_Internet(_T("Found debugging Ident-URL %s"), m_pszOrigIdentUrl);
}
else
{
dwRegCheckResult = ERROR_SUCCESS + 1; // any error number will do
}
}
RegCloseKey(hKey);
}
if (ERROR_SUCCESS != dwRegCheckResult)
{
//
// if there is no debug override, check to see if there is policy define
// ident server for corporate case
//
dwRegCheckResult= RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_CORPWU_POLICY, 0, KEY_READ, &hKey);
if (ERROR_SUCCESS == dwRegCheckResult)
{
dwSize = sizeof(TCHAR) * m_nOrigIdentUrlBufSize;
dwRegCheckResult = RegQueryValueEx(hKey, REGKEY_CORPWU_WUSERVER, NULL, &dwType, (LPBYTE)m_pszOrigIdentUrl, &dwSize);
if (ERROR_SUCCESS == dwRegCheckResult && REG_SZ == dwType)
{
m_fIdentFromPolicy = TRUE;
//
// for any client that its name appear here as a subkey, and
// has a value "UseWUServer" set to 1 under the subkey, then
// this will also be the base url used to construct the query url
// for that client
//
m_pszWUServer = m_pszOrigIdentUrl;
LOG_Internet(_T("Found corp Ident-URL %s"), m_pszOrigIdentUrl);
//
// since we found wu server, for any client uses this url,
// we can also have an optional ping server
//
m_pszIntranetPingUrl = (LPTSTR) HeapAlloc(
m_hProcHeap,
HEAP_ZERO_MEMORY,
sizeof(TCHAR) * m_nOrigIdentUrlBufSize);
dwSize = sizeof(TCHAR) * m_nOrigIdentUrlBufSize;
if (NULL != m_pszIntranetPingUrl)
{
if (ERROR_SUCCESS != (dwRegCheckResult = RegQueryValueEx(hKey, REGKEY_CORPWU_PINGSERVER, NULL, &dwType, (LPBYTE)m_pszIntranetPingUrl, &dwSize)) || REG_SZ != dwType)
{
StringCchCopyEx(m_pszIntranetPingUrl,m_nOrigIdentUrlBufSize,m_pszOrigIdentUrl,NULL,NULL,MISTSAFE_STRING_FLAGS);
dwRegCheckResult = ERROR_SUCCESS;
}
}
}
else
{
dwRegCheckResult = ERROR_SUCCESS + 1; // any error number will do
}
RegCloseKey(hKey);
}
}
if (ERROR_SUCCESS != dwRegCheckResult)
{
//
// not debugging , neither corporate policy found
//
StringCchCopyEx(m_pszOrigIdentUrl,m_nOrigIdentUrlBufSize,C_DEFAULT_IDENT_URL,NULL,NULL,MISTSAFE_STRING_FLAGS);
LOG_Internet(_T("Use default ident URL %s"), m_pszOrigIdentUrl);
}
}
}
else
{
LOG_ErrorMsg(GetLastError());
}
//
// Check IUControl Reg Key for Beta Mode
//
m_fIsBetaMode = FALSE;
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, &hKey))
{
dwValue = 0;
dwSize = sizeof(dwValue);
if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGVAL_ISBETA, NULL, NULL, (LPBYTE)&dwValue, &dwSize))
{
m_fIsBetaMode = (1 == dwValue);
}
RegCloseKey(hKey);
}
}
CUrlAgent::~CUrlAgent(void)
{
DesertData();
SafeHeapFree(m_pszOrigIdentUrl);
SafeHeapFree(m_pszIntranetPingUrl);
}
//------------------------------------------------------------------------
//
// this function should be called after you downloaded ident, and get
// a fresh copy of ident text file from the cab, after verifying cab was
// signed properly.
//
// this function reads data from ident and registry
//
//------------------------------------------------------------------------
HRESULT CUrlAgent::PopulateData(void)
{
LOG_Block("CUrlAgent::PopuldateData");
if (m_fPopulated)
return S_OK;
HRESULT hr = S_OK;
LPTSTR pszBuffer = NULL;
LPTSTR pszCurrentKey = NULL; // ptr only, no memory alloc
LPTSTR pszUrlBuffer = NULL;
LPCTSTR pcszSuffix = (m_fIsBetaMode ? IDENT_ENTRY_BETAQUERYSERVERINDEX : IDENT_ENTRY_QUERYSEVERINDEX);
HKEY hKey = NULL;
DWORD dwRegCheckResult = 0;
DWORD dwSize = 0,
dwType,
dwValue = 0;
int iLen = 0, iLenSuffix = 0;
TCHAR szIdentBuffer[MAX_PATH + 1];
TCHAR szIdentFile[MAX_PATH + 1];
if (NULL == m_hProcHeap)
{
return E_FAIL;
}
pszUrlBuffer = (LPTSTR) HeapAlloc(m_hProcHeap, HEAP_ZERO_MEMORY, sizeof(TCHAR)*INTERNET_MAX_URL_LENGTH);
CleanUpFailedAllocSetHrMsg(pszUrlBuffer);
GetIndustryUpdateDirectory(szIdentBuffer);
hr=PathCchCombine(szIdentFile,ARRAYSIZE(szIdentFile), szIdentBuffer, IDENTTXT);
if(FAILED(hr))
{
SafeHeapFree(pszUrlBuffer);
LOG_ErrorMsg(hr);
return hr;
}
//
// make sure we release all data, if any
//
DesertData();
//
// before populate per-client array, we want to find out inter net ping server
//
m_pszInternetPingUrl = RetrieveIdentStrAlloc(
IDENT_SECTION_PINGSERVER,
IDENT_ENTRY_SERVERURL,
NULL,
szIdentFile);
//
// allocate array of pointers for storing each server node
//
m_ArrayUrls = (PServerPerClient) HeapAlloc(m_hProcHeap, HEAP_ZERO_MEMORY, C_INIT_URL_ARRAY_SIZE * sizeof(ServerPerClient));
CleanUpFailedAllocSetHrMsg(m_ArrayUrls);
m_nArraySize = C_INIT_URL_ARRAY_SIZE; // now array is this big
//
// try to read data from policy first, if WU server exists
//
if (NULL != m_pszWUServer &&
ERROR_SUCCESS == (dwRegCheckResult= RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_CORPWU_POLICY, 0, KEY_READ, &hKey)))
{
//
// the way we find a client name under WU policy is, to open this key, see if it has a value
// called "UseWUServer"
//
DWORD dwSubKeyIndex = 0;
TCHAR szKeyName[32];
while (TRUE)
{
DWORD dwKeyBufLen = ARRAYSIZE(szKeyName);
dwRegCheckResult = RegEnumKeyEx(
hKey, // handle to key to enumerate
dwSubKeyIndex, // subkey index
szKeyName, // subkey name
&dwKeyBufLen, // size of subkey buffer
NULL, // reserved
NULL, // class string buffer
NULL, // size of class string buffer
NULL // last write time
);
if (ERROR_SUCCESS == dwRegCheckResult)
{
//
// try to open this key
//
HKEY hKeyClient = NULL;
dwRegCheckResult= RegOpenKeyEx(hKey, szKeyName, 0, KEY_READ, &hKeyClient);
if (ERROR_SUCCESS == dwRegCheckResult)
{
//
// try to see if it has a value called UseWUServer
//
dwValue = 0;
dwType = REG_DWORD;
dwSize = sizeof(dwValue);
dwRegCheckResult = RegQueryValueEx(hKeyClient, REGKEY_USEWUSERVER, NULL, &dwType, (LPBYTE) &dwValue, &dwSize);
if (ERROR_SUCCESS == dwRegCheckResult && REG_DWORD == dwType && 0x1 == dwValue)
{
LOG_Internet(_T("Found client %s\\UseWUServer=1"), szKeyName);
//
// we want to add this client to our url array
//
CleanUpIfFailedAndSetHrMsg(ExpandArrayIfNeeded());
m_ArrayUrls[m_nArrayUrlCount].pszClientName = (LPTSTR)HeapAllocCopy(szKeyName, sizeof(TCHAR) * (lstrlen(szKeyName) + 1));
CleanUpFailedAllocSetHrMsg(m_ArrayUrls[m_nArrayUrlCount].pszClientName);
m_ArrayUrls[m_nArrayUrlCount].pszQueryServer = (LPTSTR) HeapAllocCopy(m_pszOrigIdentUrl, sizeof(TCHAR) * (lstrlen(m_pszOrigIdentUrl) + 1));
CleanUpFailedAllocSetHrMsg(m_ArrayUrls[m_nArrayUrlCount].pszQueryServer);
m_ArrayUrls[m_nArrayUrlCount].fInternalServer = TRUE;
m_nArrayUrlCount++; // increase counter by 1
//
// BUG 507500 AUDriver Policy -
// map calls with the "AUDriver client to "AU" when checking the policy for usewuserver
//
if (CSTR_EQUAL == WUCompareStringI(szKeyName, CLIENT_AU))
{
//
// we want to add client "AUDriver" to our url array
//
CleanUpIfFailedAndSetHrMsg(ExpandArrayIfNeeded());
m_ArrayUrls[m_nArrayUrlCount].pszClientName = (LPTSTR)HeapAllocCopy((LPTSTR)CLIENT_AU_DRIVER, sizeof(TCHAR) * (lstrlen(CLIENT_AU_DRIVER) + 1));
CleanUpFailedAllocSetHrMsg(m_ArrayUrls[m_nArrayUrlCount].pszClientName);
m_ArrayUrls[m_nArrayUrlCount].pszQueryServer = (LPTSTR) HeapAllocCopy(m_pszOrigIdentUrl, sizeof(TCHAR) * (lstrlen(m_pszOrigIdentUrl) + 1));
CleanUpFailedAllocSetHrMsg(m_ArrayUrls[m_nArrayUrlCount].pszQueryServer);
m_ArrayUrls[m_nArrayUrlCount].fInternalServer = TRUE;
m_nArrayUrlCount++; // increase counter by 1
}
}
}
RegCloseKey(hKeyClient);
}
else
{
if (ERROR_NO_MORE_ITEMS == dwRegCheckResult)
{
//
// there is no more sub key to loop through. get out here
//
break;
}
//
// otherwise, we try next sub key
//
}
dwSubKeyIndex++; // try next sub key
}
RegCloseKey(hKey); // done with policy reg
}
//
// now we should continue to work on internet case
// that is, to retrieve query server(s) from ident
//
dwSize = MAX_PATH;
pszBuffer = (LPTSTR) HeapAlloc(m_hProcHeap, HEAP_ZERO_MEMORY, dwSize * sizeof(TCHAR));
while (NULL != pszBuffer &&
GetPrivateProfileString(
IDENT_SECITON_IUSERVERCACHE,
NULL,
_T(""),
pszBuffer,
dwSize,
szIdentFile) == dwSize-2)
{
//
// buffer too small?
//
dwSize *= 2;
LPTSTR pszTemp = (LPTSTR) HeapReAlloc(m_hProcHeap, HEAP_ZERO_MEMORY, pszBuffer, dwSize * sizeof(TCHAR));
if (NULL != pszTemp)
{
pszBuffer = pszTemp;
}
else
{
//
// HeapReAlloc failed, bail from while with origional allocation freed
//
SafeHeapFree(pszBuffer);
}
}
CleanUpFailedAllocSetHrMsg(pszBuffer);
//
// loop through each key
//
pszCurrentKey = pszBuffer;
while ('\0' != *pszCurrentKey)
{
//
// for the current key, we first try to see if its index key or server key
// if it's not index key, skip it
//
iLen = lstrlen(pszCurrentKey);
iLenSuffix = lstrlen(pcszSuffix);
if ((iLen > iLenSuffix) && (0 == StrCmpI((pszCurrentKey + (iLen - iLenSuffix)), pcszSuffix)))
{
TCHAR szClient[MAX_PATH]; // isn't MAX_PATH big enough?
int nIndex = 0;
BOOL fExist = FALSE;
//
// retrieve server index from this key
//
nIndex = GetPrivateProfileInt(IDENT_SECITON_IUSERVERCACHE, pszCurrentKey, 0, szIdentFile);
//
// no use of szIdentBuffer, so utilize it here
//
CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szIdentBuffer,ARRAYSIZE(szIdentBuffer),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("%s%d"), IDENT_ENTRY_SERVER, nIndex));
GetPrivateProfileString(
IDENT_SECITON_IUSERVERCACHE,
szIdentBuffer, // use current str as key
_T(""),
pszUrlBuffer,
INTERNET_MAX_URL_LENGTH,
szIdentFile);
if ('0' != *pszUrlBuffer)
{
//
// this is an index key!
// try to extract client name from this key
//
CleanUpIfFailedAndSetHrMsg(StringCchCopyNEx(szClient,ARRAYSIZE(szClient),pszCurrentKey,iLen - iLenSuffix,NULL,NULL,MISTSAFE_STRING_FLAGS));
//
// find out if this client is already defined in policy and therefore
// arleady got data in the url array
//
for (int i = 0; i < m_nArrayUrlCount && !fExist; i++)
{
fExist= (StrCmpI(m_ArrayUrls[i].pszClientName, szClient) == 0);
}
if (!fExist)
{
CleanUpIfFailedAndSetHrMsg(ExpandArrayIfNeeded());
m_ArrayUrls[m_nArrayUrlCount].pszClientName = (LPTSTR)HeapAllocCopy(szClient, sizeof(TCHAR) * (lstrlen(szClient) + 1));
CleanUpFailedAllocSetHrMsg(m_ArrayUrls[m_nArrayUrlCount].pszClientName);
m_ArrayUrls[m_nArrayUrlCount].pszQueryServer = (LPTSTR) HeapAllocCopy(pszUrlBuffer, sizeof(TCHAR) * (lstrlen(pszUrlBuffer) + 1));
CleanUpFailedAllocSetHrMsg(m_ArrayUrls[m_nArrayUrlCount].pszQueryServer);
m_ArrayUrls[m_nArrayUrlCount].fInternalServer = FALSE;
m_nArrayUrlCount++; // increase counter by 1
}
else
{
//
// this client is already defined in policy, we just need to append the QueryServer with the
// rest of the url path defined in iuident
//
LPTSTR pszPath = NULL;
//
// find "//" in URL retrieved from iuident
//
if (NULL == (pszPath = StrStrI(pszUrlBuffer, _T("//"))))
{
// unexpected error
hr = E_FAIL;
LOG_ErrorMsg(hr);
goto CleanUp;
}
else
{
//
// find next "/" in URL retrieved from iuident
//
if (NULL != (pszPath = StrStrI(pszPath+2, _T("/"))))
{
DWORD dwLen = 0;
LPTSTR pszTemp = NULL;
//
// remove trailing "/" in URL retrieved from policy
//
if (_T('/') == *(m_ArrayUrls[i-1].pszQueryServer + lstrlen(m_ArrayUrls[i-1].pszQueryServer) - 1))
{
dwLen = lstrlen(m_ArrayUrls[i-1].pszQueryServer) + lstrlen(pszPath);
pszTemp = (LPTSTR)HeapReAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
m_ArrayUrls[i-1].pszQueryServer,
sizeof(TCHAR) * dwLen);
CleanUpFailedAllocSetHrMsg(pszTemp);
m_ArrayUrls[i-1].pszQueryServer = pszTemp;
hr=StringCchCatEx(m_ArrayUrls[i-1].pszQueryServer,dwLen,pszPath + 1,NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr))
{
LOG_ErrorMsg(hr);
SafeHeapFree(pszTemp);
m_ArrayUrls[i-1].pszQueryServer=NULL;
}
}
else
{
dwLen = lstrlen(m_ArrayUrls[i-1].pszQueryServer) + lstrlen(pszPath) + 1;
pszTemp = (LPTSTR)HeapReAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
m_ArrayUrls[i-1].pszQueryServer,
sizeof(TCHAR) * dwLen);
CleanUpFailedAllocSetHrMsg(pszTemp);
m_ArrayUrls[i-1].pszQueryServer = pszTemp;
hr=StringCchCatEx(m_ArrayUrls[i-1].pszQueryServer,dwLen,pszPath,NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr))
{
LOG_ErrorMsg(hr);
SafeHeapFree(pszTemp);
m_ArrayUrls[i-1].pszQueryServer=NULL;
}
}
}
}
}
}
}
//
// move to next string
//
pszCurrentKey += lstrlen(pszCurrentKey) + 1;
}
CleanUp:
if (FAILED(hr))
{
//
// clean up half-way populated data
//
DesertData();
}
else
{
m_fPopulated = TRUE;
}
SafeHeapFree(pszBuffer);
SafeHeapFree(pszUrlBuffer);
return hr;
}
//------------------------------------------------------------------------
//
// get the original ident server.
// *** this API should be called before PopulateData() is called ***
// *** this API should be called to retrieve the base URL where you download ident ***
//
//------------------------------------------------------------------------
HRESULT CUrlAgent::GetOriginalIdentServer(
LPTSTR lpsBuffer,
int nBufferSize,
BOOL* pfInternalServer /*= NULL*/)
{
HRESULT hr=S_OK;
if (NULL == lpsBuffer)
{
return E_INVALIDARG;
}
nBufferSize/=sizeof(TCHAR);
if (nBufferSize <= lstrlen(m_pszOrigIdentUrl))
{
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
hr=StringCchCopyEx(lpsBuffer,nBufferSize,m_pszOrigIdentUrl,NULL,NULL,MISTSAFE_STRING_FLAGS);
if( FAILED(hr) )
{
return hr;
}
if (NULL != pfInternalServer)
{
*pfInternalServer = m_fIdentFromPolicy;
}
return S_OK;
}
//------------------------------------------------------------------------
//
// get the ping/status server
// *** this API should be called after PopulateData() is called ***
//
//------------------------------------------------------------------------
HRESULT CUrlAgent::GetLivePingServer(
LPTSTR lpsBuffer,
int nBufferSize)
{
HRESULT hr=S_OK;
if (!m_fPopulated)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
if (NULL == lpsBuffer || 0 >= nBufferSize)
{
return E_INVALIDARG;
}
nBufferSize/=sizeof(TCHAR);
if (NULL != m_pszInternetPingUrl &&
_T('\0') != *m_pszInternetPingUrl)
{
if (nBufferSize <= lstrlen(m_pszInternetPingUrl))
{
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
else
{
hr=StringCchCopyEx(lpsBuffer,nBufferSize,m_pszInternetPingUrl,NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr))
return hr;
}
}
else
{
*lpsBuffer = _T('\0');
}
return S_OK;
}
// *** this API can be called before PopulateData() is called ***
HRESULT CUrlAgent::GetCorpPingServer(
LPTSTR lpsBuffer,
int nBufferSize)
{
HRESULT hr=S_OK;
if (NULL == m_pszIntranetPingUrl)
{
return (E_OUTOFMEMORY);
}
if (NULL == lpsBuffer || 0 >= nBufferSize)
{
return E_INVALIDARG;
}
nBufferSize/=sizeof(TCHAR);
if (NULL != m_pszIntranetPingUrl &&
_T('\0') != *m_pszIntranetPingUrl)
{
if (nBufferSize <= lstrlen(m_pszIntranetPingUrl))
{
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
else
{
hr=StringCchCopyEx(lpsBuffer,nBufferSize,m_pszIntranetPingUrl,NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr))
return hr;
}
}
else
{
*lpsBuffer = _T('\0');
}
return hr;
}
//------------------------------------------------------------------------
//
// get the query server. this is per client based
// *** this API should be called after PopulateData() is called ***
//
//------------------------------------------------------------------------
HRESULT CUrlAgent::GetQueryServer(
LPCTSTR lpsClientName,
LPTSTR lpsBuffer,
int nBufferSize,
BOOL* pfInternalServer /*= NULL*/)
{
HRESULT hr=S_OK;
if (!m_fPopulated)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
if (NULL == lpsClientName || NULL == lpsBuffer)
{
return E_INVALIDARG;
}
nBufferSize/=sizeof(TCHAR);
for (int i = 0; i < m_nArrayUrlCount; i++)
{
if (StrCmpI(m_ArrayUrls[i].pszClientName, lpsClientName) == 0)
{
if (nBufferSize <= lstrlen(m_ArrayUrls[i].pszQueryServer))
{
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
else
{
hr=StringCchCopyEx(lpsBuffer,nBufferSize,m_ArrayUrls[i].pszQueryServer,NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr)) return hr;
if (NULL != pfInternalServer)
{
*pfInternalServer = m_ArrayUrls[i].fInternalServer;
}
}
return S_OK;
}
}
return ERROR_IU_QUERYSERVER_NOT_FOUND;
}
//------------------------------------------------------------------------
//
// tell if a particular client is controlled by policy in corporate
// returns:
// S_OK = TRUE
// S_FALSE = FALSE
// other = error, so don't know
//
//------------------------------------------------------------------------
HRESULT CUrlAgent::IsClientSpecifiedByPolicy(
LPCTSTR lpsClientName
)
{
HRESULT hr=S_OK;
if (!m_fPopulated)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
if (NULL == lpsClientName)
{
return E_INVALIDARG;
}
for (int i = 0; i < m_nArrayUrlCount; i++)
{
if (StrCmpI(m_ArrayUrls[i].pszClientName, lpsClientName) == 0)
{
return (m_ArrayUrls[i].fInternalServer) ? S_OK : S_FALSE;
}
}
return S_FALSE;
}
HRESULT CUrlAgent::IsIdentFromPolicy()
{
return TRUE == m_fIdentFromPolicy ? S_OK : S_FALSE;
}
//------------------------------------------------------------------------
//
// private function, to clean up. called by destructor
//
//------------------------------------------------------------------------
void CUrlAgent::DesertData(void)
{
LOG_Block("CUrlAgent::DesertData");
if (NULL != m_ArrayUrls && m_nArrayUrlCount > 0)
{
for (int i = 0; i < m_nArrayUrlCount; i++)
{
SafeHeapFree(m_ArrayUrls[i].pszClientName);
SafeHeapFree(m_ArrayUrls[i].pszQueryServer);
}
SafeHeapFree(m_ArrayUrls);
m_nArrayUrlCount = 0;
m_nArraySize = 0;
}
SafeHeapFree(m_pszInternetPingUrl);
m_fPopulated = FALSE;
}
//------------------------------------------------------------------------
//
// private function, retrieve string from ident
// allocated memory will be multiple of MAX_PATH long.
//
//------------------------------------------------------------------------
LPTSTR CUrlAgent::RetrieveIdentStrAlloc(
LPCTSTR pSection,
LPCTSTR pEntry,
LPDWORD lpdwSizeAllocated,
LPCTSTR lpszIdentFile)
{
LPTSTR pBuffer = NULL;
DWORD dwSize = MAX_PATH;
DWORD dwRet = 0;
TCHAR szIdentFile[MAX_PATH + 1];
if (NULL == pSection || NULL == pEntry || NULL == lpszIdentFile)
{
return NULL;
}
//
// try to allocate buffer first
//
while (TRUE)
{
pBuffer = (LPTSTR) HeapAlloc(m_hProcHeap, HEAP_ZERO_MEMORY, sizeof(TCHAR) * dwSize);
if (NULL == pBuffer)
{
break;
}
dwRet = GetPrivateProfileString(
pSection,
pEntry,
_T(""),
pBuffer,
dwSize,
lpszIdentFile);
if (dwSize - 1 != dwRet)
{
if ('\0' == pBuffer)
{
//
// no such data found from ident!
//
SafeHeapFree(pBuffer);
}
//
// we are done!
//
break;
}
//
// assume it's buffer too small
//
SafeHeapFree(pBuffer);
dwSize += MAX_PATH; // increase by 255
}
if (NULL != lpdwSizeAllocated)
{
*lpdwSizeAllocated = dwSize;
}
return pBuffer;
}
//------------------------------------------------------------------------
//
// helper function
// if there is no empty slot, double the size of url array
//
//------------------------------------------------------------------------
HRESULT CUrlAgent::ExpandArrayIfNeeded(void)
{
HRESULT hr = S_OK;
LOG_Block("CUrlAgent::ExpandArrayIfNeeded()");
if (m_nArrayUrlCount >= m_nArraySize)
{
//
// we have used up all data slots. need to expand array
//
m_nArraySize *= 2;
PServerPerClient pNewArray = (PServerPerClient) HeapAlloc(m_hProcHeap, HEAP_ZERO_MEMORY, m_nArraySize * sizeof(ServerPerClient));
if (NULL == pNewArray)
{
m_nArraySize /= 2; // shrink it back
SetHrMsgAndGotoCleanUp(E_OUTOFMEMORY);
}
//
// copy old data to this new array
//
for (int i = 0; i < m_nArrayUrlCount; i++)
{
pNewArray[i] = m_ArrayUrls[i];
}
HeapFree(m_hProcHeap, 0, m_ArrayUrls);
m_ArrayUrls = pNewArray;
}
CleanUp:
return hr;
}
// *********************************************************************
//
// begin of derived class implementation
//
// *********************************************************************
CIUUrlAgent::CIUUrlAgent()
: m_fIUPopulated(FALSE),
m_pszSelfUpdateUrl(NULL)
{
if (m_fIdentFromPolicy)
{
//
// since we found wu server, set selfupdate url to it
//
m_pszSelfUpdateUrl = (LPTSTR) HeapAlloc(
m_hProcHeap,
HEAP_ZERO_MEMORY,
sizeof(TCHAR) * m_nOrigIdentUrlBufSize);
if (NULL != m_pszSelfUpdateUrl)
{
//No check is made for the return value since this is a constructor and failure codes cannot be returned
StringCchCopyEx(m_pszSelfUpdateUrl,m_nOrigIdentUrlBufSize,m_pszOrigIdentUrl,NULL,NULL,MISTSAFE_STRING_FLAGS);
}
}
}
CIUUrlAgent::~CIUUrlAgent()
{
m_fIUPopulated = FALSE;
SafeHeapFree(m_pszSelfUpdateUrl);
}
//------------------------------------------------------------------------
//
// PopulateData():
// Do base class PopulateData() and then populate self-update url
//
//------------------------------------------------------------------------
HRESULT CIUUrlAgent::PopulateData(void)
{
LOG_Block("CIUUrlAgent::PopulateData");
if (m_fIUPopulated)
return S_OK;
HRESULT hr = ((CUrlAgent*)this)->PopulateData();
if (FAILED(hr))
return hr;
//
// we need to populate the self-update url from iuident if wu server is not present
//
if (!m_fIdentFromPolicy)
{
if (NULL == m_hProcHeap)
{
return E_FAIL;
}
TCHAR szBaseServerUrl[INTERNET_MAX_URL_LENGTH];
TCHAR szSelfUpdateStructure[MAX_PATH];
TCHAR szServerDirectory[MAX_PATH] = { '\0' };
TCHAR szLocalPath[MAX_PATH];
TCHAR szValue[MAX_PATH];
LPTSTR pszWalk = NULL, pszDelim = NULL;
TCHAR szIdentBuffer[MAX_PATH + 1];
TCHAR szIdentFile[MAX_PATH + 1];
GetIndustryUpdateDirectory(szIdentBuffer);
hr=PathCchCombine(szIdentFile,ARRAYSIZE(szIdentFile),szIdentBuffer, IDENTTXT);
if(FAILED(hr))
{
LOG_ErrorMsg(hr);
return hr;
}
m_pszSelfUpdateUrl = (LPTSTR) HeapAlloc(
m_hProcHeap,
HEAP_ZERO_MEMORY,
sizeof(TCHAR) * INTERNET_MAX_URL_LENGTH);
CleanUpFailedAllocSetHrMsg(m_pszSelfUpdateUrl);
// Get SelfUpdate Server URL
GetPrivateProfileString(m_fIsBetaMode ? IDENT_IUBETASELFUPDATE : IDENT_IUSELFUPDATE,
IDENT_ENTRY_SERVERURL,
_T(""),
szBaseServerUrl,
ARRAYSIZE(szBaseServerUrl),
szIdentFile);
if ('\0' == szBaseServerUrl[0])
{
// no URL specified in iuident..
LOG_ErrorMsg(ERROR_IU_SELFUPDSERVER_NOT_FOUND);
hr = ERROR_IU_SELFUPDSERVER_NOT_FOUND;
goto CleanUp;
}
// Get SelfUpdate Structure Key
// ARCH|LOCALE
GetPrivateProfileString(m_fIsBetaMode ? IDENT_IUBETASELFUPDATE : IDENT_IUSELFUPDATE,
IDENT_STRUCTUREKEY,
_T(""),
szSelfUpdateStructure,
ARRAYSIZE(szSelfUpdateStructure),
szIdentFile);
if ('\0' == szSelfUpdateStructure[0])
{
// no SelfUpdate Structure in iudent
LOG_ErrorMsg(ERROR_IU_SELFUPDSERVER_NOT_FOUND);
hr = ERROR_IU_SELFUPDSERVER_NOT_FOUND;
goto CleanUp;
}
// Parse the SelfUpdate Structure Key for Value Names to Read
// Initially we will only have an ARCH key..
pszWalk = szSelfUpdateStructure;
while (NULL != (pszDelim = StrChr(pszWalk, '|')))
{
*pszDelim = '\0';
if (0 == StrCmpI(pszWalk, IDENT_ARCH))
{
#ifdef _IA64_
GetPrivateProfileString(IDENT_IUARCH, IDENT_IA64, _T(""), szValue, ARRAYSIZE(szValue), szIdentFile);
#else
GetPrivateProfileString(IDENT_IUARCH, IDENT_X86, _T(""), szValue, ARRAYSIZE(szValue), szIdentFile);
#endif
}
else if (0 == StrCmpI(pszWalk, IDENT_OS))
{
// Get the Current OS String
GetIdentPlatformString(szLocalPath, ARRAYSIZE(szLocalPath));
if ('\0' == szLocalPath[0])
{
LOG_ErrorMsg(ERROR_IU_SELFUPDSERVER_NOT_FOUND);
hr = ERROR_IU_SELFUPDSERVER_NOT_FOUND;
goto CleanUp;
}
GetPrivateProfileString(IDENT_IUOS, szLocalPath, _T(""), szValue, ARRAYSIZE(szValue), szIdentFile);
}
else if (0 == StrCmpI(pszWalk, IDENT_LOCALE))
{
// Get the Current Locale String
GetIdentLocaleString(szLocalPath, ARRAYSIZE(szLocalPath));
if ('\0' == szLocalPath[0])
{
LOG_ErrorMsg(ERROR_IU_SELFUPDSERVER_NOT_FOUND);
hr = ERROR_IU_SELFUPDSERVER_NOT_FOUND;
goto CleanUp;
}
GetPrivateProfileString(IDENT_IULOCALE, szLocalPath, _T(""), szValue, ARRAYSIZE(szValue), szIdentFile);
}
else if (0 == StrCmpI(pszWalk, IDENT_CHARTYPE))
{
#ifdef UNICODE
GetPrivateProfileString(IDENT_IUCHARTYPE, IDENT_UNICODE, _T(""), szValue, ARRAYSIZE(szValue), szIdentFile);
#else
GetPrivateProfileString(IDENT_IUCHARTYPE, IDENT_ANSI, _T(""), szValue, ARRAYSIZE(szValue), szIdentFile);
#endif
}
else
{
LOG_Internet(_T("Found Unrecognized Token in SelfUpdate Structure String: Token was: %s"), pszWalk);
pszWalk += lstrlen(pszWalk) + 1; // skip the previous token, and go to the next one in the string.
*pszDelim = '|';
continue;
}
if ('\0' != szValue[0])
{
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szServerDirectory,ARRAYSIZE(szServerDirectory),szValue,NULL,NULL,MISTSAFE_STRING_FLAGS));
}
pszWalk += lstrlen(pszWalk) + 1; // skip the previous token, and go to the next one in the string.
*pszDelim = '|';
}
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szServerDirectory,ARRAYSIZE(szServerDirectory),SLASHENGINECAB,NULL,NULL,MISTSAFE_STRING_FLAGS));
if ('/' == szServerDirectory[0])
{
pszWalk = CharNext(szServerDirectory);
}
else
{
pszWalk = szServerDirectory;
}
DWORD dwSize = INTERNET_MAX_URL_LENGTH;
UrlCombine(szBaseServerUrl, pszWalk, m_pszSelfUpdateUrl, &dwSize, 0);
}
CleanUp:
if (SUCCEEDED(hr))
{
m_fIUPopulated = TRUE;
}
return hr;
}
//------------------------------------------------------------------------
//
// get the self-update server.
// *** this API should be called after PopulateData() is called ***
//
//------------------------------------------------------------------------
HRESULT CIUUrlAgent::GetSelfUpdateServer(
LPTSTR lpsBuffer,
int nBufferSize,
BOOL* pfInternalServer /*= NULL*/)
{
HRESULT hr=S_OK;
if (!m_fIUPopulated)
{
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
if (NULL == m_pszSelfUpdateUrl)
{
return (E_OUTOFMEMORY);
}
if (NULL == lpsBuffer)
{
return E_INVALIDARG;
}
nBufferSize/=sizeof(TCHAR);
if (nBufferSize <= lstrlen(m_pszSelfUpdateUrl))
{
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
hr=StringCchCopyEx(lpsBuffer,nBufferSize,m_pszSelfUpdateUrl,NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr))
return hr;
if (NULL != pfInternalServer)
{
*pfInternalServer = m_fIdentFromPolicy;
}
return hr;
}