//--------------------------------------------------------------------------- // Copyright (C) Microsoft Corporation, 1997 - 1999 // // httpreg.c // // HTTP/RPC Proxy Registry Functions. // // Author: // 06-16-97 Edward Reus Initial version. // //--------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include #include #include #include //------------------------------------------------------------------------- // AtoUS() // // Convert a numeric string to an unsigned short. If the conversion // fails return FALSE. //------------------------------------------------------------------------- static BOOL AtoUS( char *pszValue, unsigned short *pusValue ) { int iValue; size_t iLen = strlen(pszValue); *pusValue = 0; if ((iLen == 0) || (iLen > 5) || (iLen != strspn(pszValue,"0123456789"))) { return FALSE; } iValue = atoi(pszValue); if ((iValue < 0) || (iValue > 65535)) { return FALSE; } *pusValue = (unsigned short) iValue; return TRUE; } char * SkipLeadingSpaces ( IN const char *CurrentPosition ) /*++ Routine Description: Skips all spaces (0x20) starting from the current position. Arguments: CurrentPosition - the beginning of the string Return Value: The first non-space character in the string --*/ { while (*CurrentPosition == ' ') CurrentPosition ++; return (char *)CurrentPosition; } void RemoveTrailingSpaces ( IN char *CurrentPosition, IN char *BeginningOfString ) /*++ Routine Description: Removes all trailing spaces at the end of the string by converting them to 0. Arguments: CurrentPosition - the current position in the string - usually one before the null terminator. BeginningOfString - the beginning of the string - we should not move beyond this. Return Value: --*/ { ASSERT(CurrentPosition >= BeginningOfString); // whack all trailing spaces while (*CurrentPosition == ' ' && CurrentPosition > BeginningOfString) { *CurrentPosition = '\0'; -- CurrentPosition; } } void LogEventValidPortsFailure ( IN char *ValidPorts ) /*++ Routine Description: Logs a message to the event log reporting that the ValidPorts regkey cannot be parsed. Arguments: ValidPorts - parses the valid ports string as read from the registry. Return Value: --*/ { HANDLE hEventSource; char *Strings[] = { ValidPorts }; hEventSource = RegisterEventSourceW (NULL, // uses local computer EVENT_LOG_SOURCE_NAME); // source name if (hEventSource == NULL) { #if DBG DbgPrint("Rpc Proxy - RegisterEventSourceW failed: %X. Can't log event ValidPorts failure event. \n", GetLastError()); #endif // DBG return; } if (!ReportEventA(hEventSource, EVENTLOG_ERROR_TYPE, // event type RPCPROXY_EVENTLOG_STARTUP_CATEGORY, // category RPCPROXY_EVENTLOG_VALID_PORTS_ERR, // event identifier NULL, // user security identifier 1, // # of substitution strings 0, // no data Strings, // pointer to string array NULL)) // pointer to data { #if DBG DbgPrint("Rpc Proxy - ReportEventW failed: %X. Can't log event ValidPorts failure. \n", GetLastError()); #endif // DBG // fall through on error } DeregisterEventSource(hEventSource); } void LogEventStartupSuccess ( IN char *IISMode ) /*++ Routine Description: Logs a message to the event log reporting that the RPC proxy started successfully. Arguments: IISMode - the mode that we start in. Must be the string "5" for 5.0 mode and the string "6" for 6.0 mode. Return Value: --*/ { HANDLE hEventSource; char *Strings[] = { IISMode }; hEventSource = RegisterEventSourceW (NULL, // uses local computer EVENT_LOG_SOURCE_NAME); // source name if (hEventSource == NULL) { #if DBG DbgPrint("Rpc Proxy - RegisterEventSourceW failed: %X. Can't log event StartupSuccess event. \n", GetLastError()); #endif // DBG return; } if (!ReportEventA(hEventSource, EVENTLOG_INFORMATION_TYPE, // event type RPCPROXY_EVENTLOG_STARTUP_CATEGORY, // category RPCPROXY_EVENTLOG_SUCCESS_LOAD, // event identifier NULL, // user security identifier 1, // # of substitution strings 0, // no data Strings, // pointer to string array NULL)) // pointer to data { #if DBG DbgPrint("Rpc Proxy - ReportEventW failed: %X. Can't log event Startup Success. \n", GetLastError()); #endif // DBG // fall through on error } DeregisterEventSource(hEventSource); } //------------------------------------------------------------------------- // HttpParseServerPort() // // Parse strings of the form: :[-] // // Return TRUE iff we have a valid specification of a server/port range. // // N.B.: pszServerPortRange gets modified on output //------------------------------------------------------------------------- static BOOL HttpParseServerPort( IN char *pszServerPortRange, OUT VALID_PORT *pValidPort ) { char *psz; char *pszColon; char *pszDash; char *pszCurrent; pszServerPortRange = SkipLeadingSpaces (pszServerPortRange); if (pszColon=_mbschr(pszServerPortRange,':')) { if (pszColon == pszServerPortRange) { return FALSE; } *pszColon = 0; psz = pszColon; psz++; pValidPort->pszMachine = (char*)MemAllocate(1+lstrlen(pszServerPortRange)); if (!pValidPort->pszMachine) { return FALSE; } lstrcpy(pValidPort->pszMachine,pszServerPortRange); // truncate trailing spaces in the name // position on the last character before the terminating NULL pszCurrent = pValidPort->pszMachine + _mbstrlen(pValidPort->pszMachine) - 1; // we checked above that the machine name is not empty ASSERT(pszCurrent > pValidPort->pszMachine); RemoveTrailingSpaces (pszCurrent, pValidPort->pszMachine); if (*psz) { // skip leading spaces psz = SkipLeadingSpaces (psz); if (pszDash=_mbschr(psz,'-')) { *pszDash = 0; RemoveTrailingSpaces (pszDash - 1, psz); if (!AtoUS(psz,&pValidPort->usPort1)) { pValidPort->pszMachine = MemFree(pValidPort->pszMachine); return FALSE; } psz = SkipLeadingSpaces (pszDash + 1); if (!AtoUS(psz,&pValidPort->usPort2)) { pValidPort->pszMachine = MemFree(pValidPort->pszMachine); return FALSE; } } else { psz = SkipLeadingSpaces (psz); if (!AtoUS(psz,&pValidPort->usPort1)) { pValidPort->pszMachine = MemFree(pValidPort->pszMachine); return FALSE; } pValidPort->usPort2 = pValidPort->usPort1; } } else { pValidPort->pszMachine = MemFree(pValidPort->pszMachine); return FALSE; } } else { return FALSE; } return TRUE; } //------------------------------------------------------------------------- // HttpFreeValidPortList() // //------------------------------------------------------------------------- void HttpFreeValidPortList( IN VALID_PORT *pValidPorts ) { VALID_PORT *pCurrent = pValidPorts; if (pValidPorts) { while (pCurrent->pszMachine) { MemFree(pCurrent->pszMachine); if (pCurrent->ppszDotMachineList) { FreeIpAddressList(pCurrent->ppszDotMachineList); } pCurrent++; } MemFree(pValidPorts); } } //------------------------------------------------------------------------- // HttpParseValidPortsList() // // Given a semicolon separated list of valid machine name/port ranges // string, part it and return an array of ValidPort structures. The last // entry has a NULL pszMachine field. //------------------------------------------------------------------------- VALID_PORT *HttpParseValidPortsList( IN char *pszValidPorts ) { int i; int iLen; int count = 1; DWORD dwSize = 1+lstrlen(pszValidPorts); char *pszList; char *pszFirst; char *psz; VALID_PORT *pValidPorts = NULL; if (!dwSize) { return NULL; } // Make a local copy of the machine/ports list to work with: pszList = MemAllocate(dwSize); if (!pszList) { // Out of memory. return NULL; } lstrcpy(pszList,pszValidPorts); // See how many separate machine/port range patterns ther are in // the list: // // NOTE: That count may be too high, if either the list contains // double semicolons or the list ends with a semicolon. If // either/both of these happen that's Ok, our array will be // just a little too long. psz = pszList; while (psz=_mbsstr(psz,";")) { count++; psz++; } pValidPorts = (VALID_PORT*)MemAllocate( (1+count)*sizeof(VALID_PORT) ); if (!pValidPorts) { // Out of memory. MemFree(pszList); return NULL; } memset(pValidPorts,0,(1+count)*sizeof(VALID_PORT)); i = 0; psz = pszList; while (idwEnabled); lStatus = RegQueryValueEx(hKey,REG_PROXY_ENABLE_STR,0,&dwType,(LPBYTE)&g_pServerInfo->dwEnabled,&dwSize); if (lStatus != ERROR_SUCCESS) { RegCloseKey(hKey); return TRUE; } if (!g_pServerInfo->dwEnabled) { // RPC Proxy is disabled, no need to go on. RegCloseKey(hKey); return TRUE; } dwSize = sizeof(g_pServerInfo->dwEnabled); lStatus = RegQueryValueEx(hKey,REG_PROXY_ALLOW_ANONYMOUS,0,&dwType,(LPBYTE)&g_pServerInfo->AllowAnonymous,&dwSize); if ((lStatus == ERROR_SUCCESS) && (dwType != REG_DWORD)) { // if the type is wrong, bail out RegCloseKey(hKey); return FALSE; } dwSize = sizeof(RedirectorDllNameBuffer); lStatus = RegQueryValueExW(hKey, REG_PROXY_REDIRECTOR_DLL, 0, &dwType, (LPBYTE)RedirectorDllNameBuffer, &dwSize); if ( ( (lStatus == ERROR_SUCCESS) || (lStatus == ERROR_MORE_DATA) ) && (dwType != REG_SZ) ) { // if the type is wrong, bail out RegCloseKey(hKey); return FALSE; } if (lStatus == ERROR_MORE_DATA) { RedirectorDllName = MemAllocate(dwSize); if (RedirectorDllName == NULL) { RegCloseKey(hKey); return FALSE; } lStatus = RegQueryValueExW(hKey, REG_PROXY_REDIRECTOR_DLL, 0, &dwType, (LPBYTE)RedirectorDllName, &dwSize); } else RedirectorDllName = RedirectorDllNameBuffer; if (lStatus == ERROR_SUCCESS) { // a redirector DLL was configured // Load it. RedirectorDll = LoadLibraryW(RedirectorDllName); if (RedirectorDll == NULL) { RegCloseKey(hKey); return FALSE; } g_pServerInfo->RpcNewHttpProxyChannel = (RPC_NEW_HTTP_PROXY_CHANNEL)GetProcAddress(RedirectorDll, "RpcNewHttpProxyChannel"); g_pServerInfo->RpcHttpProxyFreeString = (RPC_HTTP_PROXY_FREE_STRING)GetProcAddress(RedirectorDll, "RpcHttpProxyFreeString"); if ((g_pServerInfo->RpcNewHttpProxyChannel == NULL) || (g_pServerInfo->RpcHttpProxyFreeString == NULL)) { g_pServerInfo->RpcNewHttpProxyChannel = NULL; g_pServerInfo->RpcHttpProxyFreeString = NULL; FreeLibrary(RedirectorDll); RegCloseKey(hKey); return FALSE; } } // this is called as part of the ISAPI initialization - no need // to claim the right to refresh ports - we're single threaded // by definition. g_pServerInfo->RefreshingValidPorts = FALSE; g_pServerInfo->pValidPorts = HttpProxyRefreshValidPorts(hKey); RegCloseKey(hKey); if (g_pServerInfo->pValidPorts) return TRUE; else return FALSE; } //------------------------------------------------------------------------- // HttpConvertToDotAddress() // // Convert the specified machine name to IP dot notation if possible. //------------------------------------------------------------------------- char *HttpConvertToDotAddress( char *pszMachineName ) { struct hostent UNALIGNED *pHostEnt; struct in_addr MachineInAddr; char *pszDot = NULL; char *pszDotMachine = NULL; pHostEnt = gethostbyname(pszMachineName); if (pHostEnt) { memcpy(&MachineInAddr,pHostEnt->h_addr,pHostEnt->h_length); pszDot = inet_ntoa(MachineInAddr); } if (pszDot) { pszDotMachine = (char*)MemAllocate(1+lstrlen(pszDot)); if (pszDotMachine) { lstrcpy(pszDotMachine,pszDot); } } return pszDotMachine; } //------------------------------------------------------------------------- // HttpNameToDotAddressList() // // Convert the specified machine name to IP dot notation if possible. // Return a list (null terminated) of the IP dot addresses in ascii. // // If the function fails, then retrun NULL. It can fail if gethostbyname() // fails, or memory allocation fails. //------------------------------------------------------------------------- char **HttpNameToDotAddressList( IN char *pszMachineName ) { int i; int iCount = 0; struct hostent UNALIGNED *pHostEnt; struct in_addr MachineInAddr; char **ppszDotList = NULL; char *pszDot = NULL; char *pszDotMachine = NULL; pHostEnt = gethostbyname(pszMachineName); if (pHostEnt) { // Count how many addresses we have: while (pHostEnt->h_addr_list[iCount]) { iCount++; } // Make sure we have at lease one address: if (iCount > 0) { ppszDotList = (char**)MemAllocate( sizeof(char*)*(1+iCount) ); } // Build an array of strings, holding the addresses (ascii DOT // notation: if (ppszDotList) { for (i=0; ih_addr_list[i], pHostEnt->h_length); pszDot = inet_ntoa(MachineInAddr); if (pszDot) { ppszDotList[i] = (char*)MemAllocate(1+lstrlen(pszDot)); if (ppszDotList[i]) { strcpy(ppszDotList[i],pszDot); } else { // memory allocate failed: break; } } } ppszDotList[i] = NULL; // Null terminated list. } } return ppszDotList; } //------------------------------------------------------------------------- // CheckCacheTimestamp() // // Return true if the current time stamp is aged out. //------------------------------------------------------------------------- BOOL CheckCacheTimestamp( DWORD dwCurrentTickCount, DWORD dwCacheTimestamp ) { if ( (dwCurrentTickCount < dwCacheTimestamp) || ((dwCurrentTickCount - dwCacheTimestamp) > VALID_PORTS_CACHE_LIFE) ) { return TRUE; } return FALSE; } //------------------------------------------------------------------------- // CheckPort() // //------------------------------------------------------------------------- static BOOL CheckPort( DWORD dwPortNumber, VALID_PORT *pValidPort ) { return ( (dwPortNumber >= pValidPort->usPort1) && (dwPortNumber <= pValidPort->usPort2) ); } //------------------------------------------------------------------------- // HttpProxyIsValidMachine() // //------------------------------------------------------------------------- BOOL HttpProxyIsValidMachine( SERVER_INFO *pServerInfo, char *pszMachine, char *pszDotMachine, DWORD dwPortNumber ) { int i; char **ppszDot; DWORD dwTicks; DWORD dwSize; DWORD dwStatus; VALID_PORT *pValidPorts; // Check the machine name against those that were allowed // in the registry: dwStatus = RtlEnterCriticalSection(&pServerInfo->cs); dwTicks = GetTickCount(); if (CheckCacheTimestamp(dwTicks, pServerInfo->dwCacheTimestamp) && pServerInfo->RefreshingValidPorts == FALSE) { // claim the right to refresh the ports pServerInfo->RefreshingValidPorts = TRUE; RtlLeaveCriticalSection(&pServerInfo->cs); // refresh them outside the critical section pValidPorts = HttpProxyRefreshValidPorts ( NULL // hKey ); // get back into the critical section RtlEnterCriticalSection(&pServerInfo->cs); pServerInfo->RefreshingValidPorts = FALSE; if (pValidPorts) { // if success, refresh the tick count pServerInfo->dwCacheTimestamp = dwTicks; } if (pServerInfo->pValidPorts) MemFree (pServerInfo->pValidPorts); pServerInfo->pValidPorts = pValidPorts; } pValidPorts = pServerInfo->pValidPorts; if (pValidPorts) { while (pValidPorts->pszMachine) { // See if we have a name match: if ( (MatchREi(pszMachine,pValidPorts->pszMachine)) && (CheckPort(dwPortNumber,pValidPorts)) ) { dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs); return TRUE; } // The "valid entry" in the registry might be an address // wildcard, check it: if ( (pszDotMachine) && (MatchREi(pszDotMachine,pValidPorts->pszMachine)) && (CheckPort(dwPortNumber,pValidPorts)) ) { dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs); return TRUE; } // Try a match using internet dot address: if ( (pValidPorts->ppszDotMachineList) && (pszDotMachine) && (CheckPort(dwPortNumber,pValidPorts)) ) { // Note that the machine may have more than one address // associated with it: // ppszDot = pValidPorts->ppszDotMachineList; while (*ppszDot) { if (!_mbsicmp(pszDotMachine,*ppszDot)) { dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs); return TRUE; } else { ppszDot++; } } } pValidPorts++; } } dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs); return FALSE; }