diff -urN radiusd-cistron-1.6-dist/raddb/dictionary.ascend radiusd-cistron-1.6/raddb/dictionary.ascend --- radiusd-cistron-1.6-dist/raddb/dictionary.ascend 2001-11-21 13:10:46.000000000 -0600 +++ radiusd-cistron-1.6/raddb/dictionary.ascend 2003-06-02 11:04:13.000000000 -0500 @@ -294,8 +294,8 @@ ATTRIBUTE Ascend-History-Weigh-Type 239 integer Ascend ATTRIBUTE Ascend-Add-Seconds 240 integer Ascend ATTRIBUTE Ascend-Remove-Seconds 241 integer Ascend -#ATTRIBUTE Ascend-Data-Filter 242 abinary Ascend -#ATTRIBUTE Ascend-Call-Filter 243 abinary Ascend +ATTRIBUTE Ascend-Data-Filter 242 abinary Ascend +ATTRIBUTE Ascend-Call-Filter 243 abinary Ascend ATTRIBUTE Ascend-Idle-Limit 244 integer Ascend ATTRIBUTE Ascend-Preempt-Limit 245 integer Ascend ATTRIBUTE Ascend-Callback 246 integer Ascend diff -urN radiusd-cistron-1.6-dist/src/Make.inc radiusd-cistron-1.6/src/Make.inc --- radiusd-cistron-1.6-dist/src/Make.inc 2003-06-02 11:06:29.000000000 -0500 +++ radiusd-cistron-1.6/src/Make.inc 2003-06-02 11:04:49.000000000 -0500 @@ -15,7 +15,8 @@ SERVER_OBJS = radiusd.o files.o acct.o pam.o version.o proxy.o \ exec.o auth.o timestr.o cache.o readusers.o -LIB_OBJS = dict.o util.o md5.o attrprint.o radius.o log.o pair.o encrattr.o +LIB_OBJS = dict.o util.o md5.o attrprint.o radius.o log.o pair.o \ + encrattr.o filters.o INCLUDES = radius.h conf.h @@ -53,6 +54,9 @@ radius.o: radius.c $(INCLUDES) $(CC) $(CFLAGS) $(DIRS) -c radius.c +filters.o: filters.c $(INCLUDES) + $(CC) $(CFLAGS) $(DIRS) -c filters.c + readusers.o: readusers.c $(INCLUDES) $(CC) $(CFLAGS) $(DIRS) -c readusers.c diff -urN radiusd-cistron-1.6-dist/src/attrprint.c radiusd-cistron-1.6/src/attrprint.c --- radiusd-cistron-1.6-dist/src/attrprint.c 2003-04-03 11:23:17.000000000 -0600 +++ radiusd-cistron-1.6/src/attrprint.c 2003-06-02 11:04:13.000000000 -0500 @@ -195,7 +195,16 @@ localtime((time_t *)&pair->lvalue)); fprintf(fd, "\"%s\"", buffer); break; - + case PW_TYPE_FILTER_BINARY: + { + int ix; + + fprintf( fd, "%s = ", pair->name ); + for ( ix = 0; ix < pair->length; ix += 1 ) { + fprintf( fd, " %02x", (unsigned char)(pair->strvalue[ ix ]) ); + } + } + break; default: fprintf(fd, "Unknown type %d", pair->type); break; diff -urN radiusd-cistron-1.6-dist/src/dict.c radiusd-cistron-1.6/src/dict.c --- radiusd-cistron-1.6-dist/src/dict.c 2003-03-11 22:18:59.000000000 -0600 +++ radiusd-cistron-1.6/src/dict.c 2003-06-02 11:04:13.000000000 -0500 @@ -169,6 +169,9 @@ else if(strcmp(typestr, "date") == 0) { type = PW_TYPE_DATE; } + else if(strcmp(typestr, "abinary") == 0) { + type = PW_TYPE_FILTER_BINARY; + } else { log(L_ERR|L_CONS, "dict_init: Invalid type on line %d of %s", diff -urN radiusd-cistron-1.6-dist/src/filters.c radiusd-cistron-1.6/src/filters.c --- radiusd-cistron-1.6-dist/src/filters.c 1969-12-31 18:00:00.000000000 -0600 +++ radiusd-cistron-1.6/src/filters.c 2003-06-02 11:04:13.000000000 -0500 @@ -0,0 +1,1088 @@ +/* + * ASCEND: @(#)filters.c 1.3 (95/07/25 00:55:30) + * + * Copyright (c) 1994 Ascend Communications, Inc. + * All rights reserved. + * + * Permission to copy all or part of this material for any purpose is + * granted provided that the above copyright notice and this paragraph + * are duplicated in all copies. THIS SOFTWARE IS PROVIDED ``AS IS'' + * AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT + * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + */ + +/* $Id: filters.c,v 1.2 1996/12/11 23:17:08 baskar Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include /* gettimeofday() */ + +#include "radiusd.h" + +VALUE_PAIR* prevRadPair = 0; + +#undef DEBUG +#if defined( DEBUG ) +#define PRINTF( x ) printf x +#else +#define PRINTF( x ) +#endif + +#define NO_TOKEN -1 + +typedef struct { + const char* name; + int value; +} KeywordStruct; + + /* + * FilterPortType: + * + * Ascii names of some well known tcp/udp services. + * Used for filtering on a port type. + * + */ + +static KeywordStruct _filterPortType[] = { + { "ftp-data", 20 }, + { "ftp", 21 }, + { "telnet", 23 }, + { "smtp", 25 }, + { "nameserver", 42 }, + { "domain", 53 }, + { "tftp", 69 }, + { "gopher", 70 }, + { "finger", 79 }, + { "www", 80 }, + { "kerberos", 88 }, + { "hostname", 101 }, + { "nntp", 119 }, + { "ntp", 123 }, + { "exec", 512 }, + { "login", 513 }, + { "cmd", 514 }, + { "talk", 517 }, + { NULL , NO_TOKEN }, +}; + +typedef enum { + FILTER_IP_TYPE, + FILTER_GENERIC_TYPE, + FILTER_IN, + FILTER_OUT, + FILTER_FORWARD, + FILTER_DROP, + FILTER_GENERIC_OFFSET, + FILTER_GENERIC_MASK, + FILTER_GENERIC_VALUE, + FILTER_GENERIC_COMPNEQ, + FILTER_GENERIC_COMPEQ, + FILTER_MORE, + FILTER_IP_DST, + FILTER_IP_SRC, + FILTER_IP_PROTO, + FILTER_IP_DST_PORT, + FILTER_IP_SRC_PORT, + FILTER_EST, + FILTER_IPX_TYPE, + FILTER_IPX_DST_IPXNET, + FILTER_IPX_DST_IPXNODE, + FILTER_IPX_DST_IPXSOCK, + FILTER_IPX_SRC_IPXNET, + FILTER_IPX_SRC_IPXNODE, + FILTER_IPX_SRC_IPXSOCK +} FilterTokens; + + +static KeywordStruct _filterKeywords[] = { + { "ip", FILTER_IP_TYPE }, + { "generic",FILTER_GENERIC_TYPE }, + { "in", FILTER_IN }, + { "out", FILTER_OUT }, + { "forward",FILTER_FORWARD }, + { "drop", FILTER_DROP }, + { "dstip", FILTER_IP_DST }, + { "srcip", FILTER_IP_SRC }, + { "dstport",FILTER_IP_DST_PORT }, + { "srcport",FILTER_IP_SRC_PORT }, + { "est", FILTER_EST }, + { "more", FILTER_MORE }, + { "!=", FILTER_GENERIC_COMPNEQ }, + { "==", FILTER_GENERIC_COMPEQ }, + { "ipx", FILTER_IPX_TYPE }, + { "dstipxnet", FILTER_IPX_DST_IPXNET }, + { "dstipxnode", FILTER_IPX_DST_IPXNODE }, + { "dstipxsock", FILTER_IPX_DST_IPXSOCK }, + { "srcipxnet", FILTER_IPX_SRC_IPXNET }, + { "srcipxnode", FILTER_IPX_SRC_IPXNODE }, + { "srcipxsock", FILTER_IPX_SRC_IPXSOCK }, + { NULL , NO_TOKEN }, +}; + +#define FILTER_DIRECTION 0 +#define FILTER_DISPOSITION 1 +#define IP_FILTER_COMPLETE 0x3 /* bits shifted by FILTER_DIRECTION */ + /* FILTER_DISPOSITION */ + +#define IPX_FILTER_COMPLETE 0x3 /* bits shifted by FILTER_DIRECTION */ + /* FILTER_DISPOSITION */ + +#define GENERIC_FILTER_COMPLETE 0x1c3 /* bits shifted for FILTER_DIRECTION */ + /* FILTER_DISPOSITION, FILTER_GENERIC_OFFSET*/ + /* FILTER_GENERIC_MASK, FILTER_GENERIC_VALUE*/ + + /* + * FilterProtoName: + * + * Ascii name of protocols used for filtering. + * + */ +static KeywordStruct _filterProtoName[] = { + { "tcp", 6 }, + { "udp", 17 }, + { "ospf", 89 }, + { "icmp", 1 }, + { NULL , NO_TOKEN }, +}; + +static KeywordStruct _filterCompare[] = { + { ">", RAD_COMPARE_GREATER }, + { "=", RAD_COMPARE_EQUAL }, + { "<", RAD_COMPARE_LESS }, + { "!=", RAD_COMPARE_NOT_EQUAL }, + { NULL , NO_TOKEN }, +}; + +static char _curString[512]; + +int _findKey ( char *string, KeywordStruct *list ); +static int _isAllDigit ( char *token ); +static short _a2octet ( char *tok, char *retBuf ); +static char _defaultNetmask ( unsigned long address ); +static int _ipAddressStringToValue ( char *string, unsigned long *ipAddress, + char *netmask); +static int _parseIpFilter ( RadFilter *curEntry ); +static int _parseGenericFilter ( RadFilter *curEntry ); +static int _parseIpxFilter ( RadFilter *curEntry ); +static int _stringToNode ( unsigned char* dest, unsigned char* src ); + + /* + * _findKey: + * + * Given a table of keywords, it will try and match string to an + * entry. If it does it returns that keyword value. if no NO_TOKEN is + * returned. A sanity check is made for upper case characters. + * + * string: Pointer to the token to match. + * + * list: Point to the list of keywords. + * + * returns: Keyword value on a match or NO_TOKEN. + */ +int _findKey(char *string, KeywordStruct *list) +{ + short len; + KeywordStruct* entry; + char buf[80], *ptr; + + len = strlen( (char *) string ); + for( ptr = buf ; len; len--, string++ ) { + if( isupper( *string ) ) { + *ptr++ = tolower( *string ); + } else { + *ptr++ = *string; + } + } + *ptr = 0; + entry = list; + while( entry->name ) { + if( strcmp( entry->name, buf ) == 0 ) { + break; + } + entry++; + } + return( entry->value ); +} + + /* + * _isAllDigit: + * + * Routine checks a string to make sure all values are digits. + * + * token: Pointer to sting to check. + * + * returns: TRUE if all digits, or FALSE. + * + */ + +static int +_isAllDigit(token) +char *token; +{ + int i; + + i = strlen( (char *) token ); + while( i-- ) { + if( isdigit( *token ) ) { + token++; + } else { + break; + } + } + if( i > 0 ) { + return( FALSE ); + } + + return( TRUE ); +} + + /* + * _a2octet: + * + * Converts the ascii mask and value for generic filters into octets. + * It also does a sanity check to see if the string is greater than + * MAX_FILTER_LEN. It assumes the sting is hex with NO leading "0x" + * + * tok: Pointer to the string. + * + * retBuf: Pointer to place the octets. + * + * returns: Number of octects or -1 for error. + * + */ +static short +_a2octet(tok, retBuf) +char *tok; +char *retBuf; +{ + short rc, len, val, retLen, i; + char buf[ RAD_MAX_FILTER_LEN *2 ]; + char *octet = buf; + + rc = -1; + retLen = 0; + + if( ( len = strlen( (char*) tok ) ) <= ( RAD_MAX_FILTER_LEN*2 ) ) { + retLen = len/2; + if( len % 2 ) { + retLen++; + } + memset( buf, '\0', RAD_MAX_FILTER_LEN * 2 ); + for( ; len; len-- ) { + if( *tok <= '9' && *tok >= '0' ) { + val = '0'; + *octet++ = *tok++ - val; + } else if( isxdigit( *tok ) ) { + if( *tok > 'Z' ) { + val = 'a'; + } else { + val = 'A'; + } + *octet++ = ( *tok++ - val ) + 10; + } else { + break; + } + } + if( !len ) { + /* merge the values */ + for( i = 0; i < RAD_MAX_FILTER_LEN*2; i+=2 ) { + *retBuf++ = (buf[i] << 4) | buf[i+1]; + } + } + } + + if( len ) { + rc = -1; + } else { + rc = retLen; + } + return( rc ); +} + + + + /* + * _defaultNetMask: + * + * Given an ip address this routine calculate a default netmask. + * + * address: Ip address. + * + * returns: Number of bits for the netmask + * + */ +static char +_defaultNetmask(address) +unsigned long address; +{ + char netmask; + + if ( ! address ) { + netmask = 0; + } else if (( address & htonl( 0x80000000 ) ) == 0 ) { + netmask = 8; + } else if (( address & htonl( 0xc0000000 ) ) == htonl( 0x80000000 ) ) { + netmask = 16; + } else if (( address & htonl( 0xe0000000 ) ) == htonl( 0xc0000000 ) ) { + netmask = 24; + } else { + netmask = 32; + } + return netmask; +} + + +static char ipAddressDigits[] = "1234567890./"; + /* + * This functions attempts to convert an IP address in ASCII dot + * with an optional netmask part to a pair of IpAddress. Note: + * An IpAddress is always stored in network byte order. + * + * Parameters: + * + * string: Pointer to a NULL terminated IP address in dot + * notation followed by an optional /nn to indicate + * the number leading of bits in the netmask. + * + * ipAddress: Pointer to an IpAddress where the converted + * address will be stored. + * + * netmask: Pointer to an IpAddress where the netmask + * will be stored. If no netmask is passed as + * as part of the address the default netmask will + * be stored here. + * + * Returns: + * <> TRUE if valid conversion, FALSE otherwise. + * + * *ipAddress: If function returns TRUE, the IP address in NBO. + * *netmask: If function returns TRUE, the netmask in NBO. + */ + +static int +_ipAddressStringToValue(char *string, unsigned long *ipAddress, + char *netmask) +{ + u_char* dst; + char* cp; + int numDots; + int i; + long value; + + if ( ! string ) { + return(FALSE); + } + + /* Allow an IP address to be blanked instead of forcing entry of + 0.0.0.0 -- the user will like it. */ + + if ( *string == 0 ) { + *ipAddress = 0; + *netmask = 0; + return TRUE; + } + + /* First just count the number of dots in the address. If there + are more or less than three the address is invalid. */ + + cp = string; + numDots = 0; + while( *cp ) { + if( !strchr( ipAddressDigits, *cp) ) { + return( FALSE ); + } + if ( *cp == '.') { + ++numDots; + } + ++cp; + } + if ( numDots != 3 ) { + return( FALSE ); + } + + dst = (u_char *) ipAddress; + cp = string; + + for ( i = 0; i < sizeof( *ipAddress ); i++ ) { + value = strtol( cp, (char**) &cp, 10 ); + if (( value < 0 ) || ( value > 255 )) { + return( FALSE ); + } + *dst++ = (u_char) value; + if ( *cp == '.' ) { + cp += 1; + } + } + + /* If there is a netmask part, parse it, otherwise figure out the + default netmask for this class of address. */ + + if ( *cp == '/' ) { + value = strtol( cp + 1, (char**) &cp, 10 ); + if (( *cp != 0 ) || ( value < 0 ) || ( value > 32 )) { + return FALSE; + } + *netmask = (char) value; + } else { + *netmask = _defaultNetmask( *ipAddress ); + } + return TRUE; +} + + /* + * Convert a 12 digit string representation of a hex data field to a + * value. + */ +static int +_stringToNode(dest, src ) +unsigned char* dest; +unsigned char* src; +{ + int srcIx = 0; + int ix; + int nibble1; + int nibble2; + int temp; + unsigned char *src1; + + src1 = (unsigned char *) strchr(src, 'x'); + + if (src1 == NULL) + src1 = (unsigned char *) strchr(src,'X'); + + if (src1 == NULL) + src1 = src; + else + src1++; + + /* skip any leading 0x or 0X 's */ + temp = strlen( (char*) src1 ); + if( strlen( (unsigned char*) src1 ) != ( IPX_NODE_ADDR_LEN * 2 ) ) { + return( FALSE ); + } + + for ( ix = 0; ix < IPX_NODE_ADDR_LEN; ++ix ) { + if ( src1[ srcIx ] <= '9' ) { + nibble1 = src1[ srcIx ] & 0x0f; + } else { + nibble1 = (src1[ srcIx ] & 0x0f) + 9; + } + srcIx += 1; + if ( src1[ srcIx ] <= '9' ) { + nibble2 = src1[ srcIx ] & 0x0f; + } else { + nibble2 = (src1[ srcIx ] & 0x0f) + 9; + } + srcIx += 1; + ((unsigned char *) dest)[ ix ] = (unsigned char) (nibble1 << 4) + nibble2; + } + + return( TRUE ); +} + + + /* + * _parseIpxFilter: + * + * This routine parses an IPX filter string from a RADIUS + * reply. The format of the string is: + * + * ipx dir action [ srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]] + * [ dstipxnet nnnn dstipxnode mmmmm [dstipxsoc cmd value ]] + * + * Fields in [...] are optional. + * where: + * + * ipx: Keyword to designate an IPX filter. Actually this + * has been determined by _parseFilter. + * + * dir: Filter direction. "IN" or "OUT" + * + * action: Filter action. "FORWARD" or "DROP" + * + * srcipxnet: Keyword for source IPX address. + * nnnn = IPX Node address. + * + * srcipxnode: Keyword for source IPX Node address. + * mmmmm = IPX Node Address, could be FFFFFF. + * A vlid ipx node number should accompany ipx net number. + * + * srcipxsoc: Keyword for source IPX socket address. + * + * cmd: One of ">" or "<" or "=" or "!=". + * + * value: Socket value to be compared against, in hex. + * + * dstipxnet: Keyword for destination IPX address. + * nnnn = IPX Node address. + * + * dstipxnode: Keyword for destination IPX Node address. + * mmmmm = IPX Node Address, could be FFFFFF. + * A vlid ipx node number should accompany ipx net number. + * + * dstipxsoc: Keyword for destination IPX socket address. + * + * cmd: One of ">" or "<" or "=" or "!=". + * + * value: Socket value to be compared against, in hex. + * + * + * expects: + * + * curEntry: Pointer to place the filter structure + * + * returns: -1 for error or 0 for OK + * + */ + +static int +_parseIpxFilter(curEntry) +RadFilter *curEntry; +{ + unsigned long elements = 0l; + int tok; + char* token; + RadIpxFilter* ipx; + + token = (char *) strtok( NULL, " " ); + + memset( curEntry, '\0', sizeof( RadFilter ) ); + curEntry->type = RAD_FILTER_IPX; + ipx = &curEntry->u.ipx; + + while( token ) { + tok = _findKey( token, _filterKeywords ); + switch( tok ) { + case FILTER_IN: + case FILTER_OUT: + curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE; + PRINTF((" got FILTER %s ", tok == FILTER_IN?"IN":"OUT")); + elements |= (1 << FILTER_DIRECTION ); + break; + + case FILTER_FORWARD: + case FILTER_DROP: + PRINTF((" got FILTER %s ", + tok == FILTER_DROP? "DROP":"FORWARD")); + + elements |= (1 << FILTER_DISPOSITION ); + if( tok == FILTER_FORWARD ) { + curEntry->forward = TRUE; + } else { + curEntry->forward = FALSE; + } + break; + + case FILTER_IPX_DST_IPXNET: + case FILTER_IPX_SRC_IPXNET: + PRINTF((" got FILTER_IPX %s IPXNET ", + tok == FILTER_IPX_DST_IPXNET ? "DST":"SRC")); + token = (char *) strtok( NULL, " " ); + + if ( token ) { + if( tok == FILTER_IPX_DST_IPXNET ) { + ipx->dstIpxNet = ntohl( strtol( token, 0, 16 )); + PRINTF(("D.Net: %08lX token: %s \n", htonl(ipx->dstIpxNet), token)); + } else { + ipx->srcIpxNet = ntohl( strtol( token, 0, 16 )); + PRINTF(("S Net: %08lX token: %s \n", htonl(ipx->srcIpxNet), token)); + } + break; + } + goto doneErr; + + case FILTER_IPX_DST_IPXNODE: + case FILTER_IPX_SRC_IPXNODE: + PRINTF((" got FILTER_IPX %s IPXNODE ", + tok == FILTER_IPX_DST_IPXNODE ? "DST":"SRC")); + token = (char *) strtok( NULL, " " ); + + if ( token ) { + if ( tok == FILTER_IPX_DST_IPXNODE) { + _stringToNode( (unsigned char *)ipx->dstIpxNode, (unsigned char*)token ); + PRINTF(("D. Node: %08lX%04X \n", + htonl((*(int *)(ipx->dstIpxNode))), + htons((*(short *)(ipx->dstIpxNode+4))))); + } else { + _stringToNode( (unsigned char *)ipx->srcIpxNode, (unsigned char*)token ); + PRINTF(("S. Node: %08lX%04X \n", + htonl((*(int *)(ipx->srcIpxNode))), + htons((*(short *)(ipx->srcIpxNode+4))))); + } + break; + } + goto doneErr; + + case FILTER_IPX_DST_IPXSOCK: + case FILTER_IPX_SRC_IPXSOCK: + { + RadFilterComparison cmp; + + PRINTF((" got FILTER_IPX %s IPXSOCK", + tok == FILTER_IPX_DST_IPXSOCK ? "DST":"SRC")); + token = (char *) strtok( NULL, " " ); + + if ( token ) { + cmp = _findKey( token, _filterCompare ); + PRINTF((" cmp value = %d \n", cmp )); + if( cmp != NO_TOKEN ) { + token = (char *) strtok( NULL, " " ); + if ( token ) { + if ( tok == FILTER_IPX_DST_IPXSOCK ) { + ipx->dstSocComp = cmp; + ipx->dstIpxSoc = + ntohs( (IpxSocket) strtol( token, NULL, 16 )); + PRINTF(("%X \n", htons(ipx->dstIpxSoc))); + } else { + ipx->srcSocComp = cmp; + ipx->srcIpxSoc + = ntohs( (IpxSocket) strtol( token, NULL, 16 )); + PRINTF(("%X \n", htons(ipx->srcIpxSoc))); + } + break; + } + } + } + goto doneErr; + } + + default: + /* no keyword match */ + goto doneErr; + } + token = (char *) strtok( NULL, " " ); + } + + if( elements == IPX_FILTER_COMPLETE ) { + return( 0 ); + } + +doneErr: + PRINTF(( "RADIF: IPX Filter syntax error %s \n", token )); + log(L_ERR, "ipx filter error: do not recognize %s in %s \n", + token, _curString ); + return( -1 ); +} + + /* + * _parseIpFilter: + * + * This routine parses an IP filter string from a RADIUS + * reply. The format of the string is: + * + * ip dir action [ dstip n.n.n.n/nn ] [ srcip n.n.n.n/nn ] + * [ proto [ dstport cmp value ] [ srcport cmd value ] [ est ] ] + * + * Fields in [...] are optional. + * where: + * + * ip: Keyword to designate an IP filter. Actually this + * has been determined by _parseFilter. + * + * dir: Filter direction. "IN" or "OUT" + * + * action: Filter action. "FORWARD" or "DROP" + * + * dstip: Keyword for destination IP address. + * n.n.n.n = IP address. /nn - netmask. + * + * srcip: Keyword for source IP address. + * n.n.n.n = IP address. /nn - netmask. + * + * proto: Optional protocol field. Either a name or + * number. Known names are in FilterProtoName[]. + * + * dstpost: Keyword for destination port. Only valid with tcp + * or udp. 'cmp' are in FilterPortType[]. 'value' can be + * a name or number. + * + * srcpost: Keyword for source port. Only valid with tcp + * or udp. 'cmp' are in FilterPortType[]. 'value' can be + * a name or number. + * + * est: Keyword for TCP established. Valid only for tcp. + * + * expects: + * + * curEntry: Pointer to place the filter structure + * + * returns: -1 for error or 0 for OK + * + */ + +static int +_parseIpFilter(curEntry) +RadFilter *curEntry; +{ + + unsigned long elements = 0l; + int tok; + char* token; + RadIpFilter* ip; + + token = (char *) strtok( NULL, " " ); + + PRINTF((" in ip filter \n")); + + memset( curEntry, '\0', sizeof( RadFilter ) ); + curEntry->type = RAD_FILTER_IP; + ip = &curEntry->u.ip; + ip->established = FALSE; + + while( token ) { + PRINTF((" token %s ", token )); + tok = _findKey( token, _filterKeywords ); + switch( tok ) { + case FILTER_IN: + case FILTER_OUT: + curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE; + PRINTF((" got %s ", tok == FILTER_IN?"FILTER_IN":"FILTER_OUT")); + elements |= (1 << FILTER_DIRECTION ); + break; + case FILTER_FORWARD: + case FILTER_DROP: + PRINTF((" got %s ", tok == FILTER_DROP? + "FILTER_DROP":"FILTER_FORWARD")); + elements |= (1 << FILTER_DISPOSITION ); + if( tok == FILTER_FORWARD ) { + curEntry->forward = TRUE; + } else { + curEntry->forward = FALSE; + } + break; + case FILTER_IP_DST: + case FILTER_IP_SRC: + PRINTF((" got %s ", tok == FILTER_IP_DST? + "FILTER_IP_DST":"FILTER_IP_SRC")); + token = (char *) strtok( NULL, " " ); + if ( token ) { + if( tok == FILTER_IP_DST ) { + + if( _ipAddressStringToValue( (char*)token, + &ip->dstip, (char *)&ip->dstmask ) ) { + PRINTF((" ip %lx netmask %lx \n", ip->dstip, + ip->dstmask )); + break; + } + } else { + if( _ipAddressStringToValue( (char *)token, + &ip->srcip, (char *)&ip->srcmask ) ) { + PRINTF((" ip %lx netmask %lx \n", ip->srcip, + ip->srcmask )); + break; + } + } + } + + PRINTF(( "RADIF: IP Filter syntax error %s \n", token )); + log(L_ERR, "ip filter error: do not recognize %s in %s \n", + token, _curString ); + goto doneErr ; + + case FILTER_IP_DST_PORT: + case FILTER_IP_SRC_PORT: + { + RadFilterComparison cmp; + short port; + + PRINTF((" got %s ", tok == FILTER_IP_DST_PORT? + "FILTER_IP_DST_PORT":"FILTER_IP_SRC_PORT")); + token = (char *) strtok( NULL, " " ); + if ( token ) { + cmp = _findKey( token, _filterCompare ); + PRINTF((" cmp value = %d \n", cmp )); + if( cmp != NO_TOKEN ) { + token = (char *) strtok( NULL, " " ); + if ( token ) { + if( _isAllDigit( token ) ) { + port = atoi( (char *) token ); + } else { + port = _findKey( token, _filterPortType ); + } + if( port != (short) NO_TOKEN ) { + PRINTF((" port = %d \n", port )); + if( tok == FILTER_IP_DST_PORT ) { + ip->dstPortComp = cmp; + ip->dstport = htons( port ); + } else { + ip->srcPortComp = cmp; + ip->srcport = htons( port ); + } + break; + } + } + } + } + log( L_ERR, "ip filter error: do not recognize %s in %s \n", + token, _curString ); + PRINTF(( "RADIF: IP Filter syntax error %s \n", token )); + goto doneErr; + break; + } + case FILTER_EST: + PRINTF((" got est %s ", token )); + ip->established = TRUE; + break; + default: + /* no keyword match but may match a protocol list */ + if( _isAllDigit( token ) ) { + tok = atoi( (char *) token ); + } else { + tok = _findKey( token, _filterProtoName ); + + if( tok == NO_TOKEN ) { + PRINTF(( "RADIF: IP proto error %s \n", token )); + log(L_ERR, "ip filter error: do not recognize %s in %s \n", + token, _curString ); + goto doneErr; + } + } + ip->proto = tok; + PRINTF(("ip proto cmd = %d ", tok)); + } + token = (char *) strtok( NULL, " " ); + } + + if( elements == IP_FILTER_COMPLETE ) { + return( 0 ); + } + +doneErr: + PRINTF((" done err \n")); + return( -1 ); +} + + /* + * _parseGenericFilter: + * + * This routine parses a Generic filter string from a RADIUS + * reply. The format of the string is: + * + * GENERIC dir action offset mask value [== or != ] [more] + * + * Fields in [...] are optional. + * where: + * + * generic: Keyword to indicate a generic filter. This + * has been determined by _parseFilter. + * + * dir: Filter direction. "IN" or "OUT" + * + * action: Filter action. "FORWARD" or "DROP" + * + * offset: A Number. Specifies an offset into a frame + * to start comparing. + * + * mask: A hexadecimal mask of bits to compare. + * + * value: A value to compare with the masked data. + * + * compNeq: Defines type of comparison. ( "==" or "!=") + * Default is "==". + * + * more: Optional keyword MORE, to represent the attachment + * to the next entry. + * + * expects: + * + * curEntry: Pointer to place the filter structure + * + * returns: -1 for error or 0 for OK + * + */ + +static int +_parseGenericFilter(curEntry) +RadFilter *curEntry; +{ + unsigned long elements = 0l; + int tok; + int gstate = FILTER_GENERIC_OFFSET; + char* token; + short valLen, maskLen; + RadGenericFilter* gen; + + token = (char *) strtok( NULL, " " ); + + PRINTF((" in parse generic filter \n")); + + maskLen = 0; + memset( (char *)curEntry, '\0', sizeof( RadFilter ) ); + curEntry->type = RAD_FILTER_GENERIC; + gen = &curEntry->u.generic; + gen->more = FALSE; + gen->compNeq = FALSE; + + while( token ) { + PRINTF((" token %s ", token )); + tok = _findKey( token, _filterKeywords ); + PRINTF(("tok %d ", tok)); + switch( tok ) { + case FILTER_IN: + case FILTER_OUT: + curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE; + elements |= (1 << FILTER_DIRECTION ); + PRINTF((" got %s ", tok == FILTER_IN?"FILTER_IN":"FILTER_OUT")); + break; + case FILTER_FORWARD: + case FILTER_DROP: + elements |= (1 << FILTER_DISPOSITION ); + PRINTF((" got %s ", tok == FILTER_DROP? + "FILTER_DROP":"FILTER_FORWARD")); + if( tok == FILTER_FORWARD ) { + curEntry->forward = TRUE; + } else { + curEntry->forward = FALSE; + } + break; + case FILTER_GENERIC_COMPNEQ: + gen->compNeq = TRUE; + PRINTF((" got compare %s ", token)); + break; + case FILTER_GENERIC_COMPEQ: + gen->compNeq = FALSE; + PRINTF((" got compare %s ", token)); + break; + case FILTER_MORE: + gen->more = htons( TRUE ); + PRINTF((" got more %s ", token )); + break; + default: + elements |= ( 1 << gstate ); + switch( gstate ) { + case FILTER_GENERIC_OFFSET: + gstate = FILTER_GENERIC_MASK; + gen->offset = htons( atoi( (char *) token ) ); + break; + case FILTER_GENERIC_MASK: + gstate = FILTER_GENERIC_VALUE; + maskLen = _a2octet( token, (char *)gen->mask ); + if( maskLen == (short) -1 ) { + log(L_ERR, "filter mask error: %s \n", _curString ); + goto doneErr; + } +#ifdef DEBUG + PRINTF((" octet retlen = %d ", maskLen )); + for( tok = 0; tok < maskLen; tok++) { + PRINTF(("%2x", gen->mask[tok])); + } + PRINTF(("\n")); +#endif + + break; + case FILTER_GENERIC_VALUE: + gstate ++; + valLen = _a2octet( token, (char *)gen->value ); + if( valLen != maskLen ) { + log(L_ERR, "filter value size is not the same size as the filter mask: %s \n", + _curString ); + goto doneErr; + } + gen->len = htons( valLen ); +#ifdef DEBUG + PRINTF((" octet retlen = %d ", maskLen )); + for( tok = 0; tok < maskLen; tok++) { + PRINTF(("%2x", gen->value[tok])); + } + PRINTF(("\n")); +#endif + + break; + default: + log(L_ERR, "filter: do not know %s in %s \n", + token, _curString ); + PRINTF(( "RADIF: Filter syntax error %s \n", token )); + goto doneErr; + } + } + token = (char *) strtok( NULL, " " ); + } + + if( elements == GENERIC_FILTER_COMPLETE ) { + return( 0 ); + } + +doneErr: + PRINTF((" done err \n")); + return( -1 ); +} + + /* + * filterBinary: + * + * This routine will call routines to parse entries from an ASCII format + * to a binary format recognized by the Ascend boxes. + * + * pair: Pointer to value_pair to place return. + * + * valstr: The string to parse + * + * return: -1 for error or 0. + */ +int +filterBinary(pair, valstr) +VALUE_PAIR *pair; +char *valstr; +{ + + char* token; + unsigned long tok; + int rc; + RadFilter radFil, *filt; + RadGenericFilter* gen; + + rc = -1; + strcpy( _curString, valstr ); + + token = (char *) strtok( (char *)valstr, " " ); + tok = _findKey( token, _filterKeywords ); + pair->length = sizeof( RadFilter ); + switch( tok ) { + case FILTER_IP_TYPE: + rc = _parseIpFilter( &radFil ); + break; + case FILTER_GENERIC_TYPE: + rc = _parseGenericFilter( &radFil ); + break; + case FILTER_IPX_TYPE: + rc = _parseIpxFilter( &radFil ); + break; + } + + /* + * if more is set then this new entry must exist, be a + * FILTER_GENERIC_TYPE, direction and disposition must match for + * the previous more to be valid. If any should fail then TURN OFF + * previos more + */ + if( prevRadPair ) { + filt = ( RadFilter * )prevRadPair->strvalue; + if(( tok != FILTER_GENERIC_TYPE ) || (rc == -1 ) || + ( prevRadPair->attribute != pair->attribute ) || + ( filt->indirection != radFil.indirection ) || + ( filt->forward != radFil.forward ) ) { + gen = &filt->u.generic; + gen->more = FALSE; + log(L_ERR, "filterBinary: 'more' for previous entry doesn't match: %s.\n", + _curString ); + } + } + prevRadPair = NULL; + if( rc != -1 && tok == FILTER_GENERIC_TYPE ) { + if( radFil.u.generic.more ) { + prevRadPair = pair; + } + } + + if( rc != -1 ) { + memcpy( pair->strvalue, (char *) &radFil, pair->length ); + } + return(rc); +} + diff -urN radiusd-cistron-1.6-dist/src/pair.c radiusd-cistron-1.6/src/pair.c --- radiusd-cistron-1.6-dist/src/pair.c 2003-04-03 11:23:17.000000000 -0600 +++ radiusd-cistron-1.6/src/pair.c 2003-06-02 11:04:13.000000000 -0500 @@ -613,6 +613,16 @@ switch(pair->type) { + case PW_TYPE_FILTER_BINARY: + /* + * special case to convert filter to binary + */ + if ( filterBinary( pair, valstr ) == -1 ) { + free(pair); + return(-1); + } + break; + case PW_TYPE_STRING: /* Pair->strvalue has been set already */ pair->length = strlen(pair->strvalue); diff -urN radiusd-cistron-1.6-dist/src/radius.c radiusd-cistron-1.6/src/radius.c --- radiusd-cistron-1.6-dist/src/radius.c 2003-03-11 22:18:59.000000000 -0600 +++ radiusd-cistron-1.6/src/radius.c 2003-06-02 11:04:13.000000000 -0500 @@ -166,6 +166,7 @@ switch(vp->type) { + case PW_TYPE_FILTER_BINARY: case PW_TYPE_STRING: /* * FIXME: this is just to make sure but @@ -508,6 +509,7 @@ switch (pair->type) { + case PW_TYPE_FILTER_BINARY: case PW_TYPE_STRING: /* attrlen always < AUTH_STRING_LEN */ memset(pair->strvalue, 0, AUTH_STRING_LEN); diff -urN radiusd-cistron-1.6-dist/src/radius.h radiusd-cistron-1.6/src/radius.h --- radiusd-cistron-1.6-dist/src/radius.h 2003-04-03 11:23:17.000000000 -0600 +++ radiusd-cistron-1.6/src/radius.h 2003-06-02 11:05:33.000000000 -0500 @@ -57,6 +57,7 @@ #define PW_TYPE_IPADDR 2 #define PW_TYPE_DATE 3 #define PW_TYPE_INTEGER8 4 +#define PW_TYPE_FILTER_BINARY 5 /* ASCEND extension */ #define PW_AUTHENTICATION_REQUEST 1 @@ -205,3 +206,193 @@ #define PW_STATUS_ACCOUNTING_ON 7 #define PW_STATUS_ACCOUNTING_OFF 8 +/* + * ASCEND extensions for ABINARY filters + */ + +#define IPX_NODE_ADDR_LEN 6 + +typedef UINT4 IpxNet; +typedef char IpxNode[ IPX_NODE_ADDR_LEN ]; +typedef unsigned short IpxSocket; + +#if ! defined( FALSE ) +# define FALSE 0 +# define TRUE (! FALSE) +#endif + +/* + * Two types of filters are supported, GENERIC and IP. The identifiers + * are: + */ + +#define RAD_FILTER_GENERIC 0 +#define RAD_FILTER_IP 1 +#define RAD_FILTER_IPX 2 + +/* + * Generic filters mask and match up to RAD_MAX_FILTER_LEN bytes + * starting at some offset. The length is: + */ +#define RAD_MAX_FILTER_LEN 6 + +/* + * RadFilterComparison: + * + * An enumerated values for the IP filter port comparisons. + */ +typedef enum { + RAD_NO_COMPARE, + RAD_COMPARE_LESS, + RAD_COMPARE_EQUAL, + RAD_COMPARE_GREATER, + RAD_COMPARE_NOT_EQUAL +} RadFilterComparison; + + /* + * RadIpFilter: + * + * The binary format of an IP filter. ALL fields are stored in + * network byte order. + * + * srcip: The source IP address. + * + * dstip: The destination IP address. + * + * srcmask: The number of leading one bits in the source address + * mask. Specifies the bits of interest. + * + * dstmask: The number of leading one bits in the destination + * address mask. Specifies the bits of interest. + * + * proto: The IP protocol number + * + * establised: A boolean value. TRUE when we care about the + * established state of a TCP connection. FALSE when + * we dont care. + * + * srcport: TCP or UDP source port number. + * + * dstport: TCP or UDP destination port number. + * + * srcPortCmp: One of the values of the RadFilterComparison enumeration + * specifying how to compare the srcport value. + * + * dstPortCmp: One of the values of the RadFilterComparison enumeration + * specifying how to compare the dstport value. + * + * fill: Round things out to a dword boundary. + */ +typedef struct radip { + UINT4 srcip; + UINT4 dstip; + unsigned char srcmask; + unsigned char dstmask; + unsigned char proto; + unsigned char established; + unsigned short srcport; + unsigned short dstport; + unsigned char srcPortComp; + unsigned char dstPortComp; + unsigned char fill[4]; /* used to be fill[2] */ +} RadIpFilter; + + /* + * RadIpxFilter: + * The binary format of a GENERIC filter. ALL fields are stored in + * network byte order. + * + * srcIpxNet: Source IPX Net address + * + * srcIpxNode: Source IPX Node address + * + * srcIpxSoc: Source IPX socket address + * + * dstIpxNet: Destination IPX Net address + * + * dstIpxNode: Destination IPX Node address + * + * dstIpxSoc: Destination IPX socket address + * + * srcSocComp: Source socket compare value + * + * dstSocComp: Destination socket compare value + * + */ +typedef struct radipx { + IpxNet srcIpxNet; /* LongWord */ + IpxNode srcIpxNode; /* Byte[6] */ + IpxSocket srcIpxSoc; /* Word */ + IpxNet dstIpxNet; /* LongWord */ + IpxNode dstIpxNode; /* Byte[6] */ + IpxSocket dstIpxSoc; /* Word */ + unsigned char srcSocComp; + unsigned char dstSocComp; +} RadIpxFilter; + + /* + * RadGenericFilter: + * + * The binary format of a GENERIC filter. ALL fields are stored in + * network byte order. + * + * offset: Number of bytes into packet to start comparison. + * + * len: Number of bytes to mask and compare. May not + * exceed RAD_MAX_FILTER_LEN. + * + * more: Boolean. If non-zero the next filter entry is + * also to be applied to a packet. + * + * mask: A bit mask specifying the bits to compare. + * + * value: A value to compare against the masked bits at + * offset in a users packet. + * + * compNeq: Defines type of comarison (Equal or Notequal) + * default is Equal. + * + * fill: Round things out to a dword boundary + */ +typedef struct radgeneric { + unsigned short offset; + unsigned short len; + unsigned short more; + unsigned char mask[ RAD_MAX_FILTER_LEN ]; + unsigned char value[ RAD_MAX_FILTER_LEN ]; + unsigned char compNeq; + unsigned char fill[3]; /* used to be fill */ +} RadGenericFilter; + + /* + * RadFilter: + * + * A binary filter element. Contains either a RadIpFilter or a + * RadGenericFilter. All fields are stored in network byte order. + * + * type: Either RAD_FILTER_GENERIC or RAD_FILTER_IP. + * + * forward: TRUE if we should forward packets that match this + * filter, FALSE if we should drop packets that match + * this filter. + * + * indirection: TRUE if this is an input filter, FALSE if this is + * an output filter. + * + * fill: Round things out to a dword boundary. + * + * u: A union of + * ip: An ip filter entry + * generic: A generic filter entry + */ +typedef struct filter { + unsigned char type; + unsigned char forward; + unsigned char indirection; + unsigned char fill; + union { + RadIpFilter ip; + RadIpxFilter ipx; + RadGenericFilter generic; + } u; +} RadFilter; diff -urN radiusd-cistron-1.6-dist/src/radiusd.h radiusd-cistron-1.6/src/radiusd.h --- radiusd-cistron-1.6-dist/src/radiusd.h 2003-03-11 22:18:59.000000000 -0600 +++ radiusd-cistron-1.6/src/radiusd.h 2003-06-02 11:04:13.000000000 -0500 @@ -326,6 +326,9 @@ int rad_dbm_open(void); #endif +/* filters.c */ +int filterBinary(VALUE_PAIR *pair, char *valstr); + /* version.c */ void version();