Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

754 lines
16 KiB

/**********************************************************************/
/** Microsoft Windows NT **/
/** Copyright(c) Microsoft Corp., 1993 **/
/**********************************************************************/
/*
ipaccess.cxx
This module checks security based on the client's IP address
FILE HISTORY:
Johnl 18-Nov-1994 Created
MuraliK 08-Mar-1996 Rewrote to improve modularity & efficiency.
*/
#include "tcpdllp.hxx"
#include <ctype.h>
#include <tsproc.hxx>
#include "tsvcinfo.hxx"
//
// Private constants.
//
//
// The registry parameter key names for the grant list and deny
// list. We use the kludgemultisz thing for Chicago
//
#define IPSEC_DENY_LIST "Deny IP List"
#define IPSEC_GRANT_LIST "Grant IP List"
//
// Private globals.
//
//
// Private prototypes.
//
BOOL
DottedDecimalToDword(
CHAR * * ppszAddress,
DWORD * pdwAddress
);
BOOL
AppendDottedDecimal(
STR * pstr,
DWORD dwAddress
);
BOOL
WriteIPSecList(IN HKEY hKey,
IN LPCSTR pszSubKey,
IN LPINETA_IP_SEC_LIST pIPSecList
);
//
// Public functions.
//
BOOL
TSVC_INFO::InitializeIPSecurity(
VOID
)
/*++
Routine Description:
Grants or denies access of the passed IP Address based on the
service's IP Access/deny list
Note that NULL for the grant list means grant all
Arguments:
pchClientIP - String representatin of dotted IP address
pfGranted - Set to TRUE if access should be granted, FALSE if access
should be refused
--*/
{
BOOL fReturn;
//
// If this is an NtWorkstation, disable access checking
//
if ( TsIsNtWksta( ) ) {
DBGPRINTF(( DBG_CONTEXT,
"NT Workstation, disabling IP access checking.\n"));
fReturn = TRUE;
} else {
STR strRegKey;
//
// Open the keys and read the deny list
//
fReturn = (strRegKey.Copy( QueryRegParamKey()) &&
strRegKey.Append("\\") &&
strRegKey.Append( IPSEC_DENY_LIST ) &&
m_ipaDenyList.ReadIPList(strRegKey.QueryStr())
);
//
// Open the keys and read the grant list
//
fReturn = (fReturn &&
strRegKey.Copy( QueryRegParamKey()) &&
strRegKey.Append("\\") &&
strRegKey.Append( IPSEC_GRANT_LIST ) &&
m_ipaGrantList.ReadIPList(strRegKey.QueryStr())
);
m_fNoIPAccessChecks =
(m_ipaDenyList.IsEmpty() && m_ipaGrantList.IsEmpty());
}
return (fReturn);
} // TSVC_INFO::InitializeIPSecurity()
VOID
TSVC_INFO::TerminateIPSecurity(
VOID
)
/*++
Routine Description:
Cleans up the IP security stuff for this service
--*/
{
//
// Cleanup all access check lists
//
m_ipaDenyList.Cleanup();
m_ipaGrantList.Cleanup();
m_fNoIPAccessChecks = FALSE;
} // TSVC_INFO::TerminateIPSecurity()
BOOL
TSVC_INFO::SetIPSecurity(
HKEY hkey,
INETA_CONFIG_INFO * pConfig
)
/*++
Routine Description:
Write the passed IP security to the registry
Arguments:
hkey - Current open registry key to write to
pConfig - configuration structure to write
--*/
{
BOOL fReturn;
//
// Write the values to the registry, so that someone else can read
// it back later ...
//
fReturn = (WriteIPSecList( hkey, IPSEC_DENY_LIST, pConfig->DenyIPList)
&&
WriteIPSecList( hkey, IPSEC_GRANT_LIST, pConfig->GrantIPList)
);
return ( fReturn && InitializeIPSecurity());
} // TSVC_INFO::SetIPSecurity()
BOOL
TSVC_INFO::IPAccessCheckEx(
IN LPSOCKADDR_IN psockAddr,
IN BOOL * pfGranted
)
/*++
Routine Description:
Grants or denies access of the passed IP Address based on the
service's IP Access/deny list
Arguments:
psockAddr pointer to socket address structure
pfGranted - Set to TRUE if access should be granted, FALSE if access
should be refused
Returns:
TRUE is there is no failure.
FALSE if there is a failure in performing the check.
History:
Modified to take LPSOCKADDR_IN for access check. MuraliK 12/16/94
--*/
{
DWORD i;
*pfGranted = TRUE;
//
// If this isn't a TCP/IP address, then ignore it
//
if ( psockAddr->sin_family != AF_INET )
return TRUE;
//
// Look in the deny list first
//
if ( !m_ipaDenyList.IsEmpty()) {
if ( m_ipaDenyList.IsPresent( psockAddr)) {
// since the entry is found in deny list, do not grant access
*pfGranted = FALSE;
return ( TRUE);
}
}
//
// Now look in the accept list. If the accept list is NULL, then we
// accept all addresses not specifically denied
//
if ( m_ipaGrantList.IsEmpty() ) {
// we accept all non-denied addresses.
return (TRUE);
} else {
*pfGranted = m_ipaGrantList.IsPresent( psockAddr);
}
return (TRUE);
} // TSVC_INFO__IPAccessCheckEx()
/************************************************************
* Member functions of IPAccessList
************************************************************/
VOID
IPAccessList::Cleanup(VOID)
{
DBG_ASSERT( m_cReadLocks == 0);
if ( m_pIPList != NULL) {
TCP_FREE( m_pIPList);
m_pIPList = NULL;
}
return;
} // IPAccessList::Cleanup()
BOOL
IPAccessList::ReadIPList(IN LPCSTR pszRegKey)
/*++
Description:
This function reads the IP list from registry location
specified in the pszRegKey and stores the list in the
internal list in memory.
If there are no entries in the registry then this returns
a NULL IP Security list object.
If there is a new list, this function also frees the old list
present in *ppIPSecList
Arguments:
pszRegKey - pointer to string containing the registry key
where IP list is stored
Returns:
TRUE on success and FALSE on failure
--*/
{
HKEY hkey;
DWORD dwError;
BOOL fReturn = TRUE;
dwError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
pszRegKey,
0,
KEY_ALL_ACCESS,
&hkey );
if ( dwError != NO_ERROR) {
if ( dwError != ERROR_FILE_NOT_FOUND ) {
// maybe access denied or some other error.
SetLastError( dwError );
return (FALSE);
}
DBG_ASSERT( dwError == ERROR_FILE_NOT_FOUND);
//
// A non-existent key is the same as a blank key
// So free up the IP security list
//
LockThisForWrite();
if ( m_pIPList != NULL) {
TCP_FREE( m_pIPList);
m_pIPList = NULL;
}
UnlockThis();
} else {
CHAR * psz;
CHAR * pszTmp;
DWORD cb;
DWORD cEntries = 0;
INETA_IP_SEC_LIST * pIPSec = NULL;
DBG_ASSERT( dwError == NO_ERROR);
psz = pszTmp = KludgeMultiSz( hkey, &cb );
//
// Count the number of addresses and then add them to the list
//
if ( psz != NULL ) {
for( ; *pszTmp; cEntries++ ) {
pszTmp += strlen( pszTmp ) + 1;
}
pszTmp = psz;
if ( cEntries > 0) {
pIPSec = ((INETA_IP_SEC_LIST *)
TCP_ALLOC( sizeof(INETA_IP_SEC_LIST) +
cEntries * sizeof(INETA_IP_SEC_ENTRY ))
);
if ( pIPSec == NULL ) {
dwError = ERROR_NOT_ENOUGH_MEMORY;
fReturn = FALSE;
} else {
for( pIPSec->cEntries = 0;
*pszTmp;
pszTmp += strlen( pszTmp ) + 1
) {
if (!DottedDecimalToDword( &pszTmp,
&pIPSec->aIPSecEntry[pIPSec->cEntries].dwMask ) ||
!DottedDecimalToDword( &pszTmp,
&pIPSec->aIPSecEntry[pIPSec->cEntries].dwNetwork )
) {
DBGPRINTF(( DBG_CONTEXT,
"Badly formatted IP address in"
" IP security list (%s)\n",
pszTmp ));
} else {
pIPSec->cEntries++;
}
} // for
dwError = NO_ERROR;
}
}
if ( dwError == NO_ERROR) {
LockThisForWrite();
if ( m_pIPList != NULL) {
TCP_FREE( m_pIPList);
}
m_pIPList = pIPSec;
UnlockThis();
}
TCP_FREE( psz );
}
DBG_ASSERT( hkey != (HKEY) INVALID_HANDLE_VALUE );
DBG_REQUIRE( !RegCloseKey( hkey ) );
if ( !fReturn) {
DBG_ASSERT( dwError != NO_ERROR);
SetLastError( dwError);
}
}
return ( fReturn);
} // IPAccessList::ReadIPList()
IPAccessList::IsPresent(IN LPSOCKADDR_IN psockAddr)
/*++
Description:
This function checks to see if the give socket address is present
in the current IP Access list.
Arguments:
psockAddr - pointer to socket address structure that needs to
be access checked
Returns:
TRUE if the given address is present in the list
FALSE otherwise
--*/
{
DWORD i;
BOOL fFound = FALSE;
//
// We need to reduce time taken for lookup
// At present: we are using linear lookups.
// How can we speed this up? TBD
//
LockThisForRead();
for ( i = 0; i < m_pIPList->cEntries; i++ ) {
if ( (m_pIPList->aIPSecEntry[i].dwMask & psockAddr->sin_addr.s_addr)
== m_pIPList->aIPSecEntry[i].dwNetwork ) {
// a match is found.
fFound = TRUE;
break;
}
} // for
UnlockThis();
return ( fFound);
} // IPAccessList::IsPresent()
# if DBG
VOID
IPAccessList::Print(IN LPCSTR pszListName) const
{
DBGPRINTF((DBG_CONTEXT,
"IPAccessList(%08x) : %s;"
" cReadLocks = %d; IPList = %08x\n"
,
pszListName,
this,
m_cReadLocks,
m_pIPList
));
return;
} // IPAccessList::Print()
# endif // DBG
//
// Private functions
//
BOOL
DottedDecimalToDword(
CHAR * * ppszAddress,
DWORD * pdwAddress )
/*++
Routine Description:
Converts a dotted decimal IP string to it's network equivalent
Note: White space is eaten before *pszAddress and pszAddress is set
to the character following the converted address
Arguments:
ppszAddress - Pointer to address to convert. White space before the
address is OK. Will be changed to point to the first character after
the address
pdwAddress - DWORD equivalent address in network order
returns TRUE if successful, FALSE if the address is not correct
--*/
{
CHAR * psz;
USHORT i;
ULONG value;
int iSum =0;
ULONG k = 0;
UCHAR Chr;
UCHAR pArray[4];
DBG_ASSERT( *ppszAddress );
DBG_ASSERT( pdwAddress );
psz = *ppszAddress;
//
// Skip white space
//
while ( *psz && !isdigit( *psz ))
psz++;
//
// Convert the four segments
//
pArray[0] = 0;
while ((Chr = *psz) && (Chr != ' ') )
{
if (Chr == '.')
{
// be sure not to overflow a byte.
if (iSum <= 0xFF)
pArray[k] = iSum;
else
return FALSE;
// check for too many periods in the address
if (++k > 3)
return FALSE;
pArray[k] = 0;
iSum = 0;
}
else
{
Chr = Chr - '0';
// be sure character is a number 0..9
if ((Chr < 0) || (Chr > 9))
return FALSE;
iSum = iSum*10 + Chr;
}
psz++;
}
// save the last sum in the byte and be sure there are 4 pieces to the
// address
if ((iSum <= 0xFF) && (k == 3))
pArray[k] = iSum;
else
return FALSE;
// now convert to a ULONG, in network order...
value = 0;
// go through the array of bytes and concatenate into a ULONG
for (i=0; i < 4; i++ )
{
value = (value << 8) + pArray[i];
}
*pdwAddress = htonl( value );
*ppszAddress = psz;
return TRUE;
}
BOOL
AppendDottedDecimal(
STR * pstr,
DWORD dwAddress
)
/*++
Routine Description:
Converts a network order IP address to its string equivalent and appends
it to pstr
Arguments:
pstr - String to append address to
dwAddress - IP address to convert
returns TRUE if successful, FALSE if the address is not correct
--*/
{
DWORD address = ntohl( dwAddress );
BYTE * pbSeg = (BYTE *) &address;
CHAR ach[20];
for ( int i = 0; i < 4; i++ )
{
if ( !pstr->Append( _itoa( pbSeg[3-i], ach, 10 )) ||
( i != 3 && !pstr->Append( "." )))
{
return FALSE;
}
}
return pstr->Append( " " );
}
BOOL
WriteIPSecList(IN HKEY hKey,
IN LPCSTR pszSubKey,
IN LPINETA_IP_SEC_LIST pSecList
)
/*++
Description:
This function saves the IP security list to the registry location
pointed to by the hkey\pszSubKey.
Arguments:
hkey - handle for the root registry entry.
pszSubKey - pointer to string containing the sub key.
pSecList - pointer to string containing the Security list for writing.
Returns:
TRUE if the registry is successfully updated
FALSE if there is any error
--*/
{
DWORD err;
HKEY hKeySec;
DWORD dwDummy;
//
// First delete the key to remove any old values
//
err = RegDeleteKey( hKey, pszSubKey);
if ( err != NO_ERROR) {
DBGPRINTF(( DBG_CONTEXT,
"[SetIPSecurity] Unable to remove old values\n"));
}
err = RegCreateKeyEx( hKey,
pszSubKey,
0,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
&hKeySec,
&dwDummy );
if ( err != NO_ERROR) {
SetLastError( err );
return FALSE;
}
//
// Convert the data to strings and write it to the registry
//
if ( pSecList != NULL ) {
STR str;
DWORD i;
for ( i = 0; i < pSecList->cEntries; i++ ) {
DBG_REQUIRE( str.Copy( (CHAR *) NULL ));
if ( !AppendDottedDecimal( &str,
pSecList->aIPSecEntry[i].dwMask ) ||
!AppendDottedDecimal( &str,
pSecList->aIPSecEntry[i].dwNetwork ))
{
DBG_REQUIRE( !RegCloseKey( hKeySec ) );
return FALSE;
}
if ( err = RegSetValueEx( hKeySec,
str.QueryStr(),
0,
REG_SZ,
(CONST BYTE *) "",
0 ))
{
DBG_REQUIRE( !RegCloseKey( hKeySec ) );
SetLastError( err );
return FALSE;
}
}
}
DBG_REQUIRE( !RegCloseKey( hKeySec ) );
return ( TRUE);
} // WriteIPSecList()