Port fix for #945 from v3.0.x branch
[freeradius.git] / src / main / modcall.c
index 2bdce8c..f2e15ee 100644 (file)
@@ -290,8 +290,8 @@ static int call_modsingle(int component, modsingle *sp, REQUEST *request)
               comp2str[component], sp->modinst->name,
               sp->modinst->entry->name, request->number);
 
-       if (sp->modinst->dead) {
-               myresult = RLM_MODULE_FAIL;
+       if (sp->modinst->force) {
+               myresult = sp->modinst->code;
                goto fail;
        }
 
@@ -396,14 +396,14 @@ typedef struct modcall_stack_entry_t {
 
 
 static int modcall_recurse(REQUEST *request, int component, int depth,
-                           modcall_stack_entry_t *entry);
+                          modcall_stack_entry_t *entry, int do_next_sibling);
 
 /*
  *     Call a child of a block.
  */
 static void modcall_child(REQUEST *request, int component, int depth,
                          modcall_stack_entry_t *entry, modcallable *c,
-                         int *result, int *priority)
+                         int *result, int do_next_sibling)
 {
        modcall_stack_entry_t *next;
 
@@ -421,13 +421,12 @@ static void modcall_child(REQUEST *request, int component, int depth,
        next->priority = 0;
 
        if (!modcall_recurse(request, component,
-                            depth, next)) {
+                            depth, next, do_next_sibling)) {
                *result = RLM_MODULE_FAIL;
                 return;
        }
 
        *result = next->result;
-       *priority = next->priority;
 
        return;
 }
