#include "wininetp.h" static const CHAR szRegPathConnections[] = REGSTR_PATH_INTERNET_SETTINGS "\\Connections"; // 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; } /////////////////////////////////////////////////////////////////////////// // // 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); } else { // If not writing, then use RegOpenKeyEx so we don't need // registry write permissions. lRes = REGOPENKEYEX(hBaseKey, pszSubKey, 0, regsam, &_hkey); } 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; } // // Function Declarations // DWORD LoadProxySettings() /* ** Load global proxy info from registry. ** */ { DWORD error; // // Get proxy struct for proxy object // INTERNET_PROXY_INFO_EX info; memset(&info, 0, sizeof(info)); info.dwStructSize = sizeof(info); info.lpszConnectionName = NULL; // // Read LAN proxy settings and stuff them into the GlobalProxyInfo object. // error = ReadProxySettings(&info); if (error == ERROR_SUCCESS) { error = g_pGlobalProxyInfo->SetProxySettings(&info, FALSE); info.lpszConnectionName = NULL; // we don't allocate this field CleanProxyStruct(&info); } return error; } #define INTERNET_SETTINGS_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings" HKEY FindBaseProxyKey( VOID ) /* ** Determine whether proxy settings live in HKLM or HKCU ** ** WinHttpX is hard-coded to always use HKEY_LOCAL_MACHINE ** */ { return HKEY_LOCAL_MACHINE; } DWORD ReadProxySettings( LPINTERNET_PROXY_INFO_EX pInfo ) { CRegBlob r(FALSE); LPCSTR pszConnectionName; LPCSTR pszSavedConnectionName; DWORD error = ERROR_SUCCESS; long lRes; DWORD i; HKEY hBaseKey; 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; } // figure out connection name (NULL == 'network') pszConnectionName = pInfo->lpszConnectionName; pszSavedConnectionName = pInfo->lpszConnectionName; if(NULL == pszConnectionName || 0 == *pszConnectionName) { pszConnectionName = "WinHttpSettings"; } // figure out base key hBaseKey = FindBaseProxyKey(); // initialize structure memset(pInfo, 0, sizeof(*pInfo)); pInfo->dwStructSize = sizeof(*pInfo); pInfo->lpszConnectionName = pszSavedConnectionName; pInfo->dwFlags = PROXY_TYPE_DIRECT; // init blob lRes = r.Init(hBaseKey, szRegPathConnections, pszConnectionName); if(lRes) { error = (lRes == ERROR_FILE_NOT_FOUND) ? ERROR_SUCCESS : lRes; goto quit; } // read fields from blob if(0 == r.ReadBytes(&pInfo->dwStructSize, sizeof(DWORD)) || (pInfo->dwStructSize < sizeof(*pInfo))) { // blob didn't exist or in correct format - set default values pInfo->dwStructSize = sizeof(*pInfo); } 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); } // // WinHttpX does not support proxy autodection or autoconfig URL's, // so make sure those PROXY_TYPE flags are turned off. // pInfo->dwFlags &= ~(PROXY_TYPE_AUTO_DETECT | PROXY_TYPE_AUTO_PROXY_URL); DEBUG_PRINT(DIALUP, INFO, ("conn=%s, vers=%u, flag=%X, prox=%s, by=%s\n", pszConnectionName, pInfo->dwCurrentSettingsVersion, pInfo->dwFlags, (pInfo->lpszProxy ? pInfo->lpszProxy : ""), (pInfo->lpszProxyBypass ? pInfo->lpszProxyBypass : "") )); quit: 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); 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; DWORD i, dwError = ERROR_SUCCESS; BOOL fCommit = FALSE; LPSTR pszCopy, pszNew; INET_ASSERT(fIsAutoProxyThread == FALSE); INET_ASSERT(hInternet != NULL); memset(&info, 0, sizeof(info)); info.dwStructSize = sizeof(info); // loop through option list and set members for(i=0; idwOptionCount; i++) { pszNew = NULL; switch(pList->pOptions[i].dwOption) { case INTERNET_PER_CONN_PROXY_SERVER: case INTERNET_PER_CONN_PROXY_BYPASS: // 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_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_AUTODISCOVERY_FLAGS: case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS: case INTERNET_PER_CONN_AUTOCONFIG_URL: case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME: case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: default: dwError = ERROR_INVALID_PARAMETER; pList->dwOptionError = i; break; } if(dwError) { fCommit = FALSE; break; } } if (fCommit && hInternet) { g_pGlobalProxyInfo->SetProxySettings(&info, TRUE); } 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 ) { #ifndef WININET_SERVER_CORE if ( ! fIsAutoProxyThread || ! g_pGlobalProxyInfo->GetAutoProxyThreadSettings(&info) || ! IsConnectionMatch(info.lpszConnectionName, pList->pszConnection)) { CheckForUpgrade(); ReadProxySettings(&info); fFreeCopy = TRUE; } #endif //!WININET_SERVER_CORE } else { g_pGlobalProxyInfo->GetProxySettings(&info, FALSE); } // loop through option list and fill in members for(i=0; idwOptionCount; 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_PROXY_SERVER: pszCopy = info.lpszProxy; break; case INTERNET_PER_CONN_PROXY_BYPASS: pszCopy = info.lpszProxyBypass; 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; idwOptionError; i++) { switch(pList->pOptions[i].dwOption) { case INTERNET_PER_CONN_PROXY_SERVER: case INTERNET_PER_CONN_PROXY_BYPASS: 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; }