Call modules iteratively, rather than recursively.
authoraland <aland>
Mon, 12 Jun 2006 23:56:24 +0000 (23:56 +0000)
committeraland <aland>
Mon, 12 Jun 2006 23:56:24 +0000 (23:56 +0000)
This cleans up duplicate code that was in modcall.c, and means
that it's more likely we can put proxy into a module in the
authenticate section, in order to have it part of configurable
failover.

It also means that the "proxy EAP-MSCHAPv2 as MS-CHAPv2" and related
work will become easier, as we don't have to walk back up the entire
stack.  Instead, we can just keep the "modcall stack" associated
with the request, and continue where we left off.

src/include/modcall.h
src/main/modcall.c
src/main/modules.c

index c737cae..daf63a8 100644 (file)
@@ -17,14 +17,15 @@ int modcall(int component, modcallable *c, REQUEST *request);
 
 /* Parse a module-method's config section (e.g. authorize{}) into a tree that
  * may be called with modcall() */
-modcallable *compile_modgroup(int component, CONF_SECTION *cs,
-               const char *filename);
+modcallable *compile_modgroup(modcallable *parent,
+                             int component, CONF_SECTION *cs,
+                             const char *filename);
 
 /* Create a single modcallable node that references a module instance. This
  * may be a CONF_SECTION containing action specifiers like "notfound = return"
  * or a simple CONF_PAIR, in which case the default actions are used. */
-modcallable *compile_modsingle(int component, CONF_ITEM *ci,
-               const char *filename, const char **modname);
+modcallable *compile_modsingle(modcallable *parent, int component, CONF_ITEM *ci,
+                              const char *filename, const char **modname);
 
 /* Add an entry to the end of a modgroup, creating it first if necessary */
 void add_to_modcallable(modcallable **parent, modcallable *this,
index f0373d2..b58afe4 100644 (file)
@@ -32,7 +32,8 @@
 #include <freeradius-devel/modcall.h>
 
 /* mutually-recursive static functions need a prototype up front */
-static modcallable *do_compile_modgroup(int, CONF_SECTION *, const char *,
+static modcallable *do_compile_modgroup(modcallable *,
+                                       int, CONF_SECTION *, const char *,
                                        int, int);
 
 /* Actions may be a positive integer (the highest one returned in the group
@@ -46,6 +47,7 @@ static modcallable *do_compile_modgroup(int, CONF_SECTION *, const char *,
 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
  * explanation of what they are all about, see ../../doc/README.failover */
 struct modcallable {
+       modcallable *parent;
        struct modcallable *next;
        const char *name;
        int actions[RLM_MODULE_NUMCODES];
@@ -58,7 +60,7 @@ struct modcallable {
 #define GROUPTYPE_COUNT                3
 
 typedef struct {
-       modcallable mc;
+       modcallable mc;         /* self */
        int grouptype;  /* after mc */
        modcallable *children;
 } modgroup;
@@ -115,6 +117,7 @@ static void add_child(modgroup *g, modcallable *c)
 
        rad_assert(c->next == NULL);
        *last = c;
+       c->parent = mod_grouptocallable(g);
 }
 
 /* Here's where we recognize all of our keywords: first the rcodes, then the
@@ -264,347 +267,268 @@ static int call_modsingle(int component, modsingle *sp, REQUEST *request,
 }
 
 
+static int default_component_results[RLM_COMPONENT_COUNT] = {
+       RLM_MODULE_REJECT,      /* AUTH */
+       RLM_MODULE_NOTFOUND,    /* AUTZ */
+       RLM_MODULE_NOOP,        /* PREACCT */
+       RLM_MODULE_NOOP,        /* ACCT */
+       RLM_MODULE_FAIL,        /* SESS */
+       RLM_MODULE_NOOP,        /* PRE_PROXY */
+       RLM_MODULE_NOOP,        /* POST_PROXY */
+       RLM_MODULE_NOOP         /* POST_AUTH */
+};
+
+static const char *group_name[] = {
+       "",
+       "group",
+       "load-balance group",
+       "redundant-load-balance group"
+};
+
+#define MODCALL_STACK_MAX (8)
+
 /*
- *     Helper function for call_modgroup, and call_modredundantloadbalance
- *
- *     Returns 0 for "stop", and "1" for continue.
+ *     Don't call the modules recursively.  Instead, do them
+ *     iteratively, and manage the call stack ourselves.
  */
-static int call_one(int component, modcallable *p, REQUEST *request,
-                   int *priority, int *result)
-{
-       int r;
+typedef struct modcall_stack {
+       int pointer;
 
-       /*
-        *      A module has taken too long to process the request,
-        *      and we've been told to stop processing it.
-        */
-       if (request->options & RAD_REQUEST_OPTION_STOP_NOW) {
-               *result = RLM_MODULE_FAIL;
-               return 0;
-       }
-       
-       /* Call this child by recursing into modcall */
-       r = modcall(component, p, request);
-       
-#if 0
-       DEBUG2("%s: action for %s is %s",
-              comp2str[component], lrad_int2str(rcode_table, r, "??"),
-              action2str(p->actions[r]));
-#endif
-       
-       /*
-        *      Find an action to go with the child's result. If it is
-        *      "return", break out of the loop so the rest of the
-        *      children in the list will be skipped.
-        */
-       if (p->actions[r] == MOD_ACTION_RETURN) {
-               *result = r;
-               return 0;
-       }
-       
-       /* If "reject" break out of the loop and return reject */
-       if (p->actions[r] == MOD_ACTION_REJECT) {
-               *result = RLM_MODULE_REJECT;
-               return 0;
-       }
-       
-       /*
-        *      Otherwise, the action is a number, the preference
-        *      level of this return code. If no higher preference has
-        *      been seen yet, remember this one
-        . */
-       if (p->actions[r] >= *priority) {
-               *result = r;
-               *priority = p->actions[r];
-       }
-       
-       return 1;
-}
+       int priority[MODCALL_STACK_MAX];
+       int result[MODCALL_STACK_MAX];
+       modcallable *children[MODCALL_STACK_MAX];
+       modcallable *start[MODCALL_STACK_MAX];
+} modcall_stack;
 
 
-static int call_modgroup(int component, modgroup *g, REQUEST *request,
-                        int default_result)
+int modcall(int component, modcallable *c, REQUEST *request)
 {
-       int myresult = default_result;
-       int priority = 0;       /* default result has lowest priority  */
-       modcallable *p;
+       int myresult;
+       modcall_stack stack;
+       modcallable *parent, *child;
 
-       /*
-        *      Catch people who have issues.
-        */
-       if (!g->children) {
-               DEBUG2("  WARNING! Asked to process empty group.  Returning %s.", lrad_int2str(rcode_table, myresult, "??"));
-               return default_result;
-       }
+       stack.pointer = 0;
 
-       /* Loop over the children */
-       for (p = g->children; p; p = p->next) {
-               if (!call_one(component, p, request, &priority, &myresult)) {
-                       break;
-               }
+       if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {
+               return RLM_MODULE_FAIL;
        }
 
-       return myresult;
-}
-
-static int call_modloadbalance(int component, modgroup *g, REQUEST *request,
-                              int default_result)
-{
-       int count = 1;
-       modcallable *p, *child = NULL;
-
-       /*
-        *      Catch people who have issues.
-        */
-       if (!g->children) {
-               DEBUG2("  WARNING! Asked to process empty load-balance group.  Returning %s.", lrad_int2str(rcode_table, default_result, "??"));
-               return default_result;
+       if (!c) {
+               return default_component_results[component];
        }
 
-       /*
-        *      Pick a random child.
-        */
-
-       /* Loop over the children */
-       for(p = g->children; p; p = p->next) {
-               if (!child) {
-                       child = p;
-                       count = 1;
-                       continue;
-               }
+       stack.priority[0] = 0;
+       stack.children[0] = c;
+       myresult = stack.result[0] = default_component_results[component];
 
+       while (1) {
                /*
-                *      Keep track of how many load balancing servers
-                *      we've gone through.
+                *      A module has taken too long to process the request,
+                *      and we've been told to stop processing it.
                 */
-               count++;
+               if (request->options & RAD_REQUEST_OPTION_STOP_NOW) {
+                       myresult = RLM_MODULE_FAIL;
+                       break;
+               }
+
+               child = stack.children[stack.pointer];
+               parent = child->parent;
 
                /*
-                *      See the "camel book" for why this works.
-                *
-                *      If (rand(0..n) < 1), pick the current realm.
-                *      We add a scale factor of 65536, to avoid
-                *      floating point.
+                *      Child is a group that has children of it's own.
                 */
-               if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
-                       child = p;
-               }
-       }
-       rad_assert(child != NULL);
-
-       /* Call the chosen child by recursing into modcall */
-       return modcall(component, child, request);
-}
+               if (child && (child->type != MOD_SINGLE)) {
+                       int count = 1;
+                       modcallable *p, *q;
+                       modgroup *g = mod_callabletogroup(child);
+                       
+                       stack.pointer++;
 
+                       /*
+                        *      Catastrophic error.  This SHOULD have
+                        *      been caught when we were reading in the
+                        *      conf files.
+                        *
+                        *      FIXME: Do so.
+                        */
+                       if (stack.pointer >= MODCALL_STACK_MAX) {
+                               radlog(L_ERR, "Internal sanity check failed: module stack is too deep");
+                               exit(1);
+                       }
 
-/*
- *     For more than 2 modules with redundancy + load balancing
- *     across all of them, layering the "redundant" and
- *     "load-balance" groups gets too complicated.  As a result, we
- *     implement a special function to do this.
- */
-static int call_modredundantloadbalance(int component, modgroup *g, REQUEST *request,
-                                       int default_result)
-{
-       int count = 1;
-       int myresult = default_result;
-       int priority = 0;       /* default result has lowest priority  */
-       modcallable *p, *child = NULL;
+                       stack.priority[stack.pointer] = 0;
+                       stack.result[stack.pointer] = default_component_results[component];
+                       switch (child->type) {
+                       case MOD_GROUP:
+                               stack.children[stack.pointer] = g->children;
+                               break;
+                               
+                               /*
+                                *      See the "camel book" for why
+                                *      this works.
+                                *
+                                *      If (rand(0..n) < 1), pick the
+                                *      current realm.  We add a scale
+                                *      factor of 65536, to avoid
+                                *      floating point.
+                                */
+                       case MOD_LOAD_BALANCE:
+                       case MOD_REDUNDANT_LOAD_BALANCE:
+                               q = NULL;
+                               for(p = g->children; p; p = p->next) {
+                                       if (!q) {
+                                               q = p;
+                                               count = 1;
+                                               continue;
+                                       }
+                                       
+                                       count++;
+                                       
+                                       if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
+                                               q = p;
+                                       }
+                               }
+                               stack.children[stack.pointer] = q;
+                               break;
+                               
+                       default:
+                               exit(1); /* internal sanity check failure */
+                               break;
+                       }
+                       
+                       
+                       stack.start[stack.pointer] = stack.children[stack.pointer];
 
-       /*
-        *      Catch people who have issues.
-        */
-       if (!g->children) {
-               DEBUG2("  WARNING! Asked to process empty redundant-load-balance group.  Returning %s.", lrad_int2str(rcode_table, default_result, "??"));
-               return default_result;
-       }
+                       DEBUG2("modcall: entering %s %s for request %d",
+                              group_name[child->type],
+                              child->name, request->number);
 
-       /*
-        *      Pick a random child.
-        */
+                       /*
+                        *      Catch the special case of a NULL group.
+                        */
+                       if (!stack.children[stack.pointer]) {
+                               /*
+                                *      Print message for NULL group
+                                */
+                               DEBUG2("modcall[%s]: NULL object returns %s for request %d",
+                                      comp2str[component],
+                                      lrad_int2str(rcode_table,
+                                                   stack.result[stack.pointer],
+                                                   "??"),
+                                      request->number);
+                               goto do_exit;
+                       }
 
-       /* Loop over the children */
-       for(p = g->children; p; p = p->next) {
-               if (!child) {
-                       child = p;
-                       count = 1;
-                       continue;
+                       continue; /* child MAY be a group! */
                }
 
                /*
-                *      Keep track of how many load balancing servers
-                *      we've gone through.
+                *      Process a stand-alone child, and fall through
+                *      to dealing with it's parent.
                 */
-               count++;
+               if (child && (child->type == MOD_SINGLE)) {
+                       modsingle *sp = mod_callabletosingle(child);
 
-               /*
-                *      See the "camel book" for why this works.
-                *
-                *      If (rand(0..n) < 1), pick the current realm.
-                *      We add a scale factor of 65536, to avoid
-                *      floating point.
-                */
-               if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
-                       child = p;
+                       myresult = call_modsingle(component, sp, request,
+                                                 default_component_results[component]);
+                       stack.result[stack.pointer] = myresult;
                }
-       }
-       rad_assert(child != NULL);
 
-       /*
-        *      Call the chosen child, with fail-over to the next one
-        *      if it is down.
-        */
-       p = child;
-       do {
                /*
-                *      Call the chosen entry.  If we're done, then
-                *      stop.
+                *      We roll back up the stack at this point.
                 */
-               if (!call_one(component, p, request, &priority, &myresult)) {
-                       break;
-               }
-               
+       unroll:
                /*
-                *      Go to the next one, and wrap around to the beginning if
-                *      we reach the end.
+                *      No parent, we must be done.
                 */
-               p = p->next;
-               if (!p) p = g->children;
-       } while (p != child);
-
-       /*
-        *      And return whatever was decided.
-        */
-       return myresult;
-}
-
-int modcall(int component, modcallable *c, REQUEST *request)
-{
-       int myresult;
-
-       /*
-        *      A module has taken too long to process the request,
-        *      and we've been told to stop processing it.
-        */
-       if (request->options & RAD_REQUEST_OPTION_STOP_NOW) {
-               return RLM_MODULE_FAIL;
-       }
-
-       /* Choose a default return value appropriate for the component */
-       switch(component) {
-       case RLM_COMPONENT_AUTZ:
-               myresult = RLM_MODULE_NOTFOUND;
-               break;
-       case RLM_COMPONENT_AUTH:
-               myresult = RLM_MODULE_REJECT;
-               break;
-       case RLM_COMPONENT_PREACCT:
-               myresult = RLM_MODULE_NOOP;
-               break;
-       case RLM_COMPONENT_ACCT:
-               myresult = RLM_MODULE_NOOP;
-               break;
-       case RLM_COMPONENT_SESS:
-               myresult = RLM_MODULE_FAIL;
-               break;
-       case RLM_COMPONENT_PRE_PROXY:
-               myresult = RLM_MODULE_NOOP;
-               break;
-       case RLM_COMPONENT_POST_PROXY:
-               myresult = RLM_MODULE_NOOP;
-               break;
-       case RLM_COMPONENT_POST_AUTH:
-               myresult = RLM_MODULE_NOOP;
-               break;
-       default:
-               myresult = RLM_MODULE_FAIL;
-               break;
-       }
+               if (!parent) {
+                       rad_assert(stack.pointer == 0);
+                       myresult = stack.result[0];
+                       break;
+               }
 
-       if(c == NULL) {
-               DEBUG2("modcall[%s]: NULL object returns %s for request %d",
-                      comp2str[component],
-                      lrad_int2str(rcode_table, myresult, "??"),
-                      request->number);
-               return myresult;
-       }
+               rad_assert(child != NULL);
 
-       switch (c->type) {
-       case MOD_LOAD_BALANCE:
-               {
-                       modgroup *g = mod_callabletogroup(c);
-                       
-                       DEBUG2("modcall: entering load-balance group %s for request %d",
-                              c->name, request->number);
-                       
-                       myresult = call_modloadbalance(component, g, request,
-                                                      myresult);
-                       
-                       DEBUG2("modcall: load-balance group %s returns %s for request %d",
-                              c->name,
-                              lrad_int2str(rcode_table, myresult, "??"),
-                              request->number);
+               /*
+                *      Go to the "next" child, whatever that is.
+                */
+               switch (parent->type) {
+                       case MOD_GROUP:
+                               stack.children[stack.pointer] = child->next;
+                               break;
+
+                       case MOD_LOAD_BALANCE:
+                               stack.children[stack.pointer] = NULL;
+                               break;
+
+                       case MOD_REDUNDANT_LOAD_BALANCE:
+                               if (child->next) {
+                                       stack.children[stack.pointer] = child->next;
+                               } else {
+                                       modgroup *g = mod_callabletogroup(parent);
+                                       
+                                       stack.children[stack.pointer] = g->children;
+                               }
+                               if (stack.children[stack.pointer] == stack.start[stack.pointer]) {
+                                       stack.children[stack.pointer] = NULL;
+                               }
+                               break;
+                       default:        
+                               exit(1);
                }
-               break;
-               
-       case MOD_REDUNDANT_LOAD_BALANCE:
-               {
-                       modgroup *g = mod_callabletogroup(c);
-                       
-                       DEBUG2("modcall: entering redundant-load-balance group %s for request %d",
-                              c->name, request->number);
-                       
-                       myresult = call_modredundantloadbalance(component, g, request,
-                                                               myresult);
-                       
-                       DEBUG2("modcall: redundant-load-balance group %s returns %s for request %d",
-                              c->name,
-                              lrad_int2str(rcode_table, myresult, "??"),
-                              request->number);
+
+               /*
+                *      The child's action says return.  Do so.
+                */
+               if (child->actions[myresult] == MOD_ACTION_RETURN) {
+                       stack.children[stack.pointer] = NULL;
                }
-               break;
-               
-       case MOD_GROUP:
-               {
-                       modgroup *g = mod_callabletogroup(c);
-                       
-                       DEBUG2("modcall: entering group %s%s for request %d",
-                              lrad_int2str(grouptype_table, g->grouptype, ""),
-                              c->name, request->number);
-                       
-                       myresult = call_modgroup(component, g, request,
-                                                myresult);
-                       
-                       DEBUG2("modcall: leaving group %s%s (returns %s) for request %d",
-                              lrad_int2str(grouptype_table, g->grouptype, ""),
-                              c->name,
-                              lrad_int2str(rcode_table, myresult, "??"),
-                              request->number);
+       
+               /* If "reject", break out of the loop and return reject */
+               if (child->actions[myresult] == MOD_ACTION_REJECT) {
+                       stack.children[stack.pointer] = NULL;
+                       stack.result[stack.pointer] = RLM_MODULE_REJECT;
                }
-               break;
-               
-       case MOD_SINGLE:
-               {
-                       modsingle *sp = mod_callabletosingle(c);
-                       
-                       myresult = call_modsingle(component, sp, request,
-                                                 myresult);
-                       
-                       DEBUG2("  modcall[%s]: module \"%s\" returns %s for request %d",
-                              comp2str[component], c->name,
+
+               /*
+                *      No child, we're done this group.
+                */
+               if (!stack.children[stack.pointer]) {
+               do_exit:
+                       rad_assert(stack.pointer > 0);
+                       myresult = stack.result[stack.pointer];
+                       stack.pointer--;
+
+                       DEBUG2("modcall: %s %s returns %s for request %d",
+                              group_name[parent->type], parent->name,
                               lrad_int2str(rcode_table, myresult, "??"),
                               request->number);
+
+                       if (stack.pointer == 0) break;
+
+                       /*
+                        *      Unroll the stack.
+                        */
+                       child = stack.children[stack.pointer];
+                       parent = child->parent;
+                       goto unroll;
                }
-               break;
 
-       default:
-               radlog(L_ERR, "Internal error processing module entry");
-               break;
-       }
+               /*
+                *      Otherwise, the action is a number, the
+                *      preference level of this return code. If no
+                *      higher preference has been seen yet, remember
+                *      this one . */
+               if (child->actions[myresult] >= stack.priority[stack.pointer]) {
+                       stack.result[stack.pointer] = myresult;
+                       stack.priority[stack.pointer] = child->actions[myresult];
+               }
+       } /* loop until done */
 
        return myresult;
 }
 
+
 #if 0
 /* If you suspect a bug in the parser, you'll want to use these dump
  * functions. dump_tree should reproduce a whole tree exactly as it was found
@@ -970,7 +894,8 @@ defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
 /*
  *     Compile one entry of a module call.
  */
-static modcallable *do_compile_modsingle(int component, CONF_ITEM *ci,
+static modcallable *do_compile_modsingle(modcallable *parent,
+                                        int component, CONF_ITEM *ci,
                                         const char *filename, int grouptype,
                                         const char **modname)
 {
@@ -996,27 +921,37 @@ static modcallable *do_compile_modsingle(int component, CONF_ITEM *ci,
                 */
                if (strcmp(modrefname, "group") == 0) {
                        *modname = name2;
-                       return do_compile_modgroup(component, cs, filename,
-                                       GROUPTYPE_SIMPLE, grouptype);
+                       return do_compile_modgroup(parent, component, cs,
+                                                  filename,
+                                                  GROUPTYPE_SIMPLE,
+                                                  grouptype);
                } else if (strcmp(modrefname, "redundant") == 0) {
                        *modname = name2;
-                       return do_compile_modgroup(component, cs, filename,
-                                       GROUPTYPE_REDUNDANT, grouptype);
+                       return do_compile_modgroup(parent, component, cs,
+                                                  filename,
+                                                  GROUPTYPE_REDUNDANT,
+                                                  grouptype);
                } else if (strcmp(modrefname, "append") == 0) {
                        *modname = name2;
-                       return do_compile_modgroup(component, cs, filename,
-                                       GROUPTYPE_APPEND, grouptype);
+                       return do_compile_modgroup(parent, component, cs,
+                                                  filename,
+                                                  GROUPTYPE_APPEND,
+                                                  grouptype);
                } else if (strcmp(modrefname, "load-balance") == 0) {
                        *modname = name2;
-                       csingle= do_compile_modgroup(component, cs, filename,
-                                       GROUPTYPE_SIMPLE, grouptype);
+                       csingle= do_compile_modgroup(parent, component, cs,
+                                                    filename,
+                                                    GROUPTYPE_SIMPLE,
+                                                    grouptype);
                        if (!csingle) return NULL;
                        csingle->type = MOD_LOAD_BALANCE;
                        return csingle;
                } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
                        *modname = name2;
-                       csingle= do_compile_modgroup(component, cs, filename,
-                                       GROUPTYPE_REDUNDANT, grouptype);
+                       csingle= do_compile_modgroup(parent, component, cs,
+                                                    filename,
+                                                    GROUPTYPE_REDUNDANT,
+                                                    grouptype);
                        if (!csingle) return NULL;
                        csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
                        return csingle;
@@ -1051,7 +986,8 @@ static modcallable *do_compile_modsingle(int component, CONF_ITEM *ci,
                                 *      virtual module takes a section which
                                 *      contains the 
                                 */
-                               return do_compile_modsingle(component,
+                               return do_compile_modsingle(parent,
+                                                           component,
                                                            cf_sectiontoitem(subcs),
                                                            filename,
                                                            grouptype,
@@ -1071,7 +1007,9 @@ static modcallable *do_compile_modsingle(int component, CONF_ITEM *ci,
         *      them in.
         */
        single = rad_malloc(sizeof(*single));
+       memset(single, 0, sizeof(*single));
        csingle = mod_singletocallable(single);
+       csingle->parent = parent;
        csingle->next = NULL;
        memcpy(csingle->actions, defaultactions[component][grouptype],
               sizeof csingle->actions);
@@ -1134,10 +1072,12 @@ static modcallable *do_compile_modsingle(int component, CONF_ITEM *ci,
        return csingle;
 }
 
-modcallable *compile_modsingle(int component, CONF_ITEM *ci,
+modcallable *compile_modsingle(modcallable *parent,
+                              int component, CONF_ITEM *ci,
                               const char *filename, const char **modname)
 {
-       modcallable *ret = do_compile_modsingle(component, ci, filename,
+       modcallable *ret = do_compile_modsingle(parent, component, ci,
+                                               filename,
                                                GROUPTYPE_SIMPLE,
                                                modname);
        dump_tree(component, ret);
@@ -1148,7 +1088,8 @@ modcallable *compile_modsingle(int component, CONF_ITEM *ci,
 /*
  *     Internal compile group code.
  */
-static modcallable *do_compile_modgroup(int component, CONF_SECTION *cs,
+static modcallable *do_compile_modgroup(modcallable *parent,
+                                       int component, CONF_SECTION *cs,
                                        const char *filename, int grouptype,
                                        int parentgrouptype)
 {
@@ -1158,9 +1099,11 @@ static modcallable *do_compile_modgroup(int component, CONF_SECTION *cs,
        CONF_ITEM *ci;
 
        g = rad_malloc(sizeof(*g));
+       memset(g, 0, sizeof(*g));
        g->grouptype = grouptype;
 
        c = mod_grouptocallable(g);
+       c->parent = parent;
        c->next = NULL;
        memset(c->actions, 0, sizeof(c->actions));
 
@@ -1194,7 +1137,8 @@ static modcallable *do_compile_modgroup(int component, CONF_SECTION *cs,
 
                        lineno = cf_section_lineno(subcs);
 
-                       single = do_compile_modsingle(component, ci, filename,
+                       single = do_compile_modsingle(c, component, ci,
+                                                     filename,
                                                      grouptype, &junk);
                        if (!single) {
                                radlog(L_ERR|L_CONS,
@@ -1224,9 +1168,12 @@ static modcallable *do_compile_modgroup(int component, CONF_SECTION *cs,
                                modcallable *single;
                                const char *junk = NULL;
 
-                               single = do_compile_modsingle(component,
-                                               cf_pairtoitem(cp), filename,
-                                               grouptype, &junk);
+                               single = do_compile_modsingle(c,
+                                                             component,
+                                                             cf_pairtoitem(cp),
+                                                             filename,
+                                                             grouptype,
+                                                             &junk);
                                if (!single) {
                                        radlog(L_ERR|L_CONS,
                                               "%s[%d] Failed to parse \"%s\" entry.\n",
@@ -1263,10 +1210,11 @@ static modcallable *do_compile_modgroup(int component, CONF_SECTION *cs,
        return mod_grouptocallable(g);
 }
 
-modcallable *compile_modgroup(int component, CONF_SECTION *cs,
+modcallable *compile_modgroup(modcallable *parent,
+                             int component, CONF_SECTION *cs,
                              const char *filename)
 {
-       modcallable *ret = do_compile_modgroup(component, cs, filename,
+       modcallable *ret = do_compile_modgroup(parent, component, cs, filename,
                                               GROUPTYPE_SIMPLE,
                                               GROUPTYPE_SIMPLE);
        dump_tree(component, ret);
@@ -1284,6 +1232,7 @@ void add_to_modcallable(modcallable **parent, modcallable *this,
                modcallable *c;
 
                g = rad_malloc(sizeof *g);
+               memset(g, 0, sizeof(*g));
                g->grouptype = GROUPTYPE_SIMPLE;
                c = mod_grouptocallable(g);
                c->next = NULL;
index 285844e..4134e37 100644 (file)
@@ -409,18 +409,7 @@ static int indexed_modcall(int comp, int idx, REQUEST *request)
        if (!this) {
                if (idx != 0) DEBUG2("  ERROR: Unknown value specified for %s.  Cannot perform requested action.",
                                     section_type_value[comp].typename);
-               /* Return a default value appropriate for the component */
-               switch(comp) {
-                       case RLM_COMPONENT_AUTZ:    return RLM_MODULE_NOTFOUND;
-                       case RLM_COMPONENT_AUTH:    return RLM_MODULE_REJECT;
-                       case RLM_COMPONENT_PREACCT: return RLM_MODULE_NOOP;
-                       case RLM_COMPONENT_ACCT:    return RLM_MODULE_NOOP;
-                       case RLM_COMPONENT_SESS:    return RLM_MODULE_FAIL;
-                       case RLM_COMPONENT_PRE_PROXY:  return RLM_MODULE_NOOP;
-                       case RLM_COMPONENT_POST_PROXY: return RLM_MODULE_NOOP;
-                       case RLM_COMPONENT_POST_AUTH:  return RLM_MODULE_NOOP;
-                       default:                    return RLM_MODULE_FAIL;
-               }
+               return modcall(comp, NULL, request); /* does default action */
        }
 
        DEBUG2("  Processing the %s section of %s",
@@ -432,7 +421,8 @@ static int indexed_modcall(int comp, int idx, REQUEST *request)
  *     Load a sub-module list, as found inside an Auth-Type foo {}
  *     block
  */
-static int load_subcomponent_section(CONF_SECTION *cs, int comp,
+static int load_subcomponent_section(modcallable *parent,
+                                    CONF_SECTION *cs, int comp,
                                     const char *filename)
 {
        indexed_modcallable *subcomp;
@@ -457,7 +447,7 @@ static int load_subcomponent_section(CONF_SECTION *cs, int comp,
        /*
         *      Compile the group.
         */
-       ml = compile_modgroup(comp, cs, filename);
+       ml = compile_modgroup(parent, comp, cs, filename);
        if (!ml) {
                return 0;
        }       
@@ -492,7 +482,8 @@ static int load_subcomponent_section(CONF_SECTION *cs, int comp,
        return 1;               /* OK */
 }
 
-static int load_component_section(CONF_SECTION *cs, int comp,
+static int load_component_section(modcallable *parent,
+                                 CONF_SECTION *cs, int comp,
                                  const char *filename)
 {
        modcallable *this;
@@ -527,7 +518,8 @@ static int load_component_section(CONF_SECTION *cs, int comp,
 
                        if (strcmp(sec_name,
                                   section_type_value[comp].typename) == 0) {
-                               if (!load_subcomponent_section(scs, comp,
+                               if (!load_subcomponent_section(parent, scs,
+                                                              comp,
                                                               filename)) {
                                        return -1; /* FIXME: memleak? */
                                }
@@ -539,7 +531,8 @@ static int load_component_section(CONF_SECTION *cs, int comp,
                         */
                        if (strcmp(sec_name,
                                   old_section_type_value[comp].typename) == 0) {
-                               if (!load_subcomponent_section(scs, comp,
+                               if (!load_subcomponent_section(parent, scs,
+                                                              comp,
                                                               filename)) {
                                        return -1; /* FIXME: memleak? */
                                }
@@ -553,7 +546,8 @@ static int load_component_section(CONF_SECTION *cs, int comp,
                /*
                 *      Try to compile one entry.
                 */
-               this = compile_modsingle(comp, modref, filename, &modname);
+               this = compile_modsingle(parent, comp, modref, filename,
+                                        &modname);
                if (!this) {
                        radlog(L_ERR|L_CONS,
                               "%s[%d] Failed to parse %s section.\n",
@@ -919,7 +913,7 @@ int setup_modules(int reload)
                        continue;
                }
 
-               if (load_component_section(cs, comp, mainconfig.radiusd_conf) < 0) {
+               if (load_component_section(NULL, cs, comp, mainconfig.radiusd_conf) < 0) {
                        return -1;
                }
        }