/*++ Copyright (c) 1995 Microsoft Corporation Module Name: globals.cxx Abstract: Contains global data items for WININET.DLL and initialization function Contents: GlobalDllInitialize GlobalDllTerminate GlobalDataInitialize GlobalDataTerminate IsHttp1_1 SetOfflineUserState GetWininetUserName ChangeGlobalSettings Author: Richard L Firth (rfirth) 15-Jul-1995 Revision History: 15-Jul-1995 rfirth Created 07-Oct-1998 joshco updated minor version number 1->2 --*/ #include #include #include #include // // WinHttpX major & minor versions - allow to be defined externally // #if !defined(WINHTTPX_MAJOR_VERSION) #define WINHTTPX_MAJOR_VERSION 5 #endif #if !defined(WINHTTPX_MINOR_VERSION) #define WINHTTPX_MINOR_VERSION 1 #endif // // external functions // #if INET_DEBUG VOID InitDebugSock( VOID ); #endif // // global DLL state data // GLOBAL HINSTANCE GlobalDllHandle = NULL; GLOBAL DWORD GlobalPlatformType; GLOBAL DWORD GlobalPlatformVersion5; GLOBAL DWORD GlobalPlatformMillennium = FALSE; GLOBAL BOOL GlobalDataInitialized = FALSE; GLOBAL HANDLE g_hCompletionPort = NULL; GLOBAL LPOVERLAPPED g_lpCustomOverlapped = NULL; GLOBAL DWORD g_cNumIOCPThreads = 0; #if INET_DEBUG LONG g_cWSACompletions = 0; LONG g_cCustomCompletions = 0; #endif // // WinInet DLL version information (mainly for diagnostics) // #if !defined(VER_PRODUCTBUILD) #define VER_PRODUCTBUILD 0 #endif GLOBAL DWORD InternetBuildNumber = VER_PRODUCTBUILD; // // transport-based time-outs, etc. // #ifndef unix GLOBAL const DWORD GlobalConnectTimeout = DEFAULT_CONNECT_TIMEOUT; #else GLOBAL const DWORD GlobalConnectTimeout = 1 * 60 * 1000; #endif /* unix */ GLOBAL const DWORD GlobalResolveTimeout = DEFAULT_RESOLVE_TIMEOUT; GLOBAL const DWORD GlobalConnectRetries = DEFAULT_CONNECT_RETRIES; GLOBAL const DWORD GlobalSendTimeout = DEFAULT_SEND_TIMEOUT; GLOBAL const DWORD GlobalReceiveTimeout = DEFAULT_RECEIVE_TIMEOUT; GLOBAL const DWORD GlobalTransportPacketLength = DEFAULT_TRANSPORT_PACKET_LENGTH; GLOBAL const DWORD GlobalKeepAliveSocketTimeout = DEFAULT_KEEP_ALIVE_TIMEOUT; GLOBAL const DWORD GlobalSocketSendBufferLength = DEFAULT_SOCKET_SEND_BUFFER_LENGTH; GLOBAL const DWORD GlobalSocketReceiveBufferLength = DEFAULT_SOCKET_RECEIVE_BUFFER_LENGTH; GLOBAL const DWORD GlobalMaxHttpRedirects = DEFAULT_MAX_HTTP_REDIRECTS; GLOBAL const DWORD GlobalConnectionInactiveTimeout = DEFAULT_CONNECTION_INACTIVE_TIMEOUT; GLOBAL const DWORD GlobalServerInfoTimeout = DEFAULT_SERVER_INFO_TIMEOUT; // // switches // GLOBAL BOOL InDllCleanup = FALSE; GLOBAL BOOL GlobalDynaUnload = FALSE; GLOBAL BOOL GlobalDisableKeepAlive = FALSE; GLOBAL BOOL GlobalEnableHttp1_1 = FALSE; GLOBAL BOOL GlobalEnableProxyHttp1_1 = FALSE; GLOBAL BOOL GlobalIsProcessExplorer = FALSE; #ifndef UNIX GLOBAL const BOOL GlobalEnableFortezza = TRUE; #else /* for UNIX */ GLOBAL const BOOL GlobalEnableFortezza = FALSE; #endif /* UNIX */ // SSL Switches (petesk 7/24/97) GLOBAL const DWORD GlobalSecureProtocols = DEFAULT_SECURE_PROTOCOLS; // // AutoDetect Proxy Globals // GLOBAL LONG GlobalInternetOpenHandleCount = -1; GLOBAL DWORD GlobalProxyVersionCount = 0; GLOBAL BOOL GlobalAutoProxyInInit = FALSE; GLOBAL BOOL GlobalAutoProxyCacheEnable = TRUE; GLOBAL BOOL GlobalDisplayScriptDownloadFailureUI = FALSE; // // Workaround for Novell's Client32 // GLOBAL const BOOL fDontUseDNSLoadBalancing = FALSE; // // lists // GLOBAL SERIALIZED_LIST GlobalObjectList; // // SSL globals, for UI. We need to know // whether its ok for us to pop up UI. // // GLOBAL SECURITY_CACHE_LIST GlobalCertCache; GLOBAL BOOL GlobalDisableNTLMPreAuth = FALSE; // // critical sections // GLOBAL CCritSec MlangCritSec; // Mlang related data and functions. PRIVATE HINSTANCE hInstMlang; PRIVATE PFNINETMULTIBYTETOUNICODE pfnInetMultiByteToUnicode; PRIVATE BOOL bFailedMlangLoad; // So we don't try repeatedly if we fail once. BOOL LoadMlang( ); BOOL UnloadMlang( ); #define MLANGDLLNAME "mlang.dll" // // novell client32 (hack) "support" // GLOBAL BOOL GlobalRunningNovellClient32 = FALSE; GLOBAL const BOOL GlobalNonBlockingClient32 = FALSE; // // proxy info // GLOBAL PROXY_INFO_GLOBAL * g_pGlobalProxyInfo; // // DLL version info // GLOBAL INTERNET_VERSION_INFO InternetVersionInfo = { WINHTTPX_MAJOR_VERSION, WINHTTPX_MINOR_VERSION }; // // HTTP version info - default 1.0 // GLOBAL HTTP_VERSION_INFO HttpVersionInfo = {1, 0}; GLOBAL BOOL fCdromDialogActive = FALSE; // this needs to go // // The following globals are literal strings passed to winsock. // Do NOT make them const, otherwise they end up in .text section, // and web release of winsock2 has a bug where it locks and dirties // send buffers, confusing the win95 vmm and resulting in code // getting corrupted when it is paged back in. -RajeevD // GLOBAL char gszAt[] = "@"; GLOBAL char gszBang[] = "!"; GLOBAL char gszCRLF[] = "\r\n"; // cookie special casing GLOBAL PTSTR GlobalSpecialDomains = NULL; GLOBAL PTSTR *GlobalSDOffsets = NULL; GLOBAL LONG g_cSessionCount=0; GLOBAL CAsyncCount* g_pAsyncCount = NULL; // implemented in ihttprequest\httprequest.cxx: extern void CleanupWinHttpRequestGlobals(); // // functions // BOOL AddEventSource(void) { HKEY hKey; DWORD dwData; CHAR szBuf[80]; DWORD dwDispo; // Add your source name as a subkey under the Application // key in the EventLog registry key. if (RegCreateKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\WinHttp5", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &dwDispo) != ERROR_SUCCESS) { return FALSE; } if (dwDispo == REG_OPENED_EXISTING_KEY) { RegCloseKey(hKey); return TRUE; } // Set the name of the message file. strcpy(szBuf, "%SystemRoot%\\System32\\WinHttp5.dll"); // Add the name to the EventMessageFile subkey. if (RegSetValueEx(hKey, // subkey handle "EventMessageFile", // value name 0, // must be zero REG_EXPAND_SZ, // value type (LPBYTE) szBuf, // pointer to value data strlen(szBuf) + 1) != ERROR_SUCCESS) // length of value data { RegCloseKey(hKey); return FALSE; } // Set the supported event types in the TypesSupported subkey. dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; if (RegSetValueEx(hKey, // subkey handle "TypesSupported", // value name 0, // must be zero REG_DWORD, // value type (LPBYTE) &dwData, // pointer to value data sizeof(DWORD)) != ERROR_SUCCESS) // length of value data { RegCloseKey(hKey); return FALSE; } RegCloseKey(hKey); return TRUE; } HANDLE g_hEventLog = 0; BOOL InitializeEventLog(void) { if (AddEventSource() == FALSE) { return FALSE; } g_hEventLog = ::RegisterEventSourceA(NULL, "WinHttp5"); return g_hEventLog != NULL; } void TerminateEventLog(void) { if (g_hEventLog) { ::DeregisterEventSource(g_hEventLog); g_hEventLog = NULL; } } #ifdef UNIX extern "C" #endif /* UNIX */ BOOL GlobalDllInitialize( VOID ) /*++ Routine Description: The set of initializations - critical sections, etc. - that must be done at DLL_PROCESS_ATTACH Arguments: None. Return Value: TRUE, only FALSE when not enough memory to initialize globals --*/ { BOOL fResult = FALSE; DEBUG_ENTER((DBG_GLOBAL, None, "GlobalDllInitialize", NULL )); InitializeEventLog(); CLEAR_DEBUG_CRIT(szDebugBlankBuffer); if (MlangCritSec.Init() && InitializeSerializedList(&GlobalObjectList) && AuthOpen() && IwinsockInitialize() && SecurityInitialize() ) { fResult = TRUE; } DEBUG_LEAVE(fResult); return fResult; } #ifdef UNIX extern "C" #endif /* UNIX */ VOID GlobalDllTerminate( VOID ) /*++ Routine Description: Undoes the initializations of GlobalDllInitialize Arguments: None. Return Value: None. --*/ { DEBUG_ENTER((DBG_GLOBAL, None, "GlobalDllTerminate", NULL )); // // only perform resource clean-up if this DLL is being unloaded due to a // FreeLibrary() call. Otherwise, we take the lazy way out and let the // system clean up after us // if (GlobalDynaUnload) { TerminateAsyncSupport(TRUE); IwinsockTerminate(); HandleTerminate(); } CHECK_SOCKETS(); AuthClose(); // //BUGBUG: we can't Terminate the list here because // of a race condition from IE3 // (someone still holds the handle) // but we don't want to leak the CritSec // TerminateSerlizedList == DeleteCritSec + some Asserts // //TerminateSerializedList(&GlobalObjectList); GlobalObjectList.Lock.FreeLock(); MlangCritSec.FreeLock(); SecurityTerminate(); TerminateEventLog(); DEBUG_LEAVE(0); } DWORD GlobalDataInitialize( VOID ) /*++ Routine Description: Loads any global data items from the registry Arguments: None. Return Value: DWORD Success - ERROR_SUCCESS Failure - ERROR_NOT_ENOUGH_MEMORY --*/ { DEBUG_ENTER((DBG_GLOBAL, Dword, "GlobalDataInitialize", NULL )); static BOOL Initializing = FALSE; static BOOL Initialized = FALSE; static DWORD error = ERROR_SUCCESS; // // only one thread initializes // if (InterlockedExchange((LPLONG)&Initializing, TRUE)) { while (!Initialized) { SleepEx(0, TRUE); } goto done; } // // create the global cert-cache and proxy lists // GlobalCertCache.Initialize(); INET_ASSERT(g_pGlobalProxyInfo==NULL); g_pGlobalProxyInfo = New PROXY_INFO_GLOBAL(); if (!g_pGlobalProxyInfo) { error = ERROR_NOT_ENOUGH_MEMORY; goto quit; } g_pGlobalProxyInfo->InitializeProxySettings(); // // Load proxy config settings from registry... // error = LoadProxySettings(); if (error != ERROR_SUCCESS) goto quit; char buf[MAX_PATH + 1]; if (GetModuleFileName(NULL, buf, sizeof(buf))) { LPSTR p = strrchr(buf, DIR_SEPARATOR_CHAR); p = p ? ++p : buf; DEBUG_PRINT(INET, INFO, ("process is %q\n", p)); if (lstrcmpi(p, "EXPLORER.EXE") && lstrcmpi(p, "IEXPLORE.EXE")) { // // yet another app-hack: AOL's current browser can't understand // HTTP 1.1. When they do, they have to call InternetSetOption() // with WINHTTP_OPTION_HTTP_VERSION // if (!lstrcmpi(p, "WAOL.EXE")) { GlobalEnableHttp1_1 = FALSE; } } else { GlobalIsProcessExplorer = TRUE; } } else { DEBUG_PRINT(INET, INFO, ("GetModuleFileName() returns %d\n", GetLastError() )); } // // perform module/package-specific initialization // error = HandleInitialize(); if (error != ERROR_SUCCESS) { goto quit; } quit: // // finally, if EnableHttp1_1 was set to non-zero in the registry, enable // HTTP 1.1 // if (GlobalEnableHttp1_1) { HttpVersionInfo.dwMajorVersion = 1; HttpVersionInfo.dwMinorVersion = 1; } if (error == ERROR_SUCCESS) { GlobalDataInitialized = TRUE; } // // irrespective of success or failure, we have attempted global data // initialization. If we failed then we assume its something fundamental // and fatal: we don't try again // Initialized = TRUE; done: DEBUG_LEAVE(error); return error; } VOID GlobalDataTerminate( VOID ) /*++ Routine Description: Undoes work of GlobalDataInitialize() Arguments: None. Return Value: None. --*/ { DEBUG_ENTER((DBG_GLOBAL, None, "GlobalDataTerminate", NULL )); RIP(g_cSessionCount == 0); #ifndef WININET_SERVER_CORE // // Release background task manager // UnloadBackgroundTaskMgr(); #endif AuthUnload(); if (GlobalSpecialDomains) { delete [] GlobalSpecialDomains; delete [] GlobalSDOffsets; } // // terminate the global cert-cache and proxy lists // GlobalCertCache.Terminate(); if (g_pGlobalProxyInfo) { g_pGlobalProxyInfo->TerminateProxySettings(); delete g_pGlobalProxyInfo; g_pGlobalProxyInfo = NULL; } // // ServerInfo's in WinHttpX are per-session instead of global. // InternetCloseHandle on a session handles purging the server // info list. // #ifndef WININET_SERVER_CORE PurgeServerInfoList(TRUE); #endif UnloadMlang(); UnloadSecurity(); CleanupWinHttpRequestGlobals(); GlobalDataInitialized = FALSE; DEBUG_LEAVE(0); } BOOL IsHttp1_1( VOID ) /*++ Routine Description: Determine if we are using HTTP 1.1 or greater Arguments: None. Return Value: BOOL --*/ { return (HttpVersionInfo.dwMajorVersion > 1) ? TRUE : (((HttpVersionInfo.dwMajorVersion == 1) && (HttpVersionInfo.dwMajorVersion >= 1)) ? TRUE : FALSE); } VOID ChangeGlobalSettings( VOID ) /*++ Routine Description: Changes global settings Arguments: None. Return Value: None. --*/ { DEBUG_ENTER((DBG_GLOBAL, None, "ChangeGlobalSettings", NULL )); #ifndef WININET_SERVER_CORE InternetReadRegistryDword("EnableHttp1_1", (LPDWORD)&GlobalEnableHttp1_1 ); InternetReadRegistryDword("ProxyHttp1.1", (LPDWORD)&GlobalEnableProxyHttp1_1 ); if (!g_pGlobalProxyInfo->IsModifiedInProcess()) { FixProxySettingsForCurrentConnection( FALSE ); } #endif //!WININET_SERVER_CORE DEBUG_LEAVE(0); } // Loads Mlang.dll and get the entry point we are interested in. BOOL LoadMlang( ) { if (!MlangCritSec.Lock()) goto quit; if (hInstMlang == NULL && !bFailedMlangLoad) { INET_ASSERT(pfnInetMultiByteToUnicode == NULL); hInstMlang = LoadLibrary(MLANGDLLNAME); if (hInstMlang != NULL) { pfnInetMultiByteToUnicode = (PFNINETMULTIBYTETOUNICODE)GetProcAddress (hInstMlang,"ConvertINetMultiByteToUnicode"); if (pfnInetMultiByteToUnicode == NULL) { INET_ASSERT(FALSE); FreeLibrary(hInstMlang); hInstMlang = NULL; } } else { INET_ASSERT(FALSE); // bad news if we can't load mlang.dll } if (pfnInetMultiByteToUnicode == NULL) bFailedMlangLoad = TRUE; } MlangCritSec.Unlock(); quit: return (pfnInetMultiByteToUnicode != NULL); } BOOL UnloadMlang( ) { if (!MlangCritSec.Lock()) return FALSE; if (hInstMlang) FreeLibrary(hInstMlang); hInstMlang = NULL; pfnInetMultiByteToUnicode = NULL; bFailedMlangLoad = FALSE; MlangCritSec.Unlock(); return TRUE; } PFNINETMULTIBYTETOUNICODE GetInetMultiByteToUnicode( ) { // We are checking for pfnInetMultiByteToUnicode without getting a crit section. // This works only because UnloadMlang is called at the Dll unload time. if (pfnInetMultiByteToUnicode == NULL) { LoadMlang( ); } return pfnInetMultiByteToUnicode; } int cdecl _sprintf(char* buffer, char* format, va_list args); void LOG_EVENT(DWORD dwEventType, char* format, ...) { if (g_hEventLog == NULL) { return; } va_list args; int n; char *pBuffer = (char *) ALLOCATE_FIXED_MEMORY(1024); if (pBuffer == NULL) return; va_start(args, format); n = _sprintf(pBuffer, format, args); va_end(args); LPCSTR pszMessages[1]; pszMessages[0] = &pBuffer[0]; ::ReportEvent(g_hEventLog, (WORD)dwEventType, 0, dwEventType, NULL, 1, 0, &pszMessages[0], NULL); FREE_MEMORY(pBuffer); }