Added 'key' field, so that we can later get rid of the rfc_clean()
authoraland <aland>
Wed, 22 Nov 2006 21:44:19 +0000 (21:44 +0000)
committeraland <aland>
Wed, 22 Nov 2006 21:44:19 +0000 (21:44 +0000)
function.

Added a bit of a wildcard for to handle 'Vendor-Specific =* ANY'

man/man5/rlm_attr_filter.5
src/modules/rlm_attr_filter/rlm_attr_filter.c

index dde891a..6f79c07 100644 (file)
@@ -3,23 +3,24 @@
 rlm_attr_filter \- FreeRADIUS Module
 .SH DESCRIPTION
 The \fIrlm_attr_filter\fP module exists for filtering certain
-attributes and values in received ( or transmitted ) radius packets
-from ( or to ) remote proxy servers.  It gives the proxier ( us ) a
-flexible framework to filter the attributes we send to or receive
-from these remote proxies.  This makes sense, for example, in an
-out-sourced dialup situation to various policy decisions, such as
-restricting a client to certain ranges of Idle-Timeout or
-Session-Timeout.
+attributes and values in received ( or transmitted ) radius packets.
+It gives the server a flexible framework to filter the attributes we
+send to or receive from home servers or NASes.  This makes sense, for
+example, in an out-sourced dialup situation to various policy
+decisions, such as restricting a client to certain ranges of
+Idle-Timeout or Session-Timeout.
 .PP
-Filter rules are defined and applied on a per-realm basis, where the
-realm is anything that is defined and matched based on the
-configuration of the \fIrlm_realm\fP module.
+Filter rules are normally defined and applied on a per-realm basis,
+where the realm is anything that is defined and matched based on the
+configuration of the \fIrlm_realm\fP module.  Filter rules can
+optionally be applied using another attribute, by editing the
+\fIkey\fP configuration for this module.
 .PP
 The file that defines the attribute filtering rules follows a similar
 syntax to the \fIusers\fP file.  There are a few differences however:
 .PP
 .DS
-    There are no check-items allowed other than the realm.
+    There are no check-items allowed other than the name of the key.
 .PP
     There can only be a single DEFAULT entry.
 .PP
@@ -58,7 +59,7 @@ Greater Than or Equal
 Less Than or Equal
 .TP
 .B    >   
-Greather Than
+Greater Than
 .TP
 .B    <   
 Less Than
@@ -79,9 +80,16 @@ See the default \fI/etc/raddb/attrs\fP for working examples of
 sample rule ordering and how to use the different operators.
 .DE
 .PP
-The main configuration item is:
+The configuration items are:
 .IP attrsfile
 This specifies the location of the file used to load the filter rules.
+This file is used to filter the accounting response, packet before it
+is proxied, proxy response from the home server, or our response to
+the NAS.
+.IP key
+Usually %{Realm} (the default).  Can also be %{User-Name}, or other
+attribute that exists in the request.  Note that the module always
+keys off of attributes in the request, and NOT in any other packet.
 .PP
 .SH SECTIONS
 .BR accounting,
index c51d926..9dbcb51 100644 (file)
@@ -46,12 +46,15 @@ RCSID("$Id$")
  */
 struct attr_filter_instance {
         char *attrsfile;
+       char *key;
         PAIR_LIST *attrs;
 };
 
 static const CONF_PARSER module_config[] = {
        { "attrsfile",     PW_TYPE_FILENAME,
          offsetof(struct attr_filter_instance,attrsfile), NULL, "${raddbdir}/attrs" },
+       { "key",     PW_TYPE_STRING_PTR,
+         offsetof(struct attr_filter_instance,key), NULL, "%{Realm}" },
        { NULL, -1, 0, NULL, NULL }
 };
 
@@ -150,6 +153,7 @@ static int attr_filter_detach(void *instance)
        struct attr_filter_instance *inst = instance;
        pairlist_free(&inst->attrs);
        free(inst->attrsfile);
+       free(inst->key);
        free(inst);
        return 0;
 }
@@ -199,25 +203,32 @@ static int attr_filter_common(void *instance, REQUEST *request,
        PAIR_LIST       *pl;
        int             found = 0;
        int             pass, fail = 0;
-       VALUE_PAIR      *realmpair;
-       char            *realmname = NULL;
+       char            *keyname = NULL;
+       char            buffer[256];
 
-       /*
-        *      Get the realm.  Can't use request->config_items as
-        *      that gets freed by rad_authenticate....  use the one
-        *      set in the original request vps
-        */
-       realmpair = pairfind(request->packet->vps, PW_REALM);
-       if (!realmpair) {
-               /* If there is no realm...NOOP */
-               return (RLM_MODULE_NOOP);
+       if (!inst->key) {
+               VALUE_PAIR      *namepair;
+
+               namepair = pairfind(request->packet->vps, PW_REALM);
+               if (!namepair) {
+                       return (RLM_MODULE_NOOP);
+               }
+               keyname = namepair->vp_strvalue;
+       } else {
+               int len;
+
+               len = radius_xlat(buffer, sizeof(buffer), inst->key,
+                                 request, NULL);
+               if (!len) {
+                       return RLM_MODULE_NOOP;
+               }
+               keyname = buffer;
        }
-       realmname = realmpair->vp_strvalue;
 
        output_tail = &output;
 
        /*
-        *      Find the attr_filter profile entry for the realm.
+        *      Find the attr_filter profile entry for the entry.
         */
        for (pl = inst->attrs; pl; pl = pl->next) {
                int fall_through = 0;
@@ -228,7 +239,7 @@ static int attr_filter_common(void *instance, REQUEST *request,
                 *  then skip to the next entry.
                 */
                if ((strcmp(pl->name, "DEFAULT") != 0) &&
-                   (strcmp(realmname, pl->name) != 0))  {
+                   (strcmp(keyname, pl->name) != 0))  {
                    continue;
                }
 
@@ -276,6 +287,18 @@ static int attr_filter_common(void *instance, REQUEST *request,
                        for (check_item = pl->check;
                             check_item != NULL;
                             check_item = check_item->next) {
+                               /*
+                                *      Vendor-Specific is special, and
+                                *      matches any VSA if the comparison
+                                *      is always true.
+                                */
+                               if ((check_item->attribute == PW_VENDOR_SPECIFIC) &&
+                                   (VENDOR(vp->attribute) != 0) &&
+                                   (check_item->operator == T_OP_CMP_TRUE)) {
+                                       pass++;
+                                       continue;
+                               }
+
                                if (vp->attribute == check_item->attribute) {
                                        check_pair(check_item, vp,
                                                   &pass, &fail);