//--------------------------------------------------------------------------- // 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 "ecblist.h" #include "filter.h" #include "regexp.h" //------------------------------------------------------------------------- // 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; } //------------------------------------------------------------------------- // HttpParseServerPort() // // Parse strings of the form: :[-] // // Return TRUE iff we have a valid specification of a server/port range. //------------------------------------------------------------------------- static BOOL HttpParseServerPort( IN char *pszServerPortRange, OUT VALID_PORT *pValidPort ) { char *psz; char *pszColon; char *pszDash; 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); *pszColon = ':'; if (*psz) { if (pszDash=_mbschr(psz,'-')) { *pszDash = 0; if (!AtoUS(psz,&pValidPort->usPort1)) { pValidPort->pszMachine = MemFree(pValidPort->pszMachine); return FALSE; } *pszDash = '-'; psz = pszDash; if (!AtoUS(++psz,&pValidPort->usPort2)) { pValidPort->pszMachine = MemFree(pValidPort->pszMachine); return FALSE; } } else { 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. //------------------------------------------------------------------------- static VALID_PORT *HttpParseValidPortsList( IN char *pszValidPorts ) { int i; int iLen; int count = 1; DWORD dwSize = 1+lstrlen(pszValidPorts); char *pszList; char *psz; VALID_PORT *pValidPorts = NULL; if (!dwSize) { return NULL; } // Make a local copy of the machine/ports list to work with: pszList = _alloca(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. return NULL; } memset(pValidPorts,0,(1+count)*sizeof(VALID_PORT)); i = 0; while (ih_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; } //------------------------------------------------------------------------- // CheckDotCacheTimestamp() // // Return true if the current time stamp is aged out. //------------------------------------------------------------------------- static BOOL CheckDotCacheTimestamp( DWORD dwCurrentTickCount, DWORD dwDotCacheTimestamp ) { if ( (dwCurrentTickCount < dwDotCacheTimestamp) || ((dwCurrentTickCount - dwDotCacheTimestamp) > HOST_ADDR_CACHE_LIFE) ) { return TRUE; } return FALSE; } //------------------------------------------------------------------------- // CheckPort() // //------------------------------------------------------------------------- static BOOL CheckPort( SERVER_CONNECTION *pConn, VALID_PORT *pValidPort ) { return ( (pConn->dwPortNumber >= pValidPort->usPort1) && (pConn->dwPortNumber <= pValidPort->usPort2) ); } //------------------------------------------------------------------------- // HttpProxyIsValidMachine() // //------------------------------------------------------------------------- BOOL HttpProxyIsValidMachine( SERVER_INFO *pServerInfo, SERVER_CONNECTION *pConn ) { int i; char **ppszDot; DWORD dwTicks; DWORD dwSize; DWORD dwStatus; VALID_PORT *pValidPorts; // See if the machine is this (local) one, if so, then // its access is Ok. if (!_mbsicmp(pConn->pszMachine,pServerInfo->pszLocalMachineName)) { return TRUE; } // Ok convert the local machine name to dot notation and // see if we have a match: dwTicks = GetTickCount(); dwStatus = RtlEnterCriticalSection(&pServerInfo->cs); // We keep a cache of the IP addresses for the local machine name, // that chach ages out every ~5 minutes, to allow for dynamic change // of IP addresses. This does the age-out of the IP address list: if ( (pServerInfo->ppszLocalDotMachineList) && CheckDotCacheTimestamp(dwTicks,pServerInfo->dwDotCacheTimestamp) ) { FreeIpAddressList(pServerInfo->ppszLocalDotMachineList); pServerInfo->ppszLocalDotMachineList = NULL; } // If we don't (or no longer have) a list of the IP addresses for the // local machine, then generate it: if (!pServerInfo->ppszLocalDotMachineList) { pServerInfo->dwDotCacheTimestamp = dwTicks; pServerInfo->ppszLocalDotMachineList = HttpNameToDotAddressList(pServerInfo->pszLocalMachineName); } // Go through a list of the IP addresses to see if we have a match. // Note that the machine may have more than one address associated // with it: if ( (pServerInfo->ppszLocalDotMachineList) && (pConn->pszDotMachine) ) { ppszDot = pServerInfo->ppszLocalDotMachineList; while (*ppszDot) { if (!_mbsicmp(pConn->pszDotMachine,*ppszDot)) { dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs); return TRUE; } else { ppszDot++; } } } dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs); // Check the machine name against those that were allowed // in the registry: dwStatus = RtlEnterCriticalSection(&pServerInfo->cs); pValidPorts = pServerInfo->pValidPorts; if (pValidPorts) { while (pValidPorts->pszMachine) { // See if we have a name match: if ( (MatchREi(pConn->pszMachine,pValidPorts->pszMachine)) && (CheckPort(pConn,pValidPorts)) ) { dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs); return TRUE; } // The "valid entry" in the registry might be an address // wildcard, check it: if ( (pConn->pszDotMachine) && (MatchREi(pConn->pszDotMachine,pValidPorts->pszMachine)) && (CheckPort(pConn,pValidPorts)) ) { dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs); return TRUE; } // If the address list is aged out then get rid of it. if ( (pValidPorts->ppszDotMachineList) && CheckDotCacheTimestamp(dwTicks,pServerInfo->dwDotCacheTimestamp)) { FreeIpAddressList(pValidPorts->ppszDotMachineList); pValidPorts->ppszDotMachineList = NULL; } // Make up a new list of addresses for this machine. if (!pValidPorts->ppszDotMachineList) { // Note: that this will only work if the name in the valid // ports list is not a wildcard. // // Note: pServerInfo->dwCacheTicks will have been updated // above... // pValidPorts->ppszDotMachineList = HttpNameToDotAddressList(pValidPorts->pszMachine); } // Try a match using internet dot address: if ( (pValidPorts->ppszDotMachineList) && (pConn->pszDotMachine) && (CheckPort(pConn,pValidPorts)) ) { // Note that the machine may have more than one address // associated with it: // ppszDot = pValidPorts->ppszDotMachineList; while (*ppszDot) { if (!_mbsicmp(pConn->pszDotMachine,*ppszDot)) { dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs); return TRUE; } else { ppszDot++; } } } pValidPorts++; } } dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs); return FALSE; }