|
|
/********************************************************************/ /** Microsoft LAN Manager **/ /** Copyright(c) Microsoft Corp., 1990-1993 **/ /********************************************************************/ /* :ts=4 */
//** SECFLTR.C - Security Filter Support
//
//
// Security filters provide a mechanism by which the transport protocol
// traffic accepted on IP interfaces may be controlled. Security filtering
// is globally enabled or disabled for all IP interfaces and transports.
// If filtering is enabled, incoming traffic is filtered based on registered
// {interface, protocol, transport value} tuples. The tuples specify
// permissible traffic. All other values will be rejected. For UDP datagrams
// and TCP connections, the transport value is the port number. For RawIP
// datagrams, the transport value is the IP protocol number. An entry exists
// in the filter database for all active interfaces and protocols in the
// system.
//
// The initial status of security filtering - enabled or disabled, is
// controlled by the registry parameter
//
// Services\Tcpip\Parameters\EnableSecurityFilters
//
// If the parameter is not found, filtering is disabled.
//
// The list of permissible values for each protocol is stored in the registry
// under the <Adaptername>\Parameters\Tcpip key in MULTI_SZ parameters.
// The parameter names are TCPAllowedPorts, UDPAllowedPorts and
// RawIPAllowedProtocols. If no parameter is found for a particular protocol,
// all values are permissible. If a parameter is found, the string identifies
// the permissible values. If the string is empty, no values are permissible.
//
// Filter Operation (Filtering Enabled):
//
// IF ( Match(interface, protocol) AND ( AllValuesPermitted(Protocol) OR
// Match(Value) ))
// THEN operation permitted.
// ELSE operation rejected.
//
// Database Implementation:
//
// The filter database is implemented as a three-level structure. The top
// level is a list of interface entries. Each interface entry points to
// a list of protocol entries. Each protocol entry contains a bucket hash
// table used to store transport value entries.
//
// The following calls may be used to access the security filter database:
//
// InitializeSecurityFilters
// CleanupSecurityFilters
// IsSecurityFilteringEnabled
// ControlSecurityFiltering
// AddProtocolSecurityFilter
// DeleteProtocolSecurityFilter
// AddValueSecurityFilter
// DeleteValueSecurityFilter
// EnumerateSecurityFilters
// IsPermittedSecurityFilter
//
#include "precomp.h"
#include "addr.h"
#include "tlcommon.h"
#include "udp.h"
#include "tcp.h"
#include "raw.h"
#include "tcpcfg.h"
#include "tcpinfo.h"
#include "secfltr.h"
//
// All of the init code can be discarded.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, InitializeSecurityFilters)
#endif
//
// The following routines must be supplied by each platform which implements
// security filters.
//
extern TDI_STATUS GetSecurityFilterList( IN NDIS_HANDLE ConfigHandle, IN ulong Protocol, IN OUT PNDIS_STRING FilterList );
extern uint EnumSecurityFilterValue( IN PNDIS_STRING FilterList, IN ulong Index, OUT ulong * FilterValue );
//
// Constants
//
#define DHCP_CLIENT_PORT 68
//
// Modification Opcodes
//
#define ADD_VALUE_SECURITY_FILTER 0
#define DELETE_VALUE_SECURITY_FILTER 1
//
// Types
//
//
// Structure for a transport value entry.
//
struct value_entry { struct Queue ve_link; ulong ve_value; };
typedef struct value_entry VALUE_ENTRY, *PVALUE_ENTRY;
#define VALUE_ENTRY_HASH_SIZE 16
#define VALUE_ENTRY_HASH(value) (value % VALUE_ENTRY_HASH_SIZE)
//
// Structure for a protocol entry.
//
struct protocol_entry { struct Queue pe_link; ulong pe_protocol; ULONG pe_accept_all; // TRUE if all values are accepted.
struct Queue pe_entries[VALUE_ENTRY_HASH_SIZE]; };
typedef struct protocol_entry PROTOCOL_ENTRY, *PPROTOCOL_ENTRY;
//
// Structure for an interface entry.
//
struct interface_entry { struct Queue ie_link; IPAddr ie_address; struct Queue ie_protocol_list; // list of protocols to filter
};
typedef struct interface_entry INTERFACE_ENTRY, *PINTERFACE_ENTRY;
//
// Global Data
//
//
// This list of interface entries is the root of the filter database.
//
struct Queue InterfaceEntryList;
//
// The filter operations are synchronized using the AddrObjTableLock.
//
extern IPInfo LocalNetInfo;
//
// Filter Database Helper Functions
//
//* FindInterfaceEntry - Search for an interface entry.
//
// This utility routine searches the security filter database
// for the specified interface entry.
//
//
// Input: InterfaceAddress - The address of the interface to search for.
//
//
// Returns: A pointer to the database entry for the Interface,
// or NULL if no match was found.
//
//
PINTERFACE_ENTRY FindInterfaceEntry(ULONG InterfaceAddress) { PINTERFACE_ENTRY ientry; struct Queue *qentry;
for (qentry = InterfaceEntryList.q_next; qentry != &InterfaceEntryList; qentry = qentry->q_next ) { ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
if (ientry->ie_address == InterfaceAddress) { return (ientry); } }
return (NULL); }
//* FindProtocolEntry - Search for a protocol associated with an interface.
//
// This utility routine searches the security filter database
// for the specified protocol registered under the specified interface.
//
//
// Input: InterfaceEntry - A pointer to an interface entry to search under.
// Protocol - The protocol value to search for.
//
//
// Returns: A pointer to the database entry for the <Address, Protocol>,
// or NULL if no match was found.
//
//
PPROTOCOL_ENTRY FindProtocolEntry(PINTERFACE_ENTRY InterfaceEntry, ULONG Protocol) { PPROTOCOL_ENTRY pentry; struct Queue *qentry;
for (qentry = InterfaceEntry->ie_protocol_list.q_next; qentry != &(InterfaceEntry->ie_protocol_list); qentry = qentry->q_next ) { pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
if (pentry->pe_protocol == Protocol) { return (pentry); } }
return (NULL); }
//* FindValueEntry - Search for a value on a particular protocol.
//
// This utility routine searches the security filter database
// for the specified value registered under the specified protocol.
//
//
// Input: ProtocolEntry - A pointer to the database structure for the
// Protocol to search.
// FilterValue - The value to search for.
//
//
// Returns: A pointer to the database entry for the <Protocol, Value>,
// or NULL if no match was found.
//
//
PVALUE_ENTRY FindValueEntry(PPROTOCOL_ENTRY ProtocolEntry, ULONG FilterValue) { PVALUE_ENTRY ventry; ulong hash_value = VALUE_ENTRY_HASH(FilterValue); struct Queue *qentry;
for (qentry = ProtocolEntry->pe_entries[hash_value].q_next; qentry != &(ProtocolEntry->pe_entries[hash_value]); qentry = qentry->q_next ) { ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
if (ventry->ve_value == FilterValue) { return (ventry); } }
return (NULL); }
//* DeleteProtocolValueEntries
//
// This utility routine deletes all the value entries associated with
// a protocol filter entry.
//
//
// Input: ProtocolEntry - The protocol filter entry for which to
// delete the value entries.
//
//
// Returns: Nothing
//
void DeleteProtocolValueEntries(PPROTOCOL_ENTRY ProtocolEntry) { ulong i; PVALUE_ENTRY entry;
for (i = 0; i < VALUE_ENTRY_HASH_SIZE; i++) { while (!EMPTYQ(&(ProtocolEntry->pe_entries[i]))) {
DEQUEUE(&(ProtocolEntry->pe_entries[i]), entry, VALUE_ENTRY, ve_link); CTEFreeMem(entry); } }
return; }
//* ModifyProtocolEntry
//
// This utility routine modifies one or more filter values associated
// with a protocol.
//
//
// Input: Operation - The operation to perform (add or delete)
//
// ProtocolEntry - A pointer to the protocol entry structure on
// which to operate.
//
// FilterValue - The value to add or delete.
//
//
// Returns: TDI_STATUS code
//
TDI_STATUS ModifyProtocolEntry(ulong Operation, PPROTOCOL_ENTRY ProtocolEntry, ulong FilterValue) { TDI_STATUS status = TDI_SUCCESS;
if (FilterValue == 0) { if (Operation == ADD_VALUE_SECURITY_FILTER) { //
// Accept all values for the protocol
//
ProtocolEntry->pe_accept_all = TRUE; } else { //
// Reject all values for the protocol
//
ProtocolEntry->pe_accept_all = FALSE; }
DeleteProtocolValueEntries(ProtocolEntry); } else { PVALUE_ENTRY ventry; ulong hash_value;
//
// This request modifies an individual entry.
//
ventry = FindValueEntry(ProtocolEntry, FilterValue);
if (Operation == ADD_VALUE_SECURITY_FILTER) {
if (ventry == NULL) {
ventry = CTEAllocMem(sizeof(VALUE_ENTRY));
if (ventry != NULL) { ventry->ve_value = FilterValue; hash_value = VALUE_ENTRY_HASH(FilterValue);
ENQUEUE(&(ProtocolEntry->pe_entries[hash_value]), &(ventry->ve_link));
ProtocolEntry->pe_accept_all = FALSE; } else { status = TDI_NO_RESOURCES; } } } else { if (ventry != NULL) { REMOVEQ(&(ventry->ve_link)); CTEFreeMem(ventry); } } }
return (status); }
//* ModifyInterfaceEntry
//
// This utility routine modifies the value entries of one or more protocol
// entries associated with an interface.
//
//
// Input: Operation - The operation to perform (add or delete)
//
// ProtocolEntry - A pointer to the interface entry structure on
// which to operate.
//
// Protocol - The protocol on which to operate.
//
// FilterValue - The value to add or delete.
//
//
// Returns: TDI_STATUS code
//
TDI_STATUS ModifyInterfaceEntry(ulong Operation, PINTERFACE_ENTRY InterfaceEntry, ulong Protocol, ulong FilterValue) { PPROTOCOL_ENTRY pentry; TDI_STATUS status; TDI_STATUS returnStatus = TDI_SUCCESS;
if (Protocol == 0) { struct Queue *qentry;
//
// Modify all protocols on the interface
//
for (qentry = InterfaceEntry->ie_protocol_list.q_next; qentry != &(InterfaceEntry->ie_protocol_list); qentry = qentry->q_next ) { pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link); status = ModifyProtocolEntry(Operation, pentry, FilterValue);
if (status != TDI_SUCCESS) { returnStatus = status; } } } else { //
// Modify a specific protocol on the interface
//
pentry = FindProtocolEntry(InterfaceEntry, Protocol);
if (pentry != NULL) { returnStatus = ModifyProtocolEntry(Operation, pentry, FilterValue); } else { returnStatus = TDI_INVALID_PARAMETER; } }
return (returnStatus); }
//* ModifySecurityFilter - Add or delete an entry.
//
// This routine adds or deletes an entry to/from the security filter database.
//
//
// Input: Operation - The operation to perform (Add or Delete)
// InterfaceAddress - The interface address to modify.
// Protocol - The protocol to modify.
// FilterValue - The transport value to add/delete.
//
// Returns: A TDI status code:
// TDI_INVALID_PARAMETER if the protocol is not in the database.
// TDI_ADDR_INVALID if the interface is not in the database.
// TDI_NO_RESOURCES if memory could not be allocated.
// TDI_SUCCESS otherwise
//
// NOTES:
//
TDI_STATUS ModifySecurityFilter(ulong Operation, IPAddr InterfaceAddress, ulong Protocol, ulong FilterValue) { PINTERFACE_ENTRY ientry; TDI_STATUS status; TDI_STATUS returnStatus = TDI_SUCCESS;
if (InterfaceAddress == 0) { struct Queue *qentry;
//
// Modify on all interfaces
//
for (qentry = InterfaceEntryList.q_next; qentry != &InterfaceEntryList; qentry = qentry->q_next ) { ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link); status = ModifyInterfaceEntry(Operation, ientry, Protocol, FilterValue);
if (status != TDI_SUCCESS) { returnStatus = status; } } } else { ientry = FindInterfaceEntry(InterfaceAddress);
if (ientry != NULL) { returnStatus = ModifyInterfaceEntry(Operation, ientry, Protocol, FilterValue); } else { returnStatus = TDI_ADDR_INVALID; } }
return (returnStatus); }
//* FillInEnumerationEntry
//
// This utility routine fills in an enumeration entry for a particular
// filter value entry.
//
//
// Input: InterfaceAddress - The address of the associated interface.
//
// Protocol - The associated protocol number.
//
// Value - The enumerated value.
//
// Buffer - Pointer to the user's enumeration buffer.
//
// BufferSize - Pointer to the size of the enumeration buffer.
//
// EntriesReturned - Pointer to a running count of enumerated
// entries stored in Buffer.
//
// EntriesAvailable - Pointer to a running count of entries available
// for enumeration.
//
// Returns: Nothing.
//
// Note: Values written to enumeration entry are in host byte order.
//
void FillInEnumerationEntry(IPAddr InterfaceAddress, ulong Protocol, ulong Value, uchar ** Buffer, ulong * BufferSize, ulong * EntriesReturned, ulong * EntriesAvailable) { TCPSecurityFilterEntry *entry = (TCPSecurityFilterEntry *) * Buffer;
if (*BufferSize >= sizeof(TCPSecurityFilterEntry)) { entry->tsf_address = net_long(InterfaceAddress); entry->tsf_protocol = Protocol; entry->tsf_value = Value;
*Buffer += sizeof(TCPSecurityFilterEntry); *BufferSize -= sizeof(TCPSecurityFilterEntry); (*EntriesReturned)++; } (*EntriesAvailable)++;
return; }
//* EnumerateProtocolValues
//
// This utility routine enumerates values associated with a
// protocol on an interface.
//
//
// Input: InterfaceEntry - Pointer to the associated interface entry.
//
// ProtocolEntry - Pointer to the protocol being enumerated.
//
// Value - The value to enumerate.
//
// Buffer - Pointer to the user's enumeration buffer.
//
// BufferSize - Pointer to the size of the enumeration buffer.
//
// EntriesReturned - Pointer to a running count of enumerated
// entries stored in Buffer.
//
// EntriesAvailable - Pointer to a running count of entries available
// for enumeration.
//
// Returns: Nothing.
//
void EnumerateProtocolValues(PINTERFACE_ENTRY InterfaceEntry, PPROTOCOL_ENTRY ProtocolEntry, ulong Value, uchar ** Buffer, ulong * BufferSize, ulong * EntriesReturned, ulong * EntriesAvailable) { struct Queue *qentry; PVALUE_ENTRY ventry; ulong i;
if (Value == 0) { //
// Enumerate all values
//
if (ProtocolEntry->pe_accept_all == TRUE) { //
// All values permitted.
//
FillInEnumerationEntry( InterfaceEntry->ie_address, ProtocolEntry->pe_protocol, 0, Buffer, BufferSize, EntriesReturned, EntriesAvailable ); } else { for (i = 0; i < VALUE_ENTRY_HASH_SIZE; i++) { for (qentry = ProtocolEntry->pe_entries[i].q_next; qentry != &(ProtocolEntry->pe_entries[i]); qentry = qentry->q_next ) { ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
FillInEnumerationEntry( InterfaceEntry->ie_address, ProtocolEntry->pe_protocol, ventry->ve_value, Buffer, BufferSize, EntriesReturned, EntriesAvailable ); } } } } else { //
// Enumerate a specific value, if it is registered.
//
ventry = FindValueEntry(ProtocolEntry, Value);
if (ventry != NULL) { FillInEnumerationEntry( InterfaceEntry->ie_address, ProtocolEntry->pe_protocol, ventry->ve_value, Buffer, BufferSize, EntriesReturned, EntriesAvailable ); } }
return; }
//* EnumerateInterfaceProtocols
//
// This utility routine enumerates protocols associated with
// an interface.
//
//
// Input: InterfaceEntry - Pointer to the associated interface entry.
//
// Protocol - Protocol number to enumerate.
//
// Value - The filter value to enumerate.
//
// Buffer - Pointer to the user's enumeration buffer.
//
// BufferSize - Pointer to the size of the enumeration buffer.
//
// EntriesReturned - Pointer to a running count of enumerated
// entries stored in Buffer.
//
// EntriesAvailable - Pointer to a running count of entries available
// for enumeration.
//
// Returns: Nothing.
//
void EnumerateInterfaceProtocols(PINTERFACE_ENTRY InterfaceEntry, ulong Protocol, ulong Value, uchar ** Buffer, ulong * BufferSize, ulong * EntriesReturned, ulong * EntriesAvailable) { PPROTOCOL_ENTRY pentry;
if (Protocol == 0) { struct Queue *qentry;
//
// Enumerate all protocols.
//
for (qentry = InterfaceEntry->ie_protocol_list.q_next; qentry != &(InterfaceEntry->ie_protocol_list); qentry = qentry->q_next ) { pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
EnumerateProtocolValues( InterfaceEntry, pentry, Value, Buffer, BufferSize, EntriesReturned, EntriesAvailable ); } } else { //
// Enumerate a specific protocol
//
pentry = FindProtocolEntry(InterfaceEntry, Protocol);
if (pentry != NULL) { EnumerateProtocolValues( InterfaceEntry, pentry, Value, Buffer, BufferSize, EntriesReturned, EntriesAvailable ); } }
return; }
//
// Filter Database Public API.
//
//* InitializeSecurityFilters - Initializes the security filter database.
//
// The routine performs the initialization necessary to enable the
// security filter database for operation.
//
// Input: None.
//
// Returns: Nothing.
//
//
void InitializeSecurityFilters(void) { INITQ(&InterfaceEntryList);
return; }
//* CleanupSecurityFilters - Deletes the entire security filter database.
//
// This routine deletes all entries from the security filter database.
//
//
// Input: None.
//
// Returns: Nothing.
//
// NOTE: This routine acquires the AddrObjTableLock.
//
//
void CleanupSecurityFilters(void) { PPROTOCOL_ENTRY pentry; PINTERFACE_ENTRY ientry; CTELockHandle handle;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
while (!EMPTYQ(&InterfaceEntryList)) { DEQUEUE(&InterfaceEntryList, ientry, INTERFACE_ENTRY, ie_link);
while (!EMPTYQ(&(ientry->ie_protocol_list))) { DEQUEUE(&(ientry->ie_protocol_list), pentry, PROTOCOL_ENTRY, pe_link);
DeleteProtocolValueEntries(pentry);
CTEFreeMem(pentry); }
CTEFreeMem(ientry); }
SecurityFilteringEnabled = FALSE;
CTEFreeLock(&AddrObjTableLock.Lock, handle);
return; }
//* IsSecurityFilteringEnabled
//
// This routine returns the current global status of security filtering.
//
// Entry: Nothing
//
// Returns: 0 if filtering is disabled, !0 if filtering is enabled.
//
extern uint IsSecurityFilteringEnabled(void) { uint enabled; CTELockHandle handle;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
enabled = SecurityFilteringEnabled;
CTEFreeLock(&AddrObjTableLock.Lock, handle);
return (enabled); }
//* ControlSecurityFiltering
//
// This routine globally enables/disables security filtering.
//
// Entry: IsEnabled - 0 disabled filtering, !0 enables filtering.
//
// Returns: Nothing
//
extern void ControlSecurityFiltering(uint IsEnabled) { CTELockHandle handle;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
if (IsEnabled) { SecurityFilteringEnabled = TRUE; } else { SecurityFilteringEnabled = FALSE; }
CTEFreeLock(&AddrObjTableLock.Lock, handle);
return; }
//* AddProtocolSecurityFilter
//
// This routine enables security filtering for a specified protocol
// on a specified IP interface.
//
// Entry: InterfaceAddress - The interface on which to enable the protocol.
// (in network byte order)
// Protocol - The protocol to enable.
// ConfigName - The configuration key from which to read
// the filter value information.
//
// Returns: Nothing
//
void AddProtocolSecurityFilter(IPAddr InterfaceAddress, ulong Protocol, NDIS_HANDLE ConfigHandle) { NDIS_STRING filterList; ulong filterValue; ulong i; PINTERFACE_ENTRY ientry; PPROTOCOL_ENTRY pentry; PVOID temp; CTELockHandle handle; TDI_STATUS status = 0;
if (IP_ADDR_EQUAL(InterfaceAddress, NULL_IP_ADDR) || IP_LOOPBACK_ADDR(InterfaceAddress) ) { return; } ASSERT((Protocol != 0) && (Protocol <= 0xFF));
//
// Read the protocol-specific filter value list from the registry.
//
filterList.MaximumLength = filterList.Length = 0; filterList.Buffer = NULL;
if (ConfigHandle != NULL) { status = GetSecurityFilterList(ConfigHandle, Protocol, &filterList); } //
// Preallocate interface & protocol structures. We abort on failure.
// The interface & protocol will be protected by default.
//
ientry = CTEAllocMem(sizeof(INTERFACE_ENTRY));
if (ientry == NULL) { goto cleanup; } ientry->ie_address = InterfaceAddress; INITQ(&(ientry->ie_protocol_list));
pentry = CTEAllocMem(sizeof(PROTOCOL_ENTRY));
if (pentry == NULL) { CTEFreeMem(ientry); goto cleanup; } pentry->pe_protocol = Protocol; pentry->pe_accept_all = FALSE;
for (i = 0; i < VALUE_ENTRY_HASH_SIZE; i++) { INITQ(&(pentry->pe_entries[i])); }
//
// Now go set everything up. First create the interface and protocol
// structures.
//
CTEGetLock(&AddrObjTableLock.Lock, &handle);
temp = FindInterfaceEntry(InterfaceAddress);
if (temp == NULL) { //
// New interface & protocol.
//
ENQUEUE(&InterfaceEntryList, &(ientry->ie_link)); ENQUEUE(&(ientry->ie_protocol_list), &(pentry->pe_link)); } else { //
// Existing interface
//
CTEFreeMem(ientry); ientry = temp;
temp = FindProtocolEntry(ientry, Protocol);
if (temp == NULL) { //
// New protocol
//
ENQUEUE(&(ientry->ie_protocol_list), &(pentry->pe_link)); } else { //
// Existing protocol
//
CTEFreeMem(pentry); } }
CTEFreeLock(&AddrObjTableLock.Lock, handle);
//
// At this point, the protocol entry is installed, but no values
// are permitted. This is the safest default.
//
if (ConfigHandle != NULL) { //
// Process the filter value list.
//
if (status == TDI_SUCCESS) { for (i = 0; EnumSecurityFilterValue(&filterList, i, &filterValue); i++ ) { AddValueSecurityFilter(InterfaceAddress, Protocol, filterValue); } } else if (status == TDI_ITEM_NOT_FOUND) { //
// No filter registered, permit everything.
//
AddValueSecurityFilter(InterfaceAddress, Protocol, 0); } } cleanup: if (filterList.Buffer != NULL) { CTEFreeMem(filterList.Buffer); } return; }
//* DeleteProtocolSecurityFilter
//
// This routine disables security filtering for a specified protocol
// on a specified IP interface.
//
// Entry: InterfaceAddress - The interface on which to disable the protocol.
// (in network byte order)
// Protocol - The protocol to disable.
//
// Returns: Nothing
//
void DeleteProtocolSecurityFilter(IPAddr InterfaceAddress, ulong Protocol) { PINTERFACE_ENTRY ientry; PPROTOCOL_ENTRY pentry; CTELockHandle handle; BOOLEAN deleteInterface = FALSE;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
ientry = FindInterfaceEntry(InterfaceAddress);
if (ientry != NULL) {
ASSERT(!EMPTYQ(&(ientry->ie_protocol_list)));
pentry = FindProtocolEntry(ientry, Protocol);
if (pentry != NULL) { REMOVEQ(&(pentry->pe_link)); } if (EMPTYQ(&(ientry->ie_protocol_list))) { //
// Last protocol, delete interface as well.
//
REMOVEQ(&(ientry->ie_link)); deleteInterface = TRUE; } CTEFreeLock(&AddrObjTableLock.Lock, handle);
if (pentry != NULL) { DeleteProtocolValueEntries(pentry); CTEFreeMem(pentry); } if (deleteInterface) { ASSERT(EMPTYQ(&(ientry->ie_protocol_list))); CTEFreeMem(ientry); } } else { CTEFreeLock(&AddrObjTableLock.Lock, handle); }
return; }
//* AddValueSecurityFilter - Add an entry.
//
// This routine adds a value entry for a specified protocol on a specified
// interface in the security filter database.
//
//
// Input: InterfaceAddress - The interface address to which to add.
// (in network byte order)
// Protocol - The protocol to which to add.
// FilterValue - The transport value to add.
// (in host byte order)
//
// Returns: A TDI status code:
// TDI_INVALID_PARAMETER if the protocol is not in the database.
// TDI_ADDR_INVALID if the interface is not in the database.
// TDI_NO_RESOURCES if memory could not be allocated.
// TDI_SUCCESS otherwise
//
// NOTES:
//
// This routine acquires AddrObjTableLock.
//
// Zero is a wildcard value. Supplying a zero value for the
// InterfaceAddress and/or Protocol causes the operation to be applied
// to all interfaces and/or protocols, as appropriate. Supplying a
// non-zero value causes the operation to be applied to only the
// specified interface and/or protocol. Supplying a FilterValue parameter
// of zero causes all values to be acceptable. Any previously
// registered values are deleted from the database.
//
TDI_STATUS AddValueSecurityFilter(IPAddr InterfaceAddress, ulong Protocol, ulong FilterValue) { CTELockHandle handle; TDI_STATUS status;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
status = ModifySecurityFilter(ADD_VALUE_SECURITY_FILTER, InterfaceAddress, Protocol, FilterValue);
CTEFreeLock(&AddrObjTableLock.Lock, handle);
return (status); }
//* DeleteValueSecurityFilter - Delete an entry.
//
// This routine deletes a value entry for a specified protocol on a specified
// interface in the security filter database.
//
//
// Input: InterfaceAddress - The interface address from which to delete.
// (in network byte order)
// Protocol - The protocol from which to delete.
// FilterValue - The transport value to delete.
// (in host byte order)
//
// Returns: A TDI status code:
// TDI_INVALID_PARAMETER if the protocol is not in the database.
// TDI_ADDR_INVALID if the interface is not in the database.
// TDI_NO_RESOURCES if memory could not be allocated.
// TDI_SUCCESS otherwise
//
// NOTES:
//
// This routine acquires AddrObjTableLock.
//
// Zero is a wildcard value. Supplying a zero value for the
// InterfaceAddress and/or Protocol causes the operation to be applied
// to all interfaces and/or protocols, as appropriate. Supplying a
// non-zero value causes the operation to be applied to only the
// specified interface and/or protocol. Supplying a FilterValue parameter
// of zero causes all values to be rejected. Any previously
// registered values are deleted from the database.
//
TDI_STATUS DeleteValueSecurityFilter(IPAddr InterfaceAddress, ulong Protocol, ulong FilterValue) { CTELockHandle handle; TDI_STATUS status;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
status = ModifySecurityFilter(DELETE_VALUE_SECURITY_FILTER, InterfaceAddress, Protocol, FilterValue);
CTEFreeLock(&AddrObjTableLock.Lock, handle);
return (status); }
//* EnumerateSecurityFilters - Enumerate security filter database.
//
// This routine enumerates the contents of the security filter database
// for the specified protocol and IP interface.
//
// Input: InterfaceAddress - The interface address to enumerate. A value
// of zero means enumerate all interfaces.
// (in network byte order)
//
// Protocol - The protocol to enumerate. A value of zero
// means enumerate all protocols.
//
// Value - The Protocol value to enumerate. A value of
// zero means enumerate all protocol values.
// (in host byte order)
//
// Buffer - A pointer to a buffer into which to put
// the returned filter entries.
//
// BufferSize - On input, the size in bytes of Buffer.
// On output, the number of bytes written.
//
// EntriesAvailable - On output, the total number of filter entries
// available in the database.
//
// Returns: A TDI status code:
//
// TDI_ADDR_INVALID if the address is not a valid IP interface.
// TDI_SUCCESS otherwise.
//
// NOTES:
//
// This routine acquires AddrObjTableLock.
//
// Entries written to output buffer are in host byte order.
//
void EnumerateSecurityFilters(IPAddr InterfaceAddress, ulong Protocol, ulong Value, uchar * Buffer, ulong BufferSize, ulong * EntriesReturned, ulong * EntriesAvailable) { PINTERFACE_ENTRY ientry; CTELockHandle handle;
*EntriesAvailable = *EntriesReturned = 0;
CTEGetLock(&AddrObjTableLock.Lock, &handle);
if (InterfaceAddress == 0) { struct Queue *qentry;
//
// Enumerate all interfaces.
//
for (qentry = InterfaceEntryList.q_next; qentry != &InterfaceEntryList; qentry = qentry->q_next ) { ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
EnumerateInterfaceProtocols( ientry, Protocol, Value, &Buffer, &BufferSize, EntriesReturned, EntriesAvailable ); } } else { //
// Enumerate a specific interface.
//
ientry = FindInterfaceEntry(InterfaceAddress);
if (ientry != NULL) { EnumerateInterfaceProtocols( ientry, Protocol, Value, &Buffer, &BufferSize, EntriesReturned, EntriesAvailable ); } }
CTEFreeLock(&AddrObjTableLock.Lock, handle);
return; }
//* IsPermittedSecurityFilter
//
// This routine determines if communications addressed to
// {Protocol, InterfaceAddress, Value} are permitted by the security filters.
// It looks up the tuple in the security filter database.
//
// Input: InterfaceAddress - The IP interface address to check
// (in network byte order)
// IPContext - The IPContext value passed to the transport
// Protocol - The protocol to check
// Value - The value to check (in host byte order)
//
// Returns: A boolean indicating whether or not the communication is permitted.
//
// NOTES:
//
// This routine must be called with AddrObjTableLock held.
//
//
BOOLEAN IsPermittedSecurityFilter(IPAddr InterfaceAddress, void *IPContext, ulong Protocol, ulong FilterValue) { PINTERFACE_ENTRY ientry; PPROTOCOL_ENTRY pentry; PVALUE_ENTRY ventry; ulong hash_value; struct Queue *qentry;
ASSERT(Protocol <= 0xFF);
for (qentry = InterfaceEntryList.q_next; qentry != &InterfaceEntryList; qentry = qentry->q_next ) { ientry = STRUCT_OF(INTERFACE_ENTRY, qentry, ie_link);
if (ientry->ie_address == InterfaceAddress) {
for (qentry = ientry->ie_protocol_list.q_next; qentry != &(ientry->ie_protocol_list); qentry = qentry->q_next ) { pentry = STRUCT_OF(PROTOCOL_ENTRY, qentry, pe_link);
if (pentry->pe_protocol == Protocol) {
if (pentry->pe_accept_all == TRUE) { //
// All values accepted. Permit operation.
//
return (TRUE); } hash_value = VALUE_ENTRY_HASH(FilterValue);
for (qentry = pentry->pe_entries[hash_value].q_next; qentry != &(pentry->pe_entries[hash_value]); qentry = qentry->q_next ) { ventry = STRUCT_OF(VALUE_ENTRY, qentry, ve_link);
if (ventry->ve_value == FilterValue) { //
// Found it. Operation is permitted.
//
return (TRUE); } }
//
// {Interface, Protocol} protected, but no value found.
// Reject operation.
//
return (FALSE); } }
//
// Protocol not registered. Reject operation
//
return (FALSE); } }
//
// If this packet is on the loopback interface, let it through.
//
if (IP_LOOPBACK_ADDR(InterfaceAddress)) { return (TRUE); } //
// Special check to allow the DHCP client to receive its packets.
// It is safe to make this check all the time because IP will
// not permit a packet to get through on an NTE with a zero address
// unless DHCP is in the process of configuring that NTE.
//
if ((Protocol == PROTOCOL_UDP) && (FilterValue == DHCP_CLIENT_PORT) && (*LocalNetInfo.ipi_isdhcpinterface) (IPContext) ) { return (TRUE); } //
// Interface not registered. Deny operation.
//
return (FALSE); }
|