Windows2003-3790/inetcore/wininet/dll/proxreg.cxx
2020-09-30 16:53:55 +02:00

1663 lines
45 KiB
C++

#include "wininetp.h"
#include "autodial.h"
const CHAR szRegPathConnections[] = REGSTR_PATH_INTERNET_SETTINGS "\\Connections";
static const CHAR szRegValProxyEnabled[] = REGSTR_VAL_PROXYENABLE;
static const CHAR szLegacyAutoConfigURL[] = "AutoConfigURL";
// when we haven't looked up dial-up override for autodetect
#define UNKNOWN_AUTODETECT ((DWORD)(-1))
// Internet Settings reg value do determine dial-up override for autodetect
static const CHAR szDialupAutodetect[] = "DialupAutodetect";
// base hkey we use for settings. May be per user or per machine.
CRefdKey* g_prkBase = NULL;
// type for RtlConvertSidToUnicodeString, exported from ntdll.dll
typedef NTSTATUS (* PCONVERTSID)(
PUNICODE_STRING UnicodeString,
PSID Sid,
BOOLEAN AllocateDestinationString
);
// some winsock stacks fault if we do a gethostbyname(NULL). If we come
// accross one of these, don't do any more autodetecting.
BOOL g_fGetHostByNameNULLFails = FALSE;
//
// IsConnectionMatch - a worker function to simply some logic elsewhere,
// it just handles Connection Name Matching.
//
BOOL
IsConnectionMatch(
LPCSTR lpszConnection1,
LPCSTR lpszConnection2)
{
if ( lpszConnection1 == NULL &&
lpszConnection2 == NULL)
{
return TRUE;
}
if ( lpszConnection1 && lpszConnection2 &&
stricmp(lpszConnection1, lpszConnection2) == 0 )
{
return TRUE;
}
return FALSE;
}
//
// Decide whether or not autodiscovery is turned based on IEAK setting.
// Only used when upgrading or creating settings for a new connectoid.
//
BOOL
EnableAutodiscoverForDialup(
VOID
)
{
static DWORD dwDialUpAutodetect = UNKNOWN_AUTODETECT;
if(UNKNOWN_AUTODETECT == dwDialUpAutodetect)
{
DWORD dwType, dwSize = sizeof(DWORD);
if(ERROR_SUCCESS !=
SHGetValue(HKEY_CURRENT_USER, INTERNET_POLICY_KEY,
szDialupAutodetect, &dwType, &dwDialUpAutodetect, &dwSize))
{
// not set
dwDialUpAutodetect = 0;
}
}
return (BOOL)dwDialUpAutodetect;
}
///////////////////////////////////////////////////////////////////////////
//
// CRegBlob implementation
//
///////////////////////////////////////////////////////////////////////////
CRegBlob::CRegBlob(
BOOL fWrite
)
{
// initialize members
_fWrite = fWrite;
_fCommit = TRUE;
_dwOffset = 0;
_pBuffer = NULL;
_dwBufferLimit = 0;
_hkey = NULL;
}
CRegBlob::~CRegBlob(
)
{
Commit();
if(_hkey)
REGCLOSEKEY(_hkey);
if(_pBuffer)
FREE_FIXED_MEMORY(_pBuffer);
// caller owns _pszValue pointer
}
DWORD
CRegBlob::Init(
HKEY hBaseKey,
LPCSTR pszSubKey,
LPCSTR pszValue
)
{
long lRes;
REGSAM regsam = KEY_QUERY_VALUE;
DWORD dwDisposition;
// If we're writing, save reg value name and set access
if(_fWrite)
{
_pszValue = pszValue;
regsam = KEY_SET_VALUE;
}
lRes = REGCREATEKEYEX(hBaseKey, pszSubKey, 0, "", 0,
regsam, NULL, &_hkey, &dwDisposition);
if(lRes != ERROR_SUCCESS)
{
return lRes;
}
// figure out buffer size
_dwBufferLimit = BLOB_BUFF_GRANULARITY;
if(FALSE == _fWrite)
{
// get size of registry blob
lRes = RegQueryValueEx(_hkey, pszValue, NULL, NULL, NULL, &_dwBufferLimit);
if(lRes != ERROR_SUCCESS)
{
// nothing there - make zero size buffer
_dwBufferLimit = 0;
}
}
// allocate buffer if necessary
if(_dwBufferLimit)
{
_pBuffer = (BYTE *)ALLOCATE_FIXED_MEMORY(_dwBufferLimit);
if(NULL == _pBuffer)
return GetLastError();
}
// if we're reading, fill in buffer
if(FALSE == _fWrite && _dwBufferLimit)
{
// read reg key
DWORD dwSize = _dwBufferLimit;
lRes = RegQueryValueEx(_hkey, pszValue, NULL, NULL, _pBuffer, &dwSize);
if(lRes != ERROR_SUCCESS)
{
return lRes;
}
}
// reset pointer to beginning of blob
_dwOffset = 0;
return 0;
}
DWORD
CRegBlob::Abandon(
VOID
)
{
// don't commit changes when the time comes
_fCommit = FALSE;
return 0;
}
DWORD
CRegBlob::Commit(
)
{
long lres = 0;
if(_fCommit && _fWrite && _pszValue && _pBuffer)
{
// save blob to reg key
lres = RegSetValueEx(_hkey, _pszValue, 0, REG_BINARY, _pBuffer, _dwOffset);
}
return lres;
}
DWORD
CRegBlob::Encrpyt(
)
{
return 0;
}
DWORD
CRegBlob::Decrypt(
)
{
return 0;
}
DWORD
CRegBlob::WriteString(
LPCSTR pszString
)
{
DWORD dwBytes, dwLen = 0;
if(pszString)
{
dwLen = lstrlen(pszString);
}
dwBytes = WriteBytes(&dwLen, sizeof(DWORD));
if(dwLen && dwBytes == sizeof(DWORD))
dwBytes = WriteBytes(pszString, dwLen);
return dwBytes;
}
DWORD
CRegBlob::ReadString(
LPCSTR * ppszString
)
{
DWORD dwLen, dwBytes = 0;
LPSTR lpszTemp = NULL;
dwBytes = ReadBytes(&dwLen, sizeof(DWORD));
if(dwBytes == sizeof(DWORD))
{
if(dwLen)
{
lpszTemp = (LPSTR)GlobalAlloc(GPTR, dwLen + 1);
if(lpszTemp)
{
dwBytes = ReadBytes(lpszTemp, dwLen);
lpszTemp[dwBytes] = 0;
}
}
}
*ppszString = lpszTemp;
return dwBytes;
}
DWORD
CRegBlob::WriteBytes(
LPCVOID pBytes,
DWORD dwByteCount
)
{
BYTE * pNewBuffer;
// can only do this on write blob
if(FALSE == _fWrite)
return 0;
// grow buffer if necessary
if(_dwBufferLimit - _dwOffset < dwByteCount)
{
DWORD dw = _dwBufferLimit + ((dwByteCount / BLOB_BUFF_GRANULARITY)+1)*BLOB_BUFF_GRANULARITY;
pNewBuffer = (BYTE *)ALLOCATE_FIXED_MEMORY(dw);
if(NULL == pNewBuffer)
{
// failed to get more memory
return 0;
}
memset(pNewBuffer, 0, dw);
memcpy(pNewBuffer, _pBuffer, _dwBufferLimit);
FREE_FIXED_MEMORY(_pBuffer);
_pBuffer = pNewBuffer;
_dwBufferLimit = dw;
}
// copy callers data to buffer
memcpy(_pBuffer + _dwOffset, pBytes, dwByteCount);
_dwOffset += dwByteCount;
// tell caller how much we wrote
return dwByteCount;
}
DWORD
CRegBlob::ReadBytes(
LPVOID pBytes,
DWORD dwByteCount
)
{
DWORD dwActual = _dwBufferLimit - _dwOffset;
// can only do this on read blob
if(_fWrite)
return 0;
// don't read past end of blob
if(dwByteCount < dwActual)
dwActual = dwByteCount;
// copy bytes and increment offset
if(dwActual > 0)
{
memcpy(pBytes, _pBuffer + _dwOffset, dwActual);
_dwOffset += dwActual;
}
// tell caller how much we actually read
return dwActual;
}
///////////////////////////////////////////////////////////////////////////
//
// Helpers to read and write proxy settings
//
///////////////////////////////////////////////////////////////////////////
//
// Maximum size of TOKEN_USER information.
//
#define SIZE_OF_TOKEN_INFORMATION \
sizeof( TOKEN_USER ) \
+ sizeof( SID ) \
+ sizeof( ULONG ) * SID_MAX_SUB_AUTHORITIES
#define MAX_SID_STRING 256
//
// Function Declarations
//
BOOL
InitClientUserString (
LPWSTR pString
)
/*++
Routine Description:
Arguments:
pString - output string of current user
Return Value:
TRUE = success,
FALSE = fail
Returns in pString a ansi string if the impersonated client's
SID can be expanded successfully into Unicode string. If the conversion
was unsuccessful, returns FALSE.
--*/
{
DEBUG_ENTER((DBG_DIALUP,
Bool,
"InitClientUserString",
"%#x",
pString
));
HANDLE TokenHandle;
UCHAR TokenInformation[ SIZE_OF_TOKEN_INFORMATION ];
ULONG ReturnLength;
BOOL Status;
DWORD dwLastError;
UNICODE_STRING UnicodeString;
HMODULE hNtDll;
PCONVERTSID pRtlConvertSid;
/*
if (GlobalIsProcessNtService)
{
char szUserName[10];
DWORD cbUserNameSize = ARRAYSIZE(szUserName);
GlobalUserName.Get(szUserName,&cbUserNameSize);
if (0 == lstrcmpi(szUserName, "SYSTEM"))
{
DEBUG_PRINT(DIALUP, INFO, ("User Profile = %s(env = %d)\n",
szUserName, GlobalIsProcessNtService
));
wcscpy(pString, L".default");
DEBUG_PRINT(DIALUP, INFO, ("User SID = %ws\n",
pString
));
DEBUG_LEAVE(TRUE);
return TRUE;
}
}
*/
//
// get RtlConvertSideToUnicodeString entry point in NTDLL
//
hNtDll = LoadLibrary("ntdll.dll");
if(NULL == hNtDll)
{
return FALSE;
}
pRtlConvertSid = (PCONVERTSID)GetProcAddress(hNtDll, "RtlConvertSidToUnicodeString");
if(NULL == pRtlConvertSid)
{
FreeLibrary(hNtDll);
DEBUG_LEAVE(FALSE);
return FALSE;
}
//
// We can use OpenThreadToken because this server thread
// is impersonating a client
//
Status = OpenThreadToken(
GetCurrentThread(),
TOKEN_READ,
TRUE, // Open as self
&TokenHandle
);
dwLastError = GetLastError();
if( Status == FALSE )
{
DEBUG_PRINT(DIALUP, INFO, ("OpenThreadToken() failed: Error=%d\n",
dwLastError
));
Status = OpenProcessToken(
GetCurrentProcess(),
TOKEN_READ,
&TokenHandle
);
dwLastError = GetLastError();
if( Status == FALSE )
{
DEBUG_LEAVE(FALSE);
return FALSE ;
}
}
//
// Notice that we've allocated enough space for the
// TokenInformation structure. so if we fail, we
// return a NULL pointer indicating failure
//
Status = GetTokenInformation( TokenHandle,
TokenUser,
TokenInformation,
sizeof( TokenInformation ),
&ReturnLength
);
dwLastError = GetLastError();
CloseHandle( TokenHandle );
if ( Status == FALSE ) {
DEBUG_PRINT(DIALUP, INFO, ("GetTokenInformation failed: Error=%d\n",
dwLastError
));
DEBUG_LEAVE(FALSE);
return FALSE;
}
//
// Convert the Sid (pointed to by pSid) to its
// equivalent Unicode string representation.
//
UnicodeString.Length = 0;
UnicodeString.MaximumLength = MAX_SID_STRING;
UnicodeString.Buffer = pString;
Status = (*pRtlConvertSid)(
&UnicodeString,
((PTOKEN_USER)TokenInformation)->User.Sid,
FALSE );
FreeLibrary(hNtDll);
if( !NT_SUCCESS( Status )){
DEBUG_PRINT(DIALUP, INFO, ("RtlConvertSidToUnicodeString failed: Error=%d\n",
Status
));
DEBUG_LEAVE(FALSE);
return FALSE;
}
DEBUG_PRINT(DIALUP, INFO, ("User SID = %ws\n",
pString
));
DEBUG_LEAVE(TRUE);
return TRUE;
}
HKEY
GetClientUserHandle(
IN REGSAM samDesired
)
/*++
Routine Description:
Arguments:
Returns:
---*/
{
DEBUG_ENTER((DBG_DIALUP,
Dword,
"GetClientUserHandle",
"%#x",
samDesired
));
HKEY hKeyClient;
WCHAR String[MAX_SID_STRING];
LONG ReturnValue;
if (!InitClientUserString(String)) {
DEBUG_LEAVE(0);
return NULL ;
}
//
// We now have the Unicode string representation of the
// local client's Sid we'll use this string to open a handle
// to the client's key in the registry.
ReturnValue = RegOpenKeyExW( HKEY_USERS,
String,
0,
samDesired,
&hKeyClient );
//
// If we couldn't get a handle to the local key
// for some reason, return a NULL handle indicating
// failure to obtain a handle to the key
//
if ( ReturnValue != ERROR_SUCCESS )
{
DEBUG_PRINT(DIALUP, INFO, ("RegOpenKeyW failed: Error=%d\n",
ReturnValue
));
DEBUG_ERROR(DIALUP, ReturnValue);
SetLastError( ReturnValue );
DEBUG_LEAVE(0);
return NULL;
}
DEBUG_LEAVE(hKeyClient);
return( hKeyClient );
}
CRefdKey*
FindBaseProxyKey(
VOID
)
/*
** Determine whether proxy settings live in HKLM or HKCU
**
** Returns HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE
**
** Checks \HKLM\SW\MS\Win\CV\Internet Settings\ProxySettingsPerUser. If
** exists and is zero, use HKLM otherwise use HKCU.
*/
{
// grab the cached value
CRefdKey* prk = (CRefdKey*)InterlockedExchangePointer((void**)&g_prkBase, NULL);
if (prk == NULL)
{
HKEY hkeyBase = NULL;
BOOL bSetNewCachedValue = FALSE;
DWORD dwType, dwValue, dwSize = sizeof(DWORD);
if(ERROR_SUCCESS ==
SHGetValue(HKEY_LOCAL_MACHINE, INTERNET_POLICY_KEY,
TEXT("ProxySettingsPerUser"), &dwType, &dwValue, &dwSize) &&
0 == dwValue)
{
hkeyBase = HKEY_LOCAL_MACHINE;
bSetNewCachedValue = TRUE;
}
else
{
//
// Find an HKCU equivalent for this process
//
if(PLATFORM_TYPE_WIN95 == GlobalPlatformType ||
NULL == (hkeyBase = GetClientUserHandle(KEY_QUERY_VALUE | KEY_SET_VALUE)))
{
BOOL fLocalSystem = FALSE;
if (GlobalIsProcessNtService)
{
char szUserName[20];
DWORD cbUserNameSize = ARRAYSIZE(szUserName);
GlobalUserName.Get(szUserName,&cbUserNameSize);
if (0 == lstrcmpi(szUserName, "SYSTEM") ||
0 == lstrcmpi(szUserName, "LOCAL SERVICE") ||
0 == lstrcmpi(szUserName, "NETWORK SERVICE"))
{
fLocalSystem = TRUE;
}
}
if (!fLocalSystem)
{
hkeyBase = HKEY_CURRENT_USER;
bSetNewCachedValue = TRUE;
}
}
else if (!GlobalIsProcessNtService)
{
// only cache the CRefdKey if we are not a service
bSetNewCachedValue = TRUE;
}
}
if (hkeyBase)
{
prk = new CRefdKey(hkeyBase);
if (prk)
{
if (bSetNewCachedValue)
{
// addref it again since we are going to try and stick it in the global
prk->AddRef();
if (InterlockedCompareExchangePointer((void **)&g_prkBase, prk, 0))
{
// someone beat us in the race to fill in g_prkBase, release ours since we
// failed to set it into g_prkBase
prk->Release();
}
}
}
else
{
// we failed to create a CRefdKey, so close the hkeyBase if it is not a predefined handle
if ((hkeyBase != HKEY_LOCAL_MACHINE) &&
(hkeyBase != HKEY_CURRENT_USER))
{
RegCloseKey(hkeyBase);
}
}
}
}
else
{
// addref the global and put it back
prk->AddRef();
CRefdKey* prkOld = (CRefdKey*)InterlockedExchangePointer((void**)&g_prkBase, prk);
if (prkOld)
{
// someone also stuck a cached value in g_prkBase! Since we just put ours back
// in the global cache, we need to release theirs.
prkOld->Release();
}
}
return prk;
}
BOOL
CloseBaseProxyKey(
CRefdKey* prk
)
{
if (prk)
{
prk->Release();
return TRUE;
}
return FALSE;
}
DWORD
ReadProxySettings(
LPINTERNET_PROXY_INFO_EX pInfo
)
{
CRegBlob r(FALSE);
LPCSTR pszConnectionName;
LPCSTR pszSavedConnectionName;
DWORD error = ERROR_SUCCESS;
long lRes;
DWORD i;
BOOL fSave = FALSE, fLanConnection = FALSE;
CRefdKey* prkBase = NULL;
DWORD dwStructVersion;
DEBUG_ENTER((DBG_DIALUP,
Dword,
"ReadProxySettings",
"%#x",
pInfo
));
// verify pInfo
if(NULL == pInfo || pInfo->dwStructSize != sizeof(INTERNET_PROXY_INFO_EX))
{
DEBUG_LEAVE(ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
// take mutex
WaitForSingleObject(g_hProxyRegMutex, INFINITE);
// figure out connection name (NULL == 'network')
pszConnectionName = pInfo->lpszConnectionName;
pszSavedConnectionName = pInfo->lpszConnectionName;
if(NULL == pszConnectionName || 0 == *pszConnectionName)
{
fLanConnection = TRUE;
pszConnectionName = "DefaultConnectionSettings";
}
// figure out base key
prkBase = FindBaseProxyKey();
if (prkBase == NULL)
{
error = ERROR_FILE_NOT_FOUND;
goto quit;
}
// initialize structure
memset(pInfo, 0, sizeof(*pInfo));
pInfo->dwStructSize = sizeof(*pInfo);
pInfo->lpszConnectionName = pszSavedConnectionName;
pInfo->dwFlags = PROXY_TYPE_DIRECT;
// init blob
lRes = r.Init(prkBase->GetKey(), szRegPathConnections, pszConnectionName);
if(lRes)
{
error = lRes;
goto quit;
}
// read fields from blob
if(0 == r.ReadBytes(&dwStructVersion, sizeof(DWORD)) ||
(dwStructVersion < INTERNET_PROXY_INFO_EX_VERSION))
{
// blob didn't exist or in correct format - set default values
// If not on a lan connection and we're set to inherit lan settings
if(!fLanConnection && GlobalUseLanSettings)
{
// Ensure we're reading the LAN proxy information.
pInfo->lpszConnectionName = NULL;
// Get proxy settings into pInfo
lRes = ReadProxySettings(pInfo);
if(lRes)
{
error = lRes;
goto quit;
}
// Restore connection name
pInfo->lpszConnectionName = pszSavedConnectionName;
}
else
{
#ifndef UNIX
//
// All lan connections and overridden dial-ups get autodetect
//
if(fLanConnection || EnableAutodiscoverForDialup())
{
pInfo->dwFlags |= PROXY_TYPE_AUTO_DETECT;
}
#else
;
#endif /* UNIX */
}
}
else
{
// read the rest of the blob
r.ReadBytes(&pInfo->dwCurrentSettingsVersion, sizeof(DWORD));
r.ReadBytes(&pInfo->dwFlags, sizeof(DWORD));
r.ReadString(&pInfo->lpszProxy);
r.ReadString(&pInfo->lpszProxyBypass);
r.ReadString(&pInfo->lpszAutoconfigUrl);
r.ReadBytes(&pInfo->dwAutoDiscoveryFlags, sizeof(DWORD));
r.ReadString(&pInfo->lpszLastKnownGoodAutoConfigUrl);
r.ReadBytes(&pInfo->ftLastKnownDetectTime, sizeof(FILETIME));
// read interface ips
r.ReadBytes(&pInfo->dwDetectedInterfaceIpCount, sizeof(DWORD));
if(pInfo->dwDetectedInterfaceIpCount)
{
pInfo->pdwDetectedInterfaceIp = (DWORD *)GlobalAlloc(GPTR, sizeof(DWORD) * pInfo->dwDetectedInterfaceIpCount);
if(pInfo->pdwDetectedInterfaceIp)
{
for(i=0; i<pInfo->dwDetectedInterfaceIpCount; i++)
{
r.ReadBytes(&pInfo->pdwDetectedInterfaceIp[i], sizeof(DWORD));
}
}
}
r.ReadString(&pInfo->lpszAutoconfigSecondaryUrl);
r.ReadBytes(&pInfo->dwAutoconfigReloadDelayMins, sizeof(DWORD));
}
// Netware hack. Don't ever allow autodiscovery to be turned on if
// we're running the netware client. It faults and it isn't useful
// anyway.
//
// Some other stacks may also fault. If we find one, don't autodetect.
if(GlobalRunningNovellClient32 || g_fGetHostByNameNULLFails)
{
pInfo->dwFlags &= ~PROXY_TYPE_AUTO_DETECT;
// save this back so we don't ever try again
fSave = TRUE;
}
DEBUG_PRINT(DIALUP, INFO, ("conn=%s, vers=%u, flag=%X, prox=%s, by=%s, acu=%s\n",
pszConnectionName,
pInfo->dwCurrentSettingsVersion,
pInfo->dwFlags,
(pInfo->lpszProxy ? pInfo->lpszProxy : "<none>"),
(pInfo->lpszProxyBypass ? pInfo->lpszProxyBypass : "<none>"),
(pInfo->lpszAutoconfigUrl ? pInfo->lpszAutoconfigUrl : "<none>")
));
if(fSave)
{
WriteProxySettings(pInfo, TRUE);
}
quit:
CloseBaseProxyKey(prkBase);
// free mutex
ReleaseMutex(g_hProxyRegMutex);
DEBUG_LEAVE(error);
return error;
}
DWORD
WriteProxySettings(
LPINTERNET_PROXY_INFO_EX pInfo,
BOOL fForceUpdate
)
// serialize this. Only write if dwCurrentSettingsVersion member has been
// incremented by exactly 1.
{
DEBUG_ENTER((DBG_DIALUP,
Dword,
"WriteProxySettings",
"%#x, %B",
pInfo,
fForceUpdate
));
CRegBlob r(TRUE);
CRegBlob CurrentVersion(FALSE);
LPCSTR pszConnectionName;
long lRes;
DWORD i;
DWORD dwCurrentVersion;
DWORD dwCurrentStructSize;
DWORD error = ERROR_SUCCESS;
DWORD dwStructVersion = INTERNET_PROXY_INFO_EX_VERSION;
CRefdKey* prkBase = NULL;
//
// verify pInfo
//
if(NULL == pInfo || pInfo->dwStructSize != sizeof(INTERNET_PROXY_INFO_EX))
{
r.Abandon();
DEBUG_LEAVE(ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
// take mutex
WaitForSingleObject(g_hProxyRegMutex, INFINITE);
//
// figure out connection name (NULL == 'network')
//
pszConnectionName = pInfo->lpszConnectionName;
if(NULL == pszConnectionName || 0 == *pszConnectionName)
{
pszConnectionName = "DefaultConnectionSettings";
}
//
// For forced update changes, turn off this FLAG since,
// any major change in settings indicates a possible FIX
// for detection issues.
//
if ( fForceUpdate ) {
pInfo->dwAutoDiscoveryFlags &= ~(AUTO_PROXY_FLAG_DETECTION_SUSPECT);
}
DEBUG_PRINT(DIALUP, INFO, ("conn=%s, vers=%u, flag=%X, a-flag=%X, prox=%s, by=%s, acu=%s\n",
pszConnectionName,
pInfo->dwCurrentSettingsVersion,
pInfo->dwFlags,
pInfo->dwAutoDiscoveryFlags,
(pInfo->lpszProxy ? pInfo->lpszProxy : "<none>"),
(pInfo->lpszProxyBypass ? pInfo->lpszProxyBypass : "<none>"),
(pInfo->lpszAutoconfigUrl ? pInfo->lpszAutoconfigUrl : "<none>")
));
// figure out base key
prkBase = FindBaseProxyKey();
if (prkBase == NULL)
{
error = ERROR_FILE_NOT_FOUND;
goto quit;
}
//
// Get current version and verify another write hasn't happened
//
// Second dword is version
//
lRes = CurrentVersion.Init(prkBase->GetKey(), szRegPathConnections, pszConnectionName);
if(lRes || IsInGUIModeSetup())
{
r.Abandon();
error = lRes;
goto quit;
}
dwCurrentStructSize = sizeof(*pInfo);
dwCurrentVersion = 0;
CurrentVersion.ReadBytes(&dwCurrentStructSize, sizeof(DWORD)); // struct size
CurrentVersion.ReadBytes(&dwCurrentVersion, sizeof(DWORD)); // actual version
if(dwCurrentVersion != pInfo->dwCurrentSettingsVersion)
{
// someone else has written since this read. If we aren't in force
// mode, bail out
if((fForceUpdate == FALSE) &&
(dwCurrentStructSize >= sizeof(*pInfo)))
{
r.Abandon();
error = ERROR_INVALID_DATA;
goto quit;
}
// update to most recent version
pInfo->dwCurrentSettingsVersion = dwCurrentVersion;
}
//
// increment version
//
pInfo->dwCurrentSettingsVersion++;
//
// init blob
//
lRes = r.Init(prkBase->GetKey(), szRegPathConnections, pszConnectionName);
if(lRes)
{
r.Abandon();
error = lRes;
goto quit;
}
//
// write fields to blob
//
r.WriteBytes(&dwStructVersion, sizeof(DWORD)); // used for data format checking
r.WriteBytes(&pInfo->dwCurrentSettingsVersion, sizeof(DWORD));
r.WriteBytes(&pInfo->dwFlags, sizeof(DWORD));
r.WriteString(pInfo->lpszProxy);
r.WriteString(pInfo->lpszProxyBypass);
r.WriteString(pInfo->lpszAutoconfigUrl);
r.WriteBytes(&pInfo->dwAutoDiscoveryFlags, sizeof(DWORD));
r.WriteString(pInfo->lpszLastKnownGoodAutoConfigUrl);
r.WriteBytes(&pInfo->ftLastKnownDetectTime, sizeof(FILETIME));
//
// write interface ip list
//
r.WriteBytes(&pInfo->dwDetectedInterfaceIpCount, sizeof(DWORD));
for(i=0; i<pInfo->dwDetectedInterfaceIpCount; i++)
{
r.WriteBytes(&pInfo->pdwDetectedInterfaceIp[i], sizeof(DWORD));
}
r.WriteString(pInfo->lpszAutoconfigSecondaryUrl);
r.WriteBytes(&pInfo->dwAutoconfigReloadDelayMins, sizeof(DWORD));
quit:
CloseBaseProxyKey(prkBase);
// free mutex
ReleaseMutex(g_hProxyRegMutex);
DEBUG_LEAVE(error);
return error;
}
void
CleanProxyStruct(
LPINTERNET_PROXY_INFO_EX pInfo
)
{
if(pInfo->lpszConnectionName) GlobalFree((LPSTR) pInfo->lpszConnectionName);
if(pInfo->lpszProxy) GlobalFree((LPSTR) pInfo->lpszProxy);
if(pInfo->lpszProxyBypass) GlobalFree((LPSTR) pInfo->lpszProxyBypass);
if(pInfo->lpszAutoconfigUrl) GlobalFree((LPSTR) pInfo->lpszAutoconfigUrl);
if(pInfo->lpszLastKnownGoodAutoConfigUrl) GlobalFree((LPSTR) pInfo->lpszLastKnownGoodAutoConfigUrl);
if(pInfo->pdwDetectedInterfaceIp) GlobalFree(pInfo->pdwDetectedInterfaceIp);
memset(pInfo, 0, sizeof(INTERNET_PROXY_INFO_EX));
pInfo->dwFlags = PROXY_TYPE_DIRECT;
}
DWORD
SetPerConnOptions(
HINTERNET hInternet,
BOOL fIsAutoProxyThread,
LPINTERNET_PER_CONN_OPTION_LISTA pList
)
{
INTERNET_PROXY_INFO_EX info, info_temp;
DWORD i, dwError = ERROR_SUCCESS;
BOOL fCommit = FALSE;
LPSTR pszCopy, pszNew;
BOOL fFreeCopy = FALSE;
memset(&info, 0, sizeof(info));
info.dwStructSize = sizeof(info);
if ( hInternet == NULL )
{
//
// If auto-proxy thread then try to get the settings
// from the auto-proxy thread
//
if ( ! fIsAutoProxyThread ||
! GlobalProxyInfo.GetAutoProxyThreadSettings(&info) ||
! IsConnectionMatch(info.lpszConnectionName, pList->pszConnection))
{
fFreeCopy = TRUE;
info.lpszConnectionName = pList->pszConnection;
CheckForUpgrade();
dwError = ReadProxySettings(&info);
if (dwError != ERROR_SUCCESS)
{
return dwError;
}
}
}
// loop through option list and set members
for(i=0; i<pList->dwOptionCount; i++)
{
pszNew = NULL;
switch(pList->pOptions[i].dwOption)
{
case INTERNET_PER_CONN_PROXY_SERVER:
case INTERNET_PER_CONN_PROXY_BYPASS:
case INTERNET_PER_CONN_AUTOCONFIG_URL:
case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
// make a copy of the string passed in for these guys
pszCopy = pList->pOptions[i].Value.pszValue;
if(pszCopy)
{
pszNew = (LPSTR)GlobalAlloc(GPTR, lstrlen(pszCopy) + 1);
if(pszNew)
{
lstrcpy(pszNew, pszCopy);
}
else
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
pList->dwOptionError = i;
}
}
break;
}
if(dwError)
{
fCommit = FALSE;
break;
}
switch(pList->pOptions[i].dwOption)
{
case INTERNET_PER_CONN_FLAGS:
info.dwFlags = pList->pOptions[i].Value.dwValue;
fCommit = TRUE;
break;
case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
info.dwAutoDiscoveryFlags = pList->pOptions[i].Value.dwValue;
fCommit = TRUE;
break;
case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
info.dwAutoconfigReloadDelayMins = pList->pOptions[i].Value.dwValue;
fCommit = TRUE;
break;
case INTERNET_PER_CONN_PROXY_SERVER:
if(info.lpszProxy)
GlobalFree((LPSTR)info.lpszProxy);
info.lpszProxy = pszNew;
fCommit = TRUE;
break;
case INTERNET_PER_CONN_PROXY_BYPASS:
if(info.lpszProxyBypass)
GlobalFree((LPSTR)info.lpszProxyBypass);
info.lpszProxyBypass = pszNew;
fCommit = TRUE;
break;
case INTERNET_PER_CONN_AUTOCONFIG_URL:
if(info.lpszAutoconfigUrl)
GlobalFree((LPSTR)info.lpszAutoconfigUrl);
info.lpszAutoconfigUrl = pszNew;
fCommit = TRUE;
break;
case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
if(info.lpszAutoconfigSecondaryUrl)
GlobalFree((LPSTR)info.lpszAutoconfigSecondaryUrl);
info.lpszAutoconfigSecondaryUrl = pszNew;
fCommit = TRUE;
break;
case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
dwError = ERROR_INTERNET_OPTION_NOT_SETTABLE;
pList->dwOptionError = i;
break;
case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
dwError = ERROR_INTERNET_OPTION_NOT_SETTABLE;
pList->dwOptionError = i;
break;
default:
dwError = ERROR_INVALID_PARAMETER;
pList->dwOptionError = i;
break;
}
if(dwError)
{
fCommit = FALSE;
break;
}
}
if(fCommit)
{
if ( hInternet == NULL )
{
memset(&info_temp, 0, sizeof(info_temp));
info_temp.dwStructSize = sizeof(info_temp);
if ( ! fIsAutoProxyThread ||
! GlobalProxyInfo.GetAutoProxyThreadSettings(&info_temp) ||
! IsConnectionMatch(info_temp.lpszConnectionName, pList->pszConnection) ||
! GlobalProxyInfo.SetAutoProxyThreadSettings(&info))
{
WriteProxySettings(&info, TRUE);
// update legacy settings with new values
info.lpszConnectionName = LEGACY_SAVE_NAME;
WriteLegacyProxyInfo(szRegPathInternetSettings, &info, TRUE);
WriteProxySettings(&info, TRUE);
}
}
else
{
GlobalProxyInfo.SetProxySettings(&info, TRUE);
}
}
if ( fFreeCopy ) {
info.lpszConnectionName = NULL; // we don't allocate this field
CleanProxyStruct(&info);
}
return dwError;
}
DWORD
QueryPerConnOptions(
HINTERNET hInternet,
BOOL fIsAutoProxyThread,
LPINTERNET_PER_CONN_OPTION_LISTA pList
)
{
INTERNET_PROXY_INFO_EX info;
LPCSTR pszCopy;
LPSTR pszNew;
DWORD i, dwError = ERROR_SUCCESS;
BOOL fFreeCopy = FALSE;
pList->dwOptionError = 0;
memset(&info, 0, sizeof(info));
info.dwStructSize = sizeof(info);
info.lpszConnectionName = pList->pszConnection;
if ( hInternet == NULL )
{
if ( ! fIsAutoProxyThread ||
! GlobalProxyInfo.GetAutoProxyThreadSettings(&info) ||
! IsConnectionMatch(info.lpszConnectionName, pList->pszConnection))
{
CheckForUpgrade();
dwError = ReadProxySettings(&info);
if (dwError != ERROR_SUCCESS)
{
return dwError;
}
fFreeCopy = TRUE;
}
}
else
{
GlobalProxyInfo.GetProxySettings(&info, FALSE);
}
// loop through option list and fill in members
for(i=0; i<pList->dwOptionCount; i++)
{
pList->pOptions[i].Value.pszValue = NULL;
pszCopy = NULL;
switch(pList->pOptions[i].dwOption)
{
case INTERNET_PER_CONN_FLAGS:
pList->pOptions[i].Value.dwValue = info.dwFlags;
break;
case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
pList->pOptions[i].Value.dwValue = info.dwAutoDiscoveryFlags;
break;
case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
pList->pOptions[i].Value.dwValue = info.dwAutoconfigReloadDelayMins;
break;
case INTERNET_PER_CONN_PROXY_SERVER:
pszCopy = info.lpszProxy;
break;
case INTERNET_PER_CONN_PROXY_BYPASS:
pszCopy = info.lpszProxyBypass;
break;
case INTERNET_PER_CONN_AUTOCONFIG_URL:
pszCopy = info.lpszAutoconfigUrl;
break;
case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
pszCopy = info.lpszAutoconfigSecondaryUrl;
break;
case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
pszCopy = info.lpszLastKnownGoodAutoConfigUrl;
break;
case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
*(LONGLONG *) &(pList->pOptions[i].Value.ftValue) = *(LONGLONG *) &(info.ftLastKnownDetectTime);
break;
default:
dwError = ERROR_INVALID_PARAMETER;
pList->dwOptionError = i;
break;
}
// if this is a string value, make a copy of the string for the
// caller
if(pszCopy)
{
// make a copy of the string and stick it in the option
pszNew = (LPSTR)GlobalAlloc(GPTR, lstrlen(pszCopy) + 1);
if(pszNew)
{
lstrcpy(pszNew, pszCopy);
pList->pOptions[i].Value.pszValue = pszNew;
}
else
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
pList->dwOptionError = i;
}
}
if(dwError)
{
break;
}
}
if (dwError)
{
// If an error has occurred, we should get rid of any strings that
// we've allocated.
for (i=0; i<pList->dwOptionError; i++)
{
switch(pList->pOptions[i].dwOption)
{
case INTERNET_PER_CONN_PROXY_SERVER:
case INTERNET_PER_CONN_PROXY_BYPASS:
case INTERNET_PER_CONN_AUTOCONFIG_URL:
case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
if (pList->pOptions[i].Value.pszValue)
{
GlobalFree(pList->pOptions[i].Value.pszValue);
pList->pOptions[i].Value.pszValue = NULL;
}
break;
default:
break;
}
}
}
if ( fFreeCopy ) {
info.lpszConnectionName = NULL; // we don't allocate this field
CleanProxyStruct(&info);
}
return dwError;
}
BOOL
ReadLegacyProxyInfo(
IN LPCTSTR pszKey,
LPINTERNET_PROXY_INFO_EX pProxy
)
/*++
Routine Description:
Reads legacy proxy information from a specified key.
Arguments:
pszKey - key from which to read proxy info
pProxy - pointer to PROXY structure to store info
Return Value:
BOOL
TRUE - success
FALSE - failed
--*/
{
DEBUG_ENTER((DBG_DIALUP,
Bool,
"ReadLegacyProxyInfo",
"%#x (%q), %#x",
pszKey,
pszKey,
pProxy
));
BOOL fSuccess = FALSE;
HKEY hKey;
CRefdKey* prkBase;
DWORD dwSize, dwValue;
pProxy->dwFlags = PROXY_TYPE_DIRECT;
prkBase = FindBaseProxyKey();
if(prkBase &&
(ERROR_SUCCESS == REGOPENKEYEX(prkBase->GetKey(), pszKey, NULL,
KEY_READ, &hKey))) {
// read enable
dwSize = sizeof(DWORD);
if(ERROR_SUCCESS != RegQueryValueEx(hKey, szRegValProxyEnabled,
NULL, NULL, (LPBYTE)&dwValue, &dwSize)) {
dwValue = 0;
}
if(dwValue)
{
pProxy->dwFlags |= PROXY_TYPE_PROXY;
}
// read server
dwSize = INTERNET_MAX_URL_LENGTH;
pProxy->lpszProxy = (LPSTR)GlobalAlloc(GMEM_FIXED, dwSize);
if(pProxy->lpszProxy)
{
if(ERROR_SUCCESS != RegQueryValueEx(hKey, REGSTR_VAL_PROXYSERVER,
NULL, NULL, (LPBYTE)pProxy->lpszProxy, &dwSize) ||
(dwSize == 0) ||
(*pProxy->lpszProxy == '\0'))
{
GlobalFree((LPVOID)pProxy->lpszProxy);
pProxy->lpszProxy = NULL;
}
}
// read override
dwSize = INTERNET_MAX_URL_LENGTH;
pProxy->lpszProxyBypass = (LPSTR)GlobalAlloc(GMEM_FIXED, dwSize);
if(pProxy->lpszProxyBypass)
{
if(ERROR_SUCCESS != RegQueryValueEx(hKey, REGSTR_VAL_PROXYOVERRIDE,
NULL, NULL, (LPBYTE)pProxy->lpszProxyBypass, &dwSize) ||
(dwSize == 0) ||
(*pProxy->lpszProxyBypass == '\0'))
{
GlobalFree((LPVOID)pProxy->lpszProxyBypass);
pProxy->lpszProxyBypass = NULL;
}
}
// read autoconfig URL
dwSize = INTERNET_MAX_URL_LENGTH;
pProxy->lpszAutoconfigUrl = (LPSTR)GlobalAlloc(GMEM_FIXED, dwSize);
if(pProxy->lpszAutoconfigUrl)
{
if(ERROR_SUCCESS != RegQueryValueEx(hKey, szLegacyAutoConfigURL,
NULL, NULL, (LPBYTE)pProxy->lpszAutoconfigUrl, &dwSize) ||
(dwSize == 0) ||
(*pProxy->lpszAutoconfigUrl == '\0'))
{
// clear out
GlobalFree((LPVOID)pProxy->lpszAutoconfigUrl);
pProxy->lpszAutoconfigUrl = NULL;
}
else
{
// turn on if there's an URL
pProxy->dwFlags |= PROXY_TYPE_AUTO_PROXY_URL;
}
}
REGCLOSEKEY(hKey);
fSuccess = TRUE;
}
DEBUG_PRINT(DIALUP, INFO, ("flag=%x, prox=%s, by=%s, acu=%s\n",
pProxy->dwFlags,
(pProxy->lpszProxy ? pProxy->lpszProxy : "<none>"),
(pProxy->lpszProxyBypass ? pProxy->lpszProxyBypass : "<none>"),
(pProxy->lpszAutoconfigUrl ? pProxy->lpszAutoconfigUrl : "<none>")
));
CloseBaseProxyKey(prkBase);
DEBUG_LEAVE(fSuccess);
return fSuccess;
}
BOOL
WriteLegacyProxyInfo(
IN LPCTSTR pszKey,
LPINTERNET_PROXY_INFO_EX pProxy,
IN BOOL fOverwrite
)
/*++
Routine Description:
Writes legacy proxy info a specified key
Arguments:
pszKey - key to write proxy inf to
pProxy - pointer to PROXY structure containing info to write
fOverwrite - If TRUE, overwrite existing info. otherwise only create
Return Value:
BOOL
TRUE - success
FALSE - failed
--*/
{
DEBUG_ENTER((DBG_DIALUP,
Bool,
"WriteLegacyProxyInfo",
"%#x (%q), %#x, %B",
pszKey,
pszKey,
pProxy,
fOverwrite
));
BOOL fSuccess = FALSE;
HKEY hKey;
CRefdKey* prkBase;
DWORD dwDisposition, dwValue;
prkBase = FindBaseProxyKey();
if (!prkBase)
{
goto quit;
}
if (IsInGUIModeSetup())
{
fSuccess = TRUE; // don't return a failure, just skip
goto quit;
}
DEBUG_PRINT(DIALUP, INFO, ("flag=%x, prox=%s, by=%s, acu=%s\n",
pProxy->dwFlags,
(pProxy->lpszProxy ? pProxy->lpszProxy : "<none>"),
(pProxy->lpszProxyBypass ? pProxy->lpszProxyBypass : "<none>"),
(pProxy->lpszAutoconfigUrl ? pProxy->lpszAutoconfigUrl : "<none>")
));
if(ERROR_SUCCESS == REGCREATEKEYEX(prkBase->GetKey(), pszKey, 0, "", 0,
KEY_WRITE, NULL, &hKey, &dwDisposition)) {
fSuccess = TRUE;
//
// if we're not supposed to overwrite, check enable key. If it
// exists, bail
//
if(FALSE == fOverwrite) {
DWORD dwEnable, dwSize = sizeof(DWORD);
if(ERROR_SUCCESS == RegQueryValueEx(hKey, szRegValProxyEnabled,
NULL, NULL, (LPBYTE)&dwEnable, &dwSize)) {
REGCLOSEKEY(hKey);
DEBUG_PRINT(DIALUP, INFO, ("Overwrite not set.\n"));
goto quit;
}
}
// write enable
dwValue = 0;
if(pProxy->dwFlags & PROXY_TYPE_PROXY)
dwValue = 1;
DEBUG_PRINT(DIALUP, INFO, ("Setting legacy enabled=%d\n", dwValue));
if(ERROR_SUCCESS != RegSetValueEx(hKey, szRegValProxyEnabled, 0,
REG_DWORD, (BYTE *)&dwValue, sizeof(DWORD)))
fSuccess = FALSE;
// write server
if(pProxy->lpszProxy)
{
if(ERROR_SUCCESS != RegSetValueEx(hKey, REGSTR_VAL_PROXYSERVER, 0,
REG_SZ, (BYTE *)pProxy->lpszProxy,
lstrlen(pProxy->lpszProxy)))
fSuccess = FALSE;
}
else
{
RegDeleteValue(hKey, REGSTR_VAL_PROXYSERVER);
DEBUG_PRINT(DIALUP, INFO, ("Deleting legacy server\n"));
}
// write override
if(pProxy->lpszProxyBypass)
{
if(ERROR_SUCCESS != RegSetValueEx(hKey, REGSTR_VAL_PROXYOVERRIDE, 0,
REG_SZ, (BYTE *)pProxy->lpszProxyBypass,
lstrlen(pProxy->lpszProxyBypass)))
fSuccess = FALSE;
}
else
{
RegDeleteValue(hKey, REGSTR_VAL_PROXYOVERRIDE);
DEBUG_PRINT(DIALUP, INFO, ("Deleting legacy override\n"));
}
// write autoconfig url
if( (pProxy->dwFlags & PROXY_TYPE_AUTO_PROXY_URL) &&
pProxy->lpszAutoconfigUrl)
{
if(ERROR_SUCCESS != RegSetValueEx(hKey, szLegacyAutoConfigURL, 0,
REG_SZ, (BYTE *)pProxy->lpszAutoconfigUrl,
lstrlen(pProxy->lpszAutoconfigUrl)))
{
fSuccess = FALSE;
}
}
else
{
RegDeleteValue(hKey, szLegacyAutoConfigURL);
DEBUG_PRINT(DIALUP, INFO, ("Deleting legacy autoconfig url\n"));
}
REGCLOSEKEY(hKey);
}
//
// duplicate proxy enable reg settings to HKEY_CURRENT_CONFIG so
// shell doesn't blow away the setting when it migrates.
//
dwValue = (pProxy->dwFlags & PROXY_TYPE_PROXY) ? 1 : 0;
SHSetValue(HKEY_CURRENT_CONFIG, pszKey, szRegValProxyEnabled,
REG_DWORD, &dwValue, sizeof(DWORD));
quit:
CloseBaseProxyKey(prkBase);
DEBUG_LEAVE(fSuccess);
return fSuccess;
}