diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/tcpip/tcp/secfltr.c | 1425 |
1 files changed, 1425 insertions, 0 deletions
diff --git a/private/ntos/tdi/tcpip/tcp/secfltr.c b/private/ntos/tdi/tcpip/tcp/secfltr.c new file mode 100644 index 000000000..df64419e9 --- /dev/null +++ b/private/ntos/tdi/tcpip/tcp/secfltr.c @@ -0,0 +1,1425 @@ +/********************************************************************/ +/** Microsoft LAN Manager **/ +/** Copyright(c) Microsoft Corp., 1990-1993 **/ +/********************************************************************/ +/* :ts=4 */ + +#ifdef SECFLTR + + +//** 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 "oscfg.h" +#include "queue.h" +#include "ndis.h" +#include "cxport.h" +#include "ip.h" +#include "tdi.h" +#include "tdistat.h" + +#ifdef NT + +#include "tdikrnl.h" +#include "tdint.h" +#include "tdistat.h" + +#endif // NT + +#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 NT +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(INIT, InitializeSecurityFilters) + +#endif // ALLOC_PRAGMA +#endif // NT + +// +// 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. +// +EXTERNAL_LOCK(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; + TDI_STATUS status = TDI_SUCCESS; + 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, &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, 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, &handle); + + enabled = SecurityFilteringEnabled; + + CTEFreeLock(&AddrObjTableLock, 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, &handle); + + if (IsEnabled) { + SecurityFilteringEnabled = TRUE; + } + else { + SecurityFilteringEnabled = FALSE; + } + + CTEFreeLock(&AddrObjTableLock, 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; + + + if ( IP_ADDR_EQUAL(InterfaceAddress, NULL_IP_ADDR) || + IP_LOOPBACK_ADDR(InterfaceAddress) + ) + { + return; + } + + CTEAssert( (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) { + return; + } + + ientry->ie_address = InterfaceAddress; + INITQ(&(ientry->ie_protocol_list)); + + pentry = CTEAllocMem(sizeof(PROTOCOL_ENTRY)); + + if (pentry == NULL) { + CTEFreeMem(ientry); + return; + } + + 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, &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, 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); + } + } + + 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, &handle); + + ientry = FindInterfaceEntry(InterfaceAddress); + + if (ientry != NULL) { + + CTEAssert(!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, handle); + + DeleteProtocolValueEntries(pentry); + CTEFreeMem(pentry); + + if (deleteInterface) { + CTEAssert(EMPTYQ(&(ientry->ie_protocol_list))); + CTEFreeMem(ientry); + } + } + else { + CTEFreeLock(&AddrObjTableLock, 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, &handle); + + status = ModifySecurityFilter(ADD_VALUE_SECURITY_FILTER, InterfaceAddress, + Protocol, FilterValue); + + CTEFreeLock(&AddrObjTableLock, 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, &handle); + + status = ModifySecurityFilter(DELETE_VALUE_SECURITY_FILTER, + InterfaceAddress, Protocol, FilterValue); + + CTEFreeLock(&AddrObjTableLock, 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; + TDI_STATUS status = TDI_SUCCESS; + CTELockHandle handle; + + + *EntriesAvailable = *EntriesReturned = 0; + + CTEGetLock(&AddrObjTableLock, &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, 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; + + + CTEAssert(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); +} + + +#endif // SECFLTR + |