At 08:06 AM 8/11/2003, you wrote:
On Fri, 2003-08-08 at 15:48, Alan DeKok wrote:
> Chris van Meerendonk <[EMAIL PROTECTED]> wrote:
> > Is it possible to filter attributes that are sent by using radius proxy
> > to the home-server? Something like attr_filter in the pre-proxy stage?
>
>   If attr_filter doesn't already have a pre-proxy stage, it should be
> ~2 minutes to add one.
I'm doing something terribly wrong. Can you help me out? I've copied the
attr_filter_authorize routine and renamed it to attr_filter_preproxy.
Debug shows it is passing the routine. Also I put in some extra DEBUG2
lines to verify. It finds the correct realm, compares the entries
against the entries in the users file instead of the data comming from
the NAS. Probably as a result of this, the data is passed whatever the
results of the check are.

Can you give me a hint what I'm doing wrong? (Your 2-minute patch would
be great also ;-)

I sent the post-proxy patch...you probably hadn't received it by the time you sent this.


I included a patch this time with the post-proxy() and accounting() functions. Pay attention to the accounting function as it will mirror what you are trying to do (unlike authorize()). rlm_attr_filter was not really made to work on the VPS coming back from the NAS (it was intended to work on VPS going to the NAS), so copying the authorize() function is not going to do what you wanted.

The module will work on whichever pairs you tell it to. So, for example, you probably have reply_items = &request->reply->vps. The attributes from the NAS are not in request->reply->vps, but the attributes added from rlm_files or rlm_fastusers are.

If you are trying to modify the NAS VPs, then you need to work with the request->packet->vps. So I go through a loop,

for (send_item = request_pairs...) {
    ....
    while (check) {
        ....
    }
    if (fail ==0 && pass > 0) {
        mypairappend(send_item, &send_tmp);
    }
}
pairfree(&request->packet->vps);
request->packet->vps = send_tmp;

HTH,

Chris Brotsos

Thanks,

Chris

> Alan DeKok.
>
> -
> List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
>




-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
Index: rlm_attr_filter.c
===================================================================
RCS file: /source/radiusd/src/modules/rlm_attr_filter/rlm_attr_filter.c,v
retrieving revision 1.13
diff -u -r1.13 rlm_attr_filter.c
--- rlm_attr_filter.c   7 Jul 2003 19:04:05 -0000       1.13
+++ rlm_attr_filter.c   11 Aug 2003 13:21:51 -0000
@@ -3,7 +3,7 @@
  *                      before sending reply to the NAS/Server that sent
  *                      it to us.
  *
- * Version:      $Id: rlm_attr_filter.c,v 1.13 2003/07/07 19:04:05 aland Exp $
+ * Version:      $Id: rlm_attr_filter.c,v 1.12 2002/08/24 16:54:56 aland Exp $
  *
  *   This program is is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License, version 2 if the
@@ -41,7 +41,7 @@
 #include       "radiusd.h"
 #include       "modules.h"
 
-static const char rcsid[] = "$Id: rlm_attr_filter.c,v 1.13 2003/07/07 19:04:05 aland 
Exp $";
+static const char rcsid[] = "$Id: rlm_attr_filter.c,v 1.12 2002/08/24 16:54:56 aland 
Exp $";
 
 struct attr_filter_instance {
 
@@ -152,10 +152,6 @@
        int rcode;
 
         inst = rad_malloc(sizeof *inst);
-       if (!inst) {
-               return -1;
-       }
-       memset(inst, 0, sizeof(*inst));
 
         if (cf_section_parse(conf, inst, module_config) < 0) {
                 free(inst);
@@ -173,7 +169,193 @@
         *instance = inst;
         return 0;
 }
+/*     Find the named realm in the database. Create the 
+ *     set of attribute-value pairs to check and forward with
+ *     for this realm from the database.
+ */
+static int attr_filter_accounting(void *instance, REQUEST *request)
+{
+       struct attr_filter_instance *inst = instance;
+       VALUE_PAIR      *request_pairs;
+       VALUE_PAIR      *send_item;
+       VALUE_PAIR      *send_tmp = NULL;
+       VALUE_PAIR      *check_item;
+       PAIR_LIST       *pl;
+       int             found = 0;
+       int             compare;
+       int             pass, fail;
+#ifdef HAVE_REGEX_H
+       regex_t         reg;
+#endif
+       VALUE_PAIR      *realmpair;
+       REALM           *realm;
+       char            *realmname;
+       /*
+        * Accounting is a bit different from the other functions.
+        * Here we are concerned with what we are going to forward to
+        * the remote server as opposed to concerns with what we will send
+        * to the NAS based on a proxy reply to an auth request.
+        */
+       request_pairs = request->packet->vps;
+       if (request->packet->code != PW_ACCOUNTING_REQUEST) {
+               return (RLM_MODULE_NOOP);
+       }
+       /* Get the realm from the original request vps. */
+       realmpair = pairfind(request_pairs, PW_REALM);
+       if (!realmpair) {
+               /* If there is no realm...NOOP */
+               return (RLM_MODULE_NOOP);
+       }
+       realmname = (char *) realmpair->strvalue;
+       realm = realm_find (realmname, FALSE);
+       /* Find the entry for this realm in inst->attrs */
+       for (pl = inst->attrs; pl; pl = pl->next) {
+               if ( (strcmp(pl->name, "DEFAULT") != 0) &&
+                    (strcasecmp(realmname, pl->name) != 0) ) {
+                       continue;
+               }
+               DEBUG2(" attr_filter: Matched entry %s at line %d", pl->name,
+                                                                   pl->lineno);
+               found = 1;
+               check_item = pl->check;
+               while (check_item != NULL) {
+                       /*
+                        * If it is a SET operator, add the attribute to
+                        * the send list w/out checking.
+                        */
+                       if (check_item->operator == T_OP_SET) {
+                           mypairappend(check_item, &send_tmp);
+                       }
+                       check_item = check_item->next;
+               }
+               /*
+                * Iterate through the request_pairs (items sent from NAS).
+                * Compare each pair to every rule for this realm/DEFAULT.
+                * Move an item to send_tmp if it matches all rules for
+                * attribute in question.
+                */
+               for (send_item = request_pairs;
+                    send_item != NULL;
+                    send_item = send_item->next ) {
+                   /* reset the pass/fail vars for each packet->vp. */
+                   pass = fail = 0;
+                   check_item = pl->check;
+                   /*
+                    * compare each packet->vp to the entire list of 
+                    * check_items for this realm.
+                    */
+                   while (check_item != NULL) {
+                       if (send_item->attribute == check_item->attribute) {
+                           compare = simplepaircmp(request, send_item,
+                                                   check_item);
+                           switch (check_item->operator) {
+                               case T_OP_SET: /* already handled */
+                                   break;
+                               case T_OP_EQ:
+                                    default:
+                                   radlog(L_ERR, "Invalid operator for %s: "
+                                          "reverting to '=='",
+                                          check_item->name);
+                               case T_OP_CMP_TRUE: /* compare always == 0 */
+                               case T_OP_CMP_FALSE: /* compare always == 1 */
+                               case T_OP_CMP_EQ:
+                                   if (compare == 0) {
+                                       pass++;
+                                   }
+                                   else {
+                                       fail++;
+                                   }
+                                   break;
+                               case T_OP_NE:
+                                   if (compare != 0) {
+                                       pass++;
+                                   }
+                                   else {
+                                       fail++;
+                                   }
+                                   break;
+                               case T_OP_LT:
+                                   if (compare < 0) {
+                                       pass++;
+                                   }
+                                   else {
+                                       fail++;
+                                   }
+                                   break;
+                               case T_OP_GT:
+                                   if (compare > 0) {
+                                       pass++;
+                                   }
+                                   else {
+                                       fail++;
+                                   }
+                                   break;
+                               case T_OP_LE:
+                                   if (compare <= 0) {
+                                       pass++;
+                                   }
+                                   else {
+                                       fail++;
+                                   }
+                                   break;
+                               case T_OP_GE:
+                                   if (compare >= 0) {
+                                       pass++;
+                                   }
+                                   else {
+                                       fail++;
+                                   }
+                                   break;
+#ifdef HAVE_REGEX_H
+                               case T_OP_REG_EQ:
+                                   regcomp(&reg, (char *)check_item->strvalue,
+                                                 0);
+                                   compare = regexec(&reg,
+                                                     (char *)send_item->strvalue,
+                                                     0, NULL, 0);
+                                   regfree(&reg);
+                                   if (compare == 0) {
+                                       pass++;
+                                   }
+                                   else {
+                                       fail++;
+                                   }
+                                   break;
+                               case T_OP_REG_NE:
+                                   regcomp(&reg, (char *)check_item->strvalue,
+                                                 0);
+                                   compare = regexec(&reg,
+                                                     (char *)send_item->strvalue,
+                                                     0, NULL, 0);
+                                   regfree(&reg);
+                                   if (compare != 0) {
+                                       pass++;
+                                   }
+                                   else {
+                                       fail++;
+                                   }
+                                   break;
+#endif
+                           } /* switch (check_item->operator) */
+                       } /* if (send == check) */
 
+                       check_item = check_item->next;
+                   } /* while (check) */
+                   /* only send if attribute passed all rules */
+                   if (fail == 0 && pass > 0) {
+                       mypairappend (send_item, &send_tmp);
+                   }
+               } /* for ( packet->vps) */
+               if (!fallthrough(pl->check))
+                   break;
+       }
+       pairfree (&request->packet->vps);
+       request->packet->vps = send_tmp;
+       if (!found)
+           return RLM_MODULE_OK;
+       pairdelete(&send_tmp, PW_FALL_THROUGH);
+       return RLM_MODULE_UPDATED;
+}
 /*
  *     Find the named realm in the database.  Create the
  *     set of attribute-value pairs to check and reply with
@@ -407,6 +589,238 @@
 }
 
 /*
+ *     Find the named realm in the database.  Create the
+ *     set of attribute-value pairs to check and reply with
+ *     for this realm from the database.
+ */
+static int attr_filter_postproxy(void *instance, REQUEST *request)
+{
+       struct attr_filter_instance *inst = instance;
+       VALUE_PAIR      *request_pairs;
+       VALUE_PAIR      **reply_items;
+       VALUE_PAIR      *reply_item;
+       VALUE_PAIR      *reply_tmp = NULL;
+       VALUE_PAIR      *check_item;
+       PAIR_LIST       *pl;
+       int             found = 0;
+       int             compare;
+       int             pass, fail;
+#ifdef HAVE_REGEX_H
+       regex_t         reg;
+#endif
+       VALUE_PAIR      *realmpair;
+        REALM           *realm;
+        char            *realmname;
+
+       /*
+        *      It's not a proxy reply, so return NOOP
+        */
+
+       if( request->proxy == NULL ) {
+               return( RLM_MODULE_NOOP );
+       }
+
+       request_pairs = request->packet->vps;
+       reply_items = &request->proxy_reply->vps;
+
+       /*
+        *      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_pairs, PW_REALM);
+       if(!realmpair) {
+               /*    Can't find a realm, so no filtering of attributes 
+                *    or should we use a DEFAULT entry?
+                *    For now, just return NOTFOUND. (maybe NOOP?)
+                */ 
+               return RLM_MODULE_NOTFOUND;
+       }
+
+       realmname = (char *) realmpair->strvalue;
+        realm = realm_find(realmname, FALSE);
+
+       /*
+        *      Find the attr_filter profile entry for the realm.
+        */
+       for(pl = inst->attrs; pl; pl = pl->next) {
+
+           /*
+            *  If the current entry is NOT a default,
+            *  AND the realm does NOT match the current entry,
+            *  then skip to the next entry.
+            */
+           if ( (strcmp(pl->name, "DEFAULT") != 0)
+                && (strcmp(realmname, pl->name) != 0) )  {
+                       continue;
+               }
+
+               DEBUG2("  attr_filter: Matched entry %s at line %d", pl->name, 
pl->lineno);
+
+               found = 1;
+               
+               check_item = pl->check;
+
+               while( check_item != NULL ) {
+
+                   /*
+                    *      If it is a SET operator, add the attribute to
+                    *      the reply list without checking reply_items.
+                    *
+                    */
+
+                   if( check_item->operator == T_OP_SET ) {
+                       mypairappend(check_item, &reply_tmp);
+                   }
+                   check_item = check_item->next;
+
+               }  /* while( check_item != NULL ) */
+
+               /* 
+                * Iterate through the reply items, comparing each reply item to every 
rule,
+                * then moving it to the reply_tmp list only if it matches all rules 
for that
+                * attribute.  IE, Idle-Timeout is moved only if it matches all rules 
that
+                * describe an Idle-Timeout.  
+                */
+
+               for( reply_item = *reply_items; 
+                    reply_item != NULL; 
+                    reply_item = reply_item->next ) {
+
+                 /* reset the pass,fail vars for each reply item */
+                 pass = fail = 0;
+
+                 /* reset the check_item pointer to the beginning of the list */
+                 check_item = pl->check;
+
+                 while( check_item != NULL ) {
+                     
+                     if(reply_item->attribute == check_item->attribute) {
+
+                       compare = simplepaircmp(request, reply_item, check_item);
+
+                       switch(check_item->operator) {
+
+                           case T_OP_SET:            /* nothing to do for set */
+                               break;
+                           case T_OP_EQ:
+                           default:
+                               radlog(L_ERR, "Invalid operator for item %s: "
+                                      "reverting to '=='", check_item->name);
+                               
+                           case T_OP_CMP_TRUE:       /* compare always == 0 */
+                           case T_OP_CMP_FALSE:      /* compare always == 1 */
+                           case T_OP_CMP_EQ:
+                               if (compare == 0) {
+                                   pass++;
+                               } else {
+                                   fail++;
+                               }
+                               break;
+
+                           case T_OP_NE:
+                               if (compare != 0) {
+                                   pass++;
+                               } else {
+                                   fail++;
+                               }
+                               break;
+
+                           case T_OP_LT:
+                               if (compare < 0) {
+                                   pass++;
+                               } else {
+                                   fail++;
+                               }
+                               break;
+
+                           case T_OP_GT:
+                               if (compare > 0) {
+                                   pass++;
+                               } else {
+                                   fail++;
+                               }
+                               break;
+                               
+                           case T_OP_LE:
+                               if (compare <= 0) {
+                                   pass++;
+                               } else {
+                                   fail++;
+                               }
+                               break;
+
+                           case T_OP_GE:
+                               if (compare >= 0) {
+                                   pass++;
+                               } else {
+                                   fail++;
+                               }
+                               break;
+#ifdef HAVE_REGEX_H
+                           case T_OP_REG_EQ:
+                               regcomp(&reg, (char *)check_item->strvalue, 0);
+                               compare = regexec(&reg, (char *)reply_item->strvalue,
+                                                 0, NULL, 0);
+                               regfree(&reg);
+                               if (compare == 0) {
+                                   pass++;
+                               } else {
+                                   fail++;
+                               }
+                               break;
+
+                           case T_OP_REG_NE:
+                               regcomp(&reg, (char *)check_item->strvalue, 0);
+                               compare = regexec(&reg, (char *)reply_item->strvalue,
+                                                 0, NULL, 0);
+                               regfree(&reg);
+                               if (compare != 0) {
+                                   pass++;
+                               } else {
+                                   fail++;
+                               }
+                               break;
+#endif
+                       }  /* switch( check_item->operator ) */
+
+                     }  /* if reply == check */
+
+                     check_item = check_item->next;
+
+                   }  /* while( check ) */
+
+                   /* only move attribute if it passed all rules */
+                   if (fail == 0 && pass > 0) {
+                     mypairappend( reply_item, &reply_tmp);
+                   }
+
+               }  /* for( reply ) */
+               
+               /* If we shouldn't fall through, break */
+               if(!fallthrough(pl->check))
+                   break;
+       }
+
+       pairfree(&request->proxy_reply->vps);
+       request->proxy_reply->vps = reply_tmp;
+       
+       /*
+        *      See if we succeeded.  If we didn't find the realm,
+        *      then exit from the module.
+        */
+       if (!found)
+               return RLM_MODULE_OK;
+
+       /*
+        *      Remove server internal parameters.
+        */
+       pairdelete(reply_items, PW_FALL_THROUGH);
+
+       return RLM_MODULE_UPDATED;
+}
+
+/*
  *     Clean up.
  */
 static int attr_filter_detach(void *instance)
@@ -429,10 +843,10 @@
                NULL,                   /* authentication */
                attr_filter_authorize,  /* authorization */
                NULL,                   /* preaccounting */
-               NULL,                   /* accounting */
+               attr_filter_accounting, /* accounting */
                NULL,                   /* checksimul */
                NULL,                   /* pre-proxy */
-               NULL,                   /* post-proxy */
+               attr_filter_postproxy,  /* post-proxy */
                NULL                    /* post-auth */
        },
        attr_filter_detach,             /* detach */

Reply via email to