Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1277 lines
39 KiB

// File: util.cxx
//
// Contents: Utility classes.
//
// Classes: CRefCount, CRegKey
//
// Functions://
// History:
//
//----------------------------------------------------------------------------
#include "zonepch.h"
#include "advpub.h"
#ifdef UNIX
#include <platform.h>
#endif /* UNIX */
#include "shfolder.h"
// Misc utility functions and declarations.
#define DRIVE_UNINIT 0xFFFF // Indicates that we haven't called GetDriveType yet.
DWORD rgdwDriveTypeCache[26]; // one for each drive letter.
BOOL g_bInit = FALSE;
BOOL g_bUseHKLMOnly = FALSE;
static LPWSTR s_pwzCacheDir;
static HRESULT GetCacheDirectory( );
static LPWSTR s_pwzCookieDir = NULL;
static CHAR *s_szMarkPrefix = "<!-- saved from url=(%04d)";
static CHAR *s_szMarkSuffix = " -->\r\n";
CSharedMem g_SharedMem;
static CRITICAL_SECTION g_csect_GetCacheDir;
BOOL IsZonesInitialized( )
{
return g_bInit;
}
BOOL ZonesInit( )
{
if (!g_bInit)
{
DWORD dwType;
DWORD dwSize = sizeof(DWORD);
DWORD dwDefault = FALSE ; // If no entry found default is use HKCU.
g_bInit = TRUE;
// Call the shlwapi wrapper function that directly reads in a value for us.
// Note that if the call fails we have the right value in g_bHKLMOnly already.
SHRegGetUSValue(SZPOLICIES, SZHKLMONLY, &dwType, &g_bUseHKLMOnly,
&dwSize, TRUE, &dwDefault, sizeof(dwDefault));
InitializeCriticalSection(&CUrlZoneManager::s_csect);
CUrlZoneManager::s_bcsectInit = TRUE;
CSecurityManager::GlobalInit();
// Initialize the drive type cache.
for ( int i = 0 ; i < ARRAYSIZE(rgdwDriveTypeCache) ; i++ )
rgdwDriveTypeCache[i] = DRIVE_UNINIT;
//initialize critical section for GetCacheDirectory()
InitializeCriticalSection(&g_csect_GetCacheDir);
}
return TRUE;
}
VOID ZonesUnInit ( )
{
CUrlZoneManager::Cleanup( );
CSecurityManager::GlobalCleanup( );
g_SharedMem.Release();
// Free any memory allocated for the cache directory.
delete [] s_pwzCacheDir;
if(s_pwzCookieDir)
delete [] s_pwzCookieDir;
// Destroy the GetCacheDirectory() critsec.
DeleteCriticalSection(&g_csect_GetCacheDir);
}
// IEAK calls this function so force us to re-read the global settings for
// HKLM vs HKCU.
STDAPI ZonesReInit(DWORD /* dwReserved */)
{
DWORD dwType;
DWORD dwDefault = g_bUseHKLMOnly;
DWORD dwSize = sizeof(DWORD);
DWORD dwError = SHRegGetUSValue(SZPOLICIES, SZHKLMONLY, &dwType, &g_bUseHKLMOnly,
&dwSize, TRUE, &dwDefault, sizeof(dwDefault));
return HRESULT_FROM_WIN32(dwError);
}
// SHDOCVW calls this during Thicket save to get the comment to flag the
// saved file as
STDAPI GetMarkOfTheWeb(LPCSTR pszURL, LPCSTR pszFile, DWORD dwFlags, LPSTR *ppszMark)
{
HRESULT hr = S_OK;
int cchURL = lstrlenA(pszURL);
// Note - the code assumes that lstrlen(IDS_MARK_PREFIX)
// equals wsprintf(IDS_MARK_PREFIX, lstrlen(url)
*ppszMark = (LPSTR)LocalAlloc( LMEM_FIXED, (lstrlenA(s_szMarkPrefix) +
cchURL +
lstrlenA(s_szMarkSuffix) +
1) * sizeof(CHAR) );
if ( *ppszMark )
{
wsprintfA( *ppszMark, s_szMarkPrefix, cchURL );
lstrcatA( *ppszMark, pszURL );
lstrcatA( *ppszMark, s_szMarkSuffix );
}
else
hr = E_OUTOFMEMORY;
return hr;
}
// The security manager calls this to sniff a file: URL for the Mark of the Web
BOOL FileBearsMarkOfTheWeb(LPCTSTR pszFile, LPWSTR *ppszURLMark)
{
BOOL fMarked = FALSE;
HANDLE hFile;
CHAR szMarkPrefix[MARK_PREFIX_SIZE];
CHAR szMarkSuffix[MARK_SUFFIX_SIZE];
WCHAR wzMarkPrefix[MARK_PREFIX_SIZE];
WCHAR wzMarkSuffix[MARK_SUFFIX_SIZE];
BOOL fIsInUnicode = FALSE;
DWORD cchReadBufLen = 0;
DWORD cchURL;
CHAR *szMarkHead = NULL;
WCHAR *wzMarkHead = NULL;
CHAR *szMarkSuf = NULL;
WCHAR *wzMarkSuf = NULL;
CHAR *pszURLMark = NULL;
DWORD cchReadLen = 0;
char *pszTmp = NULL;
char *szReadBuf = NULL;
int iIteration = 1;
lstrcpyA(szMarkPrefix, s_szMarkPrefix);
lstrcpyA(szMarkSuffix, s_szMarkSuffix);
hFile = CreateFile( pszFile, GENERIC_READ, FILE_SHARE_READ ,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL );
if ( hFile != INVALID_HANDLE_VALUE )
{
DWORD cchPrefix = lstrlenA(szMarkPrefix);
DWORD dwRead;
CHAR szHeader[UNICODE_HEADER_SIZE];
DWORD cchHeader = UNICODE_HEADER_SIZE;
if (ReadFile(hFile, szHeader, cchHeader, &dwRead, NULL) &&
cchHeader == dwRead)
{
if ((BYTE)szHeader[0] == (BYTE)0xFF && (BYTE)szHeader[1] == (BYTE)0xFE)
{
fIsInUnicode = TRUE;
}
else
{
fIsInUnicode = FALSE;
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
TransAssert(GetLastError() == NO_ERROR);
}
}
else
{
// Unable to sniff for header
goto Exit;
}
// File pointer is not at "real" beginning of file, regardless of
// whether we are reading a UNICODE or ANSI file.
szReadBuf = NULL;
cchReadBufLen = 0;
iIteration = 1;
// Anchor NULL to make szMarkPrefix: <!-- saved from url=
szMarkPrefix[cchPrefix-6] = '\0';
if (fIsInUnicode)
{
if (!MultiByteToWideChar(CP_ACP, 0, szMarkPrefix, -1,
wzMarkPrefix, MARK_PREFIX_SIZE))
{
goto Exit;
}
if (!MultiByteToWideChar(CP_ACP, 0, szMarkSuffix, -1,
wzMarkSuffix, MARK_SUFFIX_SIZE))
{
goto Exit;
}
}
for (;;)
{
cchReadBufLen = INTERNET_MAX_URL_LENGTH +
EXTRA_BUFFER_SIZE * iIteration + 1;
if (fIsInUnicode)
{
cchReadBufLen *= 2;
}
szReadBuf = new char[cchReadBufLen];
if (!szReadBuf)
{
goto Exit;
}
cchReadLen = (fIsInUnicode) ? (cchReadBufLen - 2) : (cchReadBufLen - 1);
if (ReadFile(hFile, szReadBuf, cchReadLen, &dwRead, NULL))
{
// look for mark of the web
if (fIsInUnicode)
{
szReadBuf[dwRead] = L'\0';
wzMarkHead = StrStrW((WCHAR *)szReadBuf, wzMarkPrefix);
if (wzMarkHead)
{
// Look for mark of the web suffix. If we don't
// have it, that means that we didn't have enough
// space for the buffer, and we need to try again
// with more space.
wzMarkSuf = StrStrW(wzMarkHead, wzMarkSuffix);
if (wzMarkSuf)
{
// Found suffix. We're done.
break;
}
else
{
if (dwRead < cchReadLen)
{
// We've already read everything, and
// we didn't find the suffix!
goto Exit;
}
// Didn't find suffix because buffer was too
// small. Try it again
delete [] szReadBuf;
szReadBuf = NULL;
iIteration++;
SetFilePointer(hFile, 2, 0, FILE_BEGIN);
TransAssert(GetLastError() == NO_ERROR);
continue;
}
}
else
{
// Can't find the mark head! Must find it on
// first iteration, or we give up.
goto Exit;
}
}
else
{
// We are dealing with ANSI
szReadBuf[dwRead] = '\0';
szMarkHead = StrStrA(szReadBuf, szMarkPrefix);
if (szMarkHead)
{
// Look for mark of the web suffix. If we don't
// have it, that means that we didn't have enough
// space for the buffer, and we need to try again
// with more space.
szMarkSuf = StrStrA(szMarkHead, szMarkSuffix);
if (szMarkSuf)
{
// Found suffix. We're done.
break;
}
else
{
if (dwRead < cchReadLen)
{
// We've already read everything, and
// we didn't find the suffix!
goto Exit;
}
// Didn't find suffix because buffer was too
// small. Try it again
delete [] szReadBuf;
szReadBuf = NULL;
iIteration++;
SetFilePointer(hFile, 0, 0, FILE_BEGIN);
TransAssert(GetLastError() == NO_ERROR);
continue;
}
}
else
{
// Can't find the mark head! Must find it on
// first iteration, or we give up.
goto Exit;
}
}
}
else
{
// Read failure!
TransAssert(0);
}
}
// now wzMarkHead or szMarkHead points to beginning of the mark
// of the web, and wzMarkSuf or szMarkSuf point to the mark suffix
if (fIsInUnicode)
{
DWORD cchURL = 0;
LPWSTR wzPtr = StrStrW(wzMarkHead, L"=(");
if (!wzPtr) goto Exit;
wzPtr += 2; // skip to beginning of length
TransAssert((wzMarkSuf >= wzPtr));
wzPtr[4] = L'\0'; // anchor NULL
cchURL = StrToIntW(wzPtr);
if (cchURL > INTERNET_MAX_URL_LENGTH)
{
cchURL = INTERNET_MAX_URL_LENGTH;
}
//the string length of the url should be greater than or equal to cchURL.
//else abort the allocation.
if ((wzMarkSuf-(wzPtr+5)) < (INT)cchURL)
goto Exit;
*ppszURLMark = (WCHAR*)LocalAlloc(LMEM_FIXED, (cchURL+1) * sizeof(WCHAR));
if (!*ppszURLMark)
{
goto Exit;
}
// StrCpyN length includes NULL terminator
StrCpyNW(*ppszURLMark, wzPtr + 5, cchURL + 1);
}
else
{
DWORD cchURL = 0;
LPSTR szPtr = StrStrA(szMarkHead, "=(");
if (!szPtr) goto Exit;
szPtr += 2; // skip to beginning of length
TransAssert((szMarkSuf >= szPtr));
szPtr[4] = '\0'; // anchor NULL
cchURL = StrToIntA(szPtr);
if (cchURL > INTERNET_MAX_URL_LENGTH)
{
cchURL = INTERNET_MAX_URL_LENGTH;
}
//the string length of the url should be greater than or equal to cchURL.
//else abort the allocation.
if ((szMarkSuf-(szPtr+5)) < (INT)cchURL)
goto Exit;
pszTmp = new char[cchURL + 1];
if (!pszTmp)
{
goto Exit;
}
*ppszURLMark = (WCHAR*)LocalAlloc(LMEM_FIXED, (cchURL+1) * sizeof(WCHAR));
if (!*ppszURLMark)
{
goto Exit;
}
// StrCpyN length includes NULL terminator
StrCpyNA(pszTmp, szPtr + 5, cchURL + 1);
MultiByteToWideChar(CP_ACP, 0, pszTmp, -1, *ppszURLMark, cchURL);
(*ppszURLMark)[cchURL] = '\0';
}
if (szReadBuf)
{
delete [] szReadBuf;
szReadBuf = NULL;
}
}
else
{
// CreateFile failure
goto Exit;
}
fMarked = TRUE;
Exit:
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
}
if (szReadBuf)
{
delete [] szReadBuf;
}
if (pszURLMark)
{
delete [] pszURLMark;
}
if (pszTmp) {
delete [] pszTmp;
}
return fMarked;
}
//This function may now be called by one or more threads from IsFileInCacheDir() ( since we've moved invocation out of
//ZonesInit ( to prevent LoadLibrary() being called during DllMain execution ) ).
//Hence, we need a critsec for mutual exclusion..
//This also means that if for some reason, this function fails the first time, it may be called mutliple times by different
//threads, whereas earlier if it failed during ZonesInit(), it was never tried again.
HRESULT GetCacheDirectory( )
{
HRESULT hr = E_FAIL;
HMODULE hModShell=NULL;
HMODULE hModShfolder=NULL;
PFNSHGETFOLDERPATH pfnGetFolderPath;
EnterCriticalSection(&g_csect_GetCacheDir);
// If another thread managed to get this while this thread was waiting, bail out with success.
// Optionally, if we want this code to execute only once, we can use a static boolean check.
if (s_pwzCacheDir != NULL && s_pwzCookieDir != NULL)
{
hr = S_OK;
goto Cleanup;
}
hModShell = LoadLibrary(TEXT("shell32.dll"));
if (NULL == hModShell)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}
#ifdef UNICODE
pfnGetFolderPath = (PFNSHGETFOLDERPATHW)GetProcAddress(hModShell, "SHGetFolderPathW");
#else
pfnGetFolderPath = (PFNSHGETFOLDERPATHA)GetProcAddress(hModShell, "SHGetFolderPathA");
#endif
if (pfnGetFolderPath == NULL)
{
hModShfolder = LoadLibrary(TEXT("shfolder.dll"));
if (hModShfolder == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}
#ifdef UNICODE
pfnGetFolderPath = (PFNSHGETFOLDERPATHW)GetProcAddress(hModShfolder, "SHGetFolderPathW");
#else
pfnGetFolderPath = (PFNSHGETFOLDERPATHA)GetProcAddress(hModShfolder, "SHGetFolderPathA");
#endif
}
if (pfnGetFolderPath == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
else
{
TCHAR rgchCachePath[MAX_PATH];
hr = pfnGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL, 0, rgchCachePath);
if (rgchCachePath[0] == TEXT('\0'))
hr = E_FAIL;
if (SUCCEEDED(hr))
{
if (s_pwzCacheDir != NULL)
{
delete [] s_pwzCacheDir;
s_pwzCacheDir = NULL;
}
// Allocate memory for the new location.
s_pwzCacheDir = new TCHAR[lstrlen(rgchCachePath) + 1];
if (s_pwzCacheDir != NULL)
{
StrCpy(s_pwzCacheDir, rgchCachePath);
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
}
hr = pfnGetFolderPath(NULL, CSIDL_COOKIES, NULL, 0, rgchCachePath);
if (rgchCachePath[0] == TEXT('\0'))
hr = E_FAIL;
if (SUCCEEDED(hr))
{
if (s_pwzCookieDir != NULL)
{
delete [] s_pwzCookieDir;
s_pwzCookieDir = NULL;
}
// Allocate memory for the new location.
s_pwzCookieDir = new TCHAR[lstrlen(rgchCachePath) + 1];
if (s_pwzCookieDir != NULL)
{
StrCpy(s_pwzCookieDir, rgchCachePath);
hr = S_OK;
}
else
hr = E_OUTOFMEMORY;
}
}
Cleanup:
if (hModShfolder)
FreeLibrary(hModShfolder);
if (hModShell)
FreeLibrary(hModShell);
LeaveCriticalSection(&g_csect_GetCacheDir);
return hr;
}
#if NOTUSED // Keep this code around in the unlikely event that we resurrect the Unix port.
// This function gets the location of the cache directory.
HRESULT GetCacheDirectory( )
{
DWORD dwType;
// First figure out if we are using per-user cache or per-machine cache.
// This decides which registry key to look at for the cache value.
BOOL fPerUserCache = TRUE;
#ifndef UNIX
OSVERSIONINFOA osvi = {0};
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
GetVersionExA(&osvi);
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
fPerUserCache = TRUE;
}
else
{
DWORD dwUserProfile = 0;
DWORD dwSize = sizeof(dwUserProfile);
// Determine if user profiles are enabled.
if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, SZLOGON, SZUSERPROFILES, &dwType, &dwUserProfile, &dwSize))
&& (dwUserProfile != 0 ))
{
fPerUserCache = TRUE;
// Look for the exceptional case where User Profiles are enabled but the cache is still
// global.
dwSize = sizeof(dwUserProfile);
if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, SZCACHE, SZUSERPROFILES, &dwType, &dwUserProfile, &dwSize))
&& (dwUserProfile == 0))
{
fPerUserCache = FALSE;
}
}
else
{
fPerUserCache = FALSE;
}
}
#endif /* !UNIX */
HRESULT hr = S_OK;
#ifdef UNIX
WCHAR wszIE5Dir[] = L"ie5/";
DWORD cchPath = MAX_PATH + sizeof(wszIE5Dir)/sizeof(WCHAR);
#else
DWORD cchPath = MAX_PATH;
#endif /* !UNIX */
s_pwzCacheDir = new WCHAR[cchPath];
DWORD dwError = NOERROR;
// First figure out if we are using per-user cache or per-machine cache.
// This decides which registry key to look at for the cache value.
if (s_pwzCacheDir != NULL)
{
LPCWSTR pwzKey = fPerUserCache ? SZSHELLFOLDER : SZCACHECONTENT;
LPCWSTR pwzValue = fPerUserCache ? SZTIFS : SZCACHEPATH ;
HKEY hKey = fPerUserCache ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
dwError = SHGetValueW(hKey, pwzKey, pwzValue, &dwType, s_pwzCacheDir, &cchPath);
}
else
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
}
if (dwError != NOERROR)
{
delete [] s_pwzCacheDir;
s_pwzCacheDir = NULL;
hr = HRESULT_FROM_WIN32(dwError);
}
else
{
TransAssert(s_pwzCacheDir != NULL);
PathRemoveBackslashW(s_pwzCacheDir);
#ifdef UNIX
{
int ccPath, index;
int lenIE5Dir = lstrlen(wszIE5Dir);
ccPath = lstrlen(s_pwzCacheDir);
index = ccPath - 1;
while(index >= 0 && s_pwzCacheDir[index] != FILENAME_SEPARATOR_W)
index--;
index++;
memmove(&s_pwzCacheDir[index+lenIE5Dir],&s_pwzCacheDir[index],(ccPath-index+1)*sizeof(TCHAR));
memcpy(&s_pwzCacheDir[index], wszIE5Dir, lenIE5Dir*sizeof(TCHAR));
}
#endif /* UNIX */
hr = S_OK;
}
return hr;
}
#endif // NOTUSED
BOOL IsFileInCacheDir(LPCWSTR pwzFile)
{
BOOL bReturn = FALSE;
TCHAR szLongPath[MAX_PATH];
if(!GetLongPathNameWrapW(pwzFile, szLongPath, sizeof(szLongPath)/sizeof(TCHAR)))
{
goto exit;
}
if (s_pwzCacheDir == NULL || s_pwzCookieDir == NULL)
{
if (! (SUCCEEDED(GetCacheDirectory())) )
goto exit;
}
if(PathIsPrefixW(s_pwzCacheDir, szLongPath))
{
bReturn = TRUE;
}
exit:
return bReturn;
}
BOOL IsFileInCookieDir(LPCWSTR pwzFile)
{
BOOL bReturn = FALSE;
TCHAR szLongPath[MAX_PATH];
if(!GetLongPathNameWrapW(pwzFile, szLongPath, sizeof(szLongPath)/sizeof(TCHAR)))
{
goto exit;
}
if (s_pwzCacheDir == NULL || s_pwzCookieDir == NULL)
{
if (! (SUCCEEDED(GetCacheDirectory())) )
goto exit;
}
if(PathIsPrefixW(s_pwzCookieDir, szLongPath))
{
bReturn = TRUE;
}
exit:
return bReturn;
}
// This function takes a DWORD and returns a wide char string
// in hex. There is no leading 0x and the leading 0's are stripped off
// This is to avoid pulling in the general wsprintfW into wininet which is
// pretty big. You have to pass in enough memory to write the resulting string
// into ( i.e >= 9 chars)
BOOL DwToWchar(DWORD dw, LPWSTR pwz, int radix)
{
char sz[9];
LPSTR psz = sz;
LPSTR pszTemp = (LPSTR)pwz;
char rgFormatHex[] = "%lX";
char rgFormatDecimal[] = "%ld";
char *pszFormat;
if (radix == 16)
pszFormat = rgFormatHex;
else if (radix == 10)
pszFormat = rgFormatDecimal;
else
{
TransAssert(FALSE);
return FALSE;
}
if (wsprintfA(sz, pszFormat, dw) == 0)
{
return FALSE;
}
#ifndef unix
// Everything in the string sz is ANSI.
while (*psz != 0)
{
*pszTemp++ = *psz++;
*pszTemp++ = '\0';
}
// Put the trailing NULL to the wide-char string.
*pszTemp++ = '\0';
*pszTemp++ = '\0';
#else
while(*psz != 0)
*pwz++ = (WCHAR)(DWORD)*psz++;
*pwz++ = 0;
#endif /* unix */
return TRUE;
}
// Drive type caching function.
//
DWORD GetDriveTypeFromCacheA(LPCSTR lpsz)
{
// NOTE: The retail version doesn't do any paramater validation to determine if this path is
// a valid one. So something like CTHISISGARBAGE will return the drive type for C:.
// This is just meant to be used inside the security manager so we can bypass these
// checks.
TransAssert(lstrlenA(lpsz) >= 3); // c:\ for example
TransAssert(lpsz[1] == ':' && lpsz[2] == '\\');
#ifndef unix
CHAR ch = (CHAR)CharLowerA((LPSTR)lpsz[0]);
#else
CHAR *pch = CharLowerA((LPSTR)lpsz);
CHAR ch = *pch;
#endif /* unix */
#ifndef UNIX
if (ch >= 'a' && ch <= 'z')
{
// First check the cache to see if the entry already exists.
int index = ch - 'a';
if (rgdwDriveTypeCache[index] == DRIVE_UNINIT)
{
rgdwDriveTypeCache[index] = GetDriveTypeA(lpsz);
}
TransAssert(rgdwDriveTypeCache[index] != DRIVE_UNINIT);
return rgdwDriveTypeCache[index];
}
#else
if (ch == '/')
{
// IEUNIX - On unix we have only one drive "/" which is of type fixed
// This was causing a wrong zone to be calculated for unix paths.
return DRIVE_FIXED;
}
#endif
else
{
return DRIVE_UNKNOWN;
}
}
// Helper to determine if we're currently loaded during GUI mode setup
BOOL IsInGUIModeSetup()
{
static DWORD s_dwSystemSetupInProgress = 42;
if (42 == s_dwSystemSetupInProgress)
{
// Rule is that this value will exist and be equal to 1 if in GUI mode setup.
// Default to NO, and only do this for upgrades because this is potentially
// needed for unattended clean installs.
s_dwSystemSetupInProgress = 0;
HKEY hKeySetup = NULL;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("System\\Setup"),
0,
KEY_READ,
&hKeySetup))
{
DWORD dwSize = sizeof(s_dwSystemSetupInProgress);
if (ERROR_SUCCESS != RegQueryValueEx (hKeySetup,
TEXT("SystemSetupInProgress"),
NULL,
NULL,
(LPBYTE) &s_dwSystemSetupInProgress,
&dwSize))
{
s_dwSystemSetupInProgress = 0;
}
else
{
dwSize = sizeof(s_dwSystemSetupInProgress);
if (s_dwSystemSetupInProgress &&
ERROR_SUCCESS != RegQueryValueEx (hKeySetup,
TEXT("UpgradeInProgress"),
NULL,
NULL,
(LPBYTE) &s_dwSystemSetupInProgress,
&dwSize))
{
s_dwSystemSetupInProgress = 0;
}
}
RegCloseKey(hKeySetup);
}
}
return s_dwSystemSetupInProgress ? TRUE : FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CRegKey
LONG CRegKey::Close()
{
LONG lRes = ERROR_SUCCESS;
if (m_hKey != NULL)
{
lRes = SHRegCloseUSKey(m_hKey);
m_hKey = NULL;
}
return lRes;
}
LONG CRegKey::Create(HUSKEY hKeyParent, LPCTSTR lpszKeyName, REGSAM samDesired)
{
HUSKEY hKey = NULL;
// BUGBUG : Is this the correct flag to call this function with?
DWORD dwFlags = m_bHKLMOnly ? SHREGSET_FORCE_HKLM : SHREGSET_FORCE_HKCU;
LONG lRes = SHRegCreateUSKey(lpszKeyName, samDesired, hKeyParent, &hKey, dwFlags);
if (lRes == ERROR_SUCCESS)
{
lRes = Close();
m_hKey = hKey;
}
return lRes;
}
LONG CRegKey::Open(HUSKEY hKeyParent, LPCTSTR lpszKeyName, REGSAM samDesired)
{
HUSKEY hKey = NULL;
LONG lRes = SHRegOpenUSKey(lpszKeyName, samDesired, hKeyParent, &hKey, m_bHKLMOnly);
if (lRes == ERROR_SUCCESS)
{
lRes = Close();
TransAssert(lRes == ERROR_SUCCESS);
m_hKey = hKey;
}
return lRes;
}
LONG CRegKey::QueryValue(DWORD* pdwValue, LPCTSTR lpszValueName)
{
DWORD dwType = NULL;
DWORD dwCount = sizeof(DWORD);
LONG lRes = SHRegQueryUSValue(m_hKey, lpszValueName, &dwType,
pdwValue, &dwCount, m_bHKLMOnly, NULL, 0);
TransAssert((lRes!=ERROR_SUCCESS) || (dwType == REG_DWORD));
TransAssert((lRes!=ERROR_SUCCESS) || (dwCount == sizeof(DWORD)));
return lRes;
}
LONG CRegKey::QueryValue(LPTSTR szValue, LPCTSTR lpszValueName, DWORD* pdwCount)
{
TransAssert(pdwCount != NULL);
DWORD dwType = 0;
LONG lRes = SHRegQueryUSValue(m_hKey, lpszValueName, &dwType,
szValue, pdwCount, m_bHKLMOnly, NULL, 0);
TransAssert((lRes!=ERROR_SUCCESS) || (dwType == REG_SZ) ||
(dwType == REG_MULTI_SZ) || (dwType == REG_EXPAND_SZ));
return lRes;
}
LONG CRegKey::QueryBinaryValue(LPBYTE pb, LPCTSTR lpszValueName, DWORD* pdwCount)
{
TransAssert(pdwCount != NULL);
DWORD dwType = NULL;
LONG lRes = SHRegQueryUSValue(m_hKey, lpszValueName, &dwType,
pb, pdwCount, m_bHKLMOnly, NULL, 0);
TransAssert((lRes!=ERROR_SUCCESS) || (dwType == REG_BINARY));
return lRes;
}
LONG WINAPI CRegKey::SetValue(HUSKEY hKeyParent, LPCTSTR lpszKeyName, LPCTSTR lpszValue, LPCTSTR lpszValueName, BOOL bHKLMOnly)
{
TransAssert(lpszValue != NULL);
CRegKey key(bHKLMOnly);
LONG lRes = key.Create(hKeyParent, lpszKeyName, KEY_WRITE);
if (lRes == ERROR_SUCCESS)
lRes = key.SetValue(lpszValue, lpszValueName);
return lRes;
}
LONG CRegKey::SetKeyValue(LPCTSTR lpszKeyName, LPCTSTR lpszValue, LPCTSTR lpszValueName)
{
TransAssert(lpszValue != NULL);
CRegKey key(m_bHKLMOnly);
LONG lRes = key.Create(m_hKey, lpszKeyName, KEY_WRITE);
if (lRes == ERROR_SUCCESS)
lRes = key.SetValue(lpszValue, lpszValueName);
return lRes;
}
//////////////////////////////////////////////////////////////////////////
//
// Autoregistration entry points
//
//////////////////////////////////////////////////////////////////////////
HRESULT CallRegInstall(LPSTR szSection)
{
HRESULT hr = E_FAIL;
HINSTANCE hinstAdvPack = LoadLibraryA("ADVPACK.DLL");
if (hinstAdvPack)
{
REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, achREGINSTALL);
if (pfnri)
{
hr = pfnri(g_hInst, szSection, NULL);
}
FreeLibrary(hinstAdvPack);
}
return hr;
}
/*
* We want to show the inetcpl settings as "Custom" in case of an upgrade only.
*
* We detect an upgrade using an HKCU key which only urlmon selfreg. code can set
* Earlier we used the "Zones" key.
*
* In Whistler, the problem is some other module ( Office maybe ) registers this key,
* so that even on a fresh install, we assume it's Custom.
* Fix is to change the key we check for.
*
* On Millenium, there was a problem with double registration - in this case, the fix
* would be to also put in the version key and check both for existence of a known key
* and to match version to avoid slamming "Custom" in if there's a version match.
*/
BOOL
ShouldSetCustom()
{
#define SZPATH_ZONES_LOCAL_A "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\0\\"
BOOL fUpgrade = FALSE;
HKEY hKeyZones;
LONG dwResult = RegOpenKeyExA(
HKEY_CURRENT_USER,
SZPATH_ZONES_LOCAL_A,
0,
KEY_READ,
&hKeyZones);
if (dwResult == ERROR_SUCCESS)
{
//key exists, not an upgrade
RegCloseKey(hKeyZones);
fUpgrade = TRUE;
}
return fUpgrade;
}
STDAPI
ZonesDllInstall
(
IN BOOL bInstall, // Install or Uninstall
IN LPCWSTR pwStr
)
{
TransAssert(pwStr != NULL);
HRESULT hr = S_OK;
BOOL bUseHKLM = TRUE;
if (pwStr && (0 == StrCmpIW(pwStr, L"HKCU")))
{
// Don't write to HKCU during GUI mode setup. Otherwise,
// the values may get slammed into all profiles during an upgrade.
if (IsInGUIModeSetup())
return hr;
bUseHKLM = FALSE;
}
if (bInstall && pwStr)
{
if(!StrCmpIW(pwStr, L"HKCUSoft"))
{
return CallRegInstall("RegSoften.HKCU");
}
else if(!StrCmpIW(pwStr, L"HKCUHard"))
{
return CallRegInstall("RegHarden.HKCU");
}
else if(!StrCmpIW(pwStr, L"HKLMHard"))
{
return CallRegInstall("RegHarden.HKLM");
}
else if(!StrCmpIW(pwStr, L"HKLMSoft"))
{
return CallRegInstall("RegSoften.HKLM");
}
}
if ( bInstall )
{
BOOL fSetHKCUToCustom = FALSE; //Default to no-upgrade to avoid overwriting default zone settings.
if (!bUseHKLM)
{
fSetHKCUToCustom = ShouldSetCustom();
}
// Backup IE3 user agent string, but don't do ever do these during
// GUI mode setup
if (!IsInGUIModeSetup())
{
CallRegInstall("BackupUserAgent");
CallRegInstall("BackupConnectionSettings");
}
CallRegInstall(bUseHKLM ? "Backup.HKLM" : "Backup.HKCU");
hr = CallRegInstall(bUseHKLM ? "Reg.HKLM" : "Reg.HKCU");
if (!bUseHKLM)
{
// Bug # 19514: To appease the press, we need to change the default for scripting unsafe activex
// controls to "disable" instead of "prompt". But at install time we can't blindly overwrite
// the existing value. We have to check if the users Intranet/Internet zones are at medium
// security from the previous install. To avoid instantiating the zone manager at registration
// time we also hardcode the registry values here.
#define SZINTRANET SZZONES TEXT("1")
#define SZTRUSTED SZZONES TEXT("2")
#define SZINTERNET SZZONES TEXT("3")
#define SZUNTRUSTED SZZONES TEXT("4")
TransAssert(URLZONE_INTRANET == 1);
TransAssert(URLZONE_TRUSTED == 2);
TransAssert(URLZONE_INTERNET == 3);
TransAssert(URLZONE_UNTRUSTED == 4);
DWORD dwCurrentLevel ;
CRegKey regKeyIntranet(FALSE);
if ((regKeyIntranet.Open(NULL, SZINTRANET, KEY_READ) == ERROR_SUCCESS) &&
(regKeyIntranet.QueryValue(&dwCurrentLevel, SZCURRLEVEL) == NOERROR) &&
(dwCurrentLevel == URLTEMPLATE_MEDIUM)
)
{
CallRegInstall("Intranet.HackActiveX");
}
CRegKey regKeyInternet(FALSE);
if ((regKeyInternet.Open(NULL, SZINTERNET, KEY_READ) == ERROR_SUCCESS) &&
(regKeyInternet.QueryValue(&dwCurrentLevel, SZCURRLEVEL) == NOERROR) &&
(dwCurrentLevel == URLTEMPLATE_MEDIUM)
)
{
CallRegInstall("Internet.HackActiveX");
}
if (fSetHKCUToCustom)
{
//108298/104506 We want to preserve the settings prior to an upgrade, but at
// the same time, we dont want to show a security level inconsistent with the
// actual policies ( which is what will happen if templates change or default
// policy values change. So set all templates to CUSTOM on install.
CRegKey regKeyIntranet(FALSE);
if(regKeyIntranet.Open(NULL, SZINTRANET, KEY_WRITE) == ERROR_SUCCESS)
regKeyIntranet.SetValue(URLTEMPLATE_CUSTOM, SZCURRLEVEL);
CRegKey regKeyTrusted(FALSE);
if(regKeyTrusted.Open(NULL, SZTRUSTED, KEY_WRITE) == ERROR_SUCCESS)
regKeyTrusted.SetValue(URLTEMPLATE_CUSTOM, SZCURRLEVEL);
CRegKey regKeyInternet(FALSE);
if(regKeyInternet.Open(NULL, SZINTERNET, KEY_WRITE) == ERROR_SUCCESS)
regKeyInternet.SetValue(URLTEMPLATE_CUSTOM, SZCURRLEVEL);
CRegKey regKeyUntrusted(FALSE);
if(regKeyUntrusted.Open(NULL, SZUNTRUSTED, KEY_WRITE) == ERROR_SUCCESS)
regKeyUntrusted.SetValue(URLTEMPLATE_CUSTOM, SZCURRLEVEL);
}
}
}
else
{
// Restore IE3 user agent string.
CallRegInstall("RestoreUserAgent");
CallRegInstall("RestoreConnectionSettings");
hr = CallRegInstall(bUseHKLM ? "Unreg.HKLM" : "UnReg.HKCU");
if (bUseHKLM)
hr = CallRegInstall("Restore.HKLM");
}
return hr;
}
// CSharedMem member functions.
BOOL CSharedMem::Init(LPCSTR pszNamePrefix, DWORD dwSize)
{
// Note that this function is in ANSI, because we don't have Unicode wrappers
// for the file-mapping functions on Win9x and these need to work on Win9x.
// Create the name for the file mapping object.
// We want this name to be unique per logged in user.
// We will choose a name of the form ZonesSM_"UserName" for systems prior to NT5
// BUGBUG: On Terminal server should we use Global\ in the name. If a user is logged on in multiple
// sessions this seems desirable, but not sure if registry changes get reflected in the other
// session anyway.
DWORD cchPrefix = lstrlenA(pszNamePrefix);
LPSTR pszHandleName = (LPSTR) _alloca(cchPrefix + MAX_PATH);
if (pszHandleName == NULL)
return FALSE;
memcpy(pszHandleName, pszNamePrefix, cchPrefix);
// Move pointer to after the fixed part of the string.
LPSTR psz = pszHandleName + cchPrefix;
// Technically the max username possible is UNLEN which is less than MAX_PATH.
// We use MAX_PATH to not pull in another random header into the build.
DWORD dwMaxNameSize = MAX_PATH;
if (GetUserNameA(psz, &dwMaxNameSize))
{
// If succeeded, rgchHandleName now contains the exact same thing.
}
else
{
TransAssert(GetLastError() != ERROR_INSUFFICIENT_BUFFER);
// if it fails, we will assume no logged on user and just use a global shared memory
// section of the base name
}
m_dwSize = dwSize ;
// First try to see if the shared memory section already exists.
m_hFileMapping = CreateFileMappingA(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
m_dwSize,
pszHandleName) ;
if (m_hFileMapping != NULL)
{
m_lpVoidShared = MapViewOfFile(m_hFileMapping, FILE_MAP_WRITE, 0, 0, 0);
}
return (m_hFileMapping != NULL && m_lpVoidShared != NULL);
}
VOID CSharedMem::Release()
{
if (m_lpVoidShared != NULL)
{
UnmapViewOfFile(m_lpVoidShared);
m_lpVoidShared = NULL;
}
if (m_hFileMapping != NULL)
{
CloseHandle(m_hFileMapping);
m_hFileMapping = NULL;
}
m_dwSize = 0;
}
// This function will return NULL if either we couldn not initialize the shared memory
// for some reason or the offset specified is not in range. The offset should be specified
// in number of bytes.
LPVOID CSharedMem::GetPtr(DWORD dwOffset)
{
if (m_lpVoidShared == NULL)
return NULL;
if (dwOffset >= m_dwSize)
return NULL;
return (BYTE *)m_lpVoidShared + dwOffset;
}