@@ -436,7 +435,7 @@ static void modcall_child(REQUEST *request, int component, int depth,
  *     Interpret the various types of blocks.
  */
 static int modcall_recurse(REQUEST *request, int component, int depth,
-                           modcall_stack_entry_t *entry)
+                          modcall_stack_entry_t *entry, int do_next_sibling)
 {
        int if_taken, was_if;
        modcallable *c;
@@ -481,7 +480,7 @@ redo:
                RDEBUG2("%.*s? %s %s", depth + 1, modcall_spaces,
                        group_name[c->type], c->name);
 
-               if (radius_evaluate_condition(request, entry->result,
+               if (radius_evaluate_condition(request, result,
                                              0, &p, TRUE, &condition)) {
                        RDEBUG2("%.*s? %s %s -> %s", depth + 1, modcall_spaces,
                                group_name[c->type],
@@ -595,13 +594,11 @@ redo:
                                               g->vps, c->name);
                if (rcode != RLM_MODULE_UPDATED) {
                        result = rcode;
-                       MOD_LOG_CLOSE_BRACE();
-                       goto calculate_result;
+               } else {
+                       result = RLM_MODULE_NOOP;
                }
-
-               result = RLM_MODULE_NOOP;
                MOD_LOG_CLOSE_BRACE();
-               goto next_sibling;
+               goto calculate_result;
        } /* MOD_IF */
 
        /*
@@ -614,10 +611,23 @@ redo:
        do_children:
                g = mod_callabletogroup(c);
 
+               /*
+                *      This should really have been caught in the
+                *      compiler, and the node never generated.  But
+                *      doing that requires changing it's API so that
+                *      it returns a flag instead of the compiled
+                *      MOD_GROUP.
+                */
+               if (!g->children) {
+                       RDEBUG2("%.*s%s %s { ... } # empty sub-section is ignored",
+                               depth + 1, modcall_spaces, group_name[c->type], c->name);
+                       goto next_sibling;
+               }
+
                MOD_LOG_OPEN_BRACE(group_name[c->type]);
                modcall_child(request, component,
                              depth + 1, entry, g->children,
-                             &result, &priority);
+                             &result, TRUE);
                MOD_LOG_CLOSE_BRACE();
                goto calculate_result;
        } /* MOD_GROUP */
@@ -636,8 +646,7 @@ redo:
                if (!strchr(c->name, '%')) {
                        VALUE_PAIR *vp = NULL;
 
-                       radius_get_vp(request, c->name, &vp);
-                       if (vp) {
+                       if (radius_get_vp(request, c->name, &vp) && vp) {
                                vp_prints_value(buffer,
                                                sizeof(buffer),
                                                vp, 0);
@@ -671,14 +680,14 @@ redo:
                MOD_LOG_OPEN_BRACE(group_name[c->type]);
                modcall_child(request, component,
                              depth + 1, entry, found,
-                             &result, &priority);
+                             &result, TRUE);
                MOD_LOG_CLOSE_BRACE();
                goto calculate_result;
        } /* MOD_SWITCH */
 
        if ((c->type == MOD_LOAD_BALANCE) ||
            (c->type == MOD_REDUNDANT_LOAD_BALANCE)) {
-               int count;
+               int count = 0;
                modcallable *this, *found;
                modgroup *g;
 
@@ -704,25 +713,23 @@ redo:
                if (c->type == MOD_LOAD_BALANCE) {
                        modcall_child(request, component,
                                      depth + 1, entry, found,
-                                     &result, &priority);
+                                     &result, FALSE);
                                               
                } else {
-                       int i;
+                       this = found;
 
-                       /*
-                        *      Loop over all children in this
-                        *      section.  If we get FAIL, then
-                        *      continue.  Otherwise, stop.
-                        */
-                       for (i = 1; i < count; i++) {
+                       do {
                                modcall_child(request, component,
                                              depth + 1, entry, found,
-                                             &result, &priority);
-                               if (c->actions[result] == MOD_ACTION_RETURN) {
+                                             &result, FALSE);
+                               if (found->actions[result] == MOD_ACTION_RETURN) {
                                        priority = -1;
                                        break;
                                }
-                       }
+
+                               this = this->next;
+                               if (!this) this = g->children;
+                       } while (this != found);
                }
                MOD_LOG_CLOSE_BRACE();
                goto calculate_result;
@@ -768,6 +775,7 @@ redo:
                        RDEBUG("`%s`", mx->xlat_name);
                                radius_exec_program(mx->xlat_name, request,
                                                    0, NULL, 0,
+                                                   EXEC_TIMEOUT,
                                                    request->packet->vps,
                                                    NULL, 1);
                }
@@ -780,6 +788,14 @@ redo:
         */
 
 calculate_result:
+#if 0
+       RDEBUG("(%s, %d) ? (%s, %d)",
+              fr_int2str(mod_rcode_table, result, "<invalid>"),
+              priority,
+              fr_int2str(mod_rcode_table, entry->result, "<invalid>"),
+              entry->priority);
+#endif
+
        /*
         *      The child's action says return.  Do so.
         */
@@ -802,7 +818,9 @@ calculate_result:
         *      The array holds a default priority for this return
         *      code.  Grab it in preference to any unset priority.
         */
-       if (priority < 0) priority = c->actions[result];
+       if (priority < 0) {
+               priority = c->actions[result];
+       }
 
        /*
         *      We're higher than any previous priority, remember this
@@ -820,9 +838,11 @@ calculate_result:
        if (c->type == MOD_CASE) return TRUE;
 
 next_sibling:
-       entry->c = entry->c->next;
+       if (do_next_sibling) {
+               entry->c = entry->c->next;
 
-       if (entry->c) goto redo;
+               if (entry->c) goto redo;
+       }
 
        /*
         *      And we're done!
@@ -853,7 +873,7 @@ int modcall(int component, modcallable *c, REQUEST *request)
        /*
         *      Call the main handler.
         */
-       if (!modcall_recurse(request, component, 0, &stack[0])) {
+       if (!modcall_recurse(request, component, 0, &stack[0], TRUE)) {
                return RLM_MODULE_FAIL;
        }
 
@@ -1443,7 +1463,7 @@ static modcallable *do_compile_modupdate(modcallable *parent,
        
        memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
               sizeof(csingle->actions));
-
+       
        g->grouptype = GROUPTYPE_SIMPLE;
        g->children = NULL;
        g->cs = cs;