6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2000,2006 The FreeRADIUS server project
23 #include <freeradius-devel/ident.h>
26 #include <freeradius-devel/autoconf.h>
30 #include <freeradius-devel/radiusd.h>
31 #include <freeradius-devel/rad_assert.h>
32 #include <freeradius-devel/modpriv.h>
33 #include <freeradius-devel/modcall.h>
35 /* mutually-recursive static functions need a prototype up front */
36 static modcallable *do_compile_modgroup(modcallable *,
37 int, CONF_SECTION *, const char *,
40 /* Actions may be a positive integer (the highest one returned in the group
41 * will be returned), or the keyword "return", represented here by
42 * MOD_ACTION_RETURN, to cause an immediate return.
43 * There's also the keyword "reject", represented here by MOD_ACTION_REJECT
44 * to cause an immediate reject. */
45 #define MOD_ACTION_RETURN (-1)
46 #define MOD_ACTION_REJECT (-2)
48 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
49 * explanation of what they are all about, see ../../doc/README.failover */
52 struct modcallable *next;
55 int actions[RLM_MODULE_NUMCODES];
56 enum { MOD_SINGLE, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE, MOD_IF, MOD_ELSE, MOD_ELSIF } type;
59 #define GROUPTYPE_SIMPLE 0
60 #define GROUPTYPE_REDUNDANT 1
61 #define GROUPTYPE_APPEND 2
62 #define GROUPTYPE_COUNT 3
65 modcallable mc; /* self */
66 int grouptype; /* after mc */
67 modcallable *children;
72 module_instance_t *modinst;
75 static const LRAD_NAME_NUMBER grouptype_table[] = {
76 { "", GROUPTYPE_SIMPLE },
77 { "redundant ", GROUPTYPE_REDUNDANT },
78 { "append ", GROUPTYPE_APPEND },
82 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
83 * so we often want to go back and forth between them. */
84 static modsingle *mod_callabletosingle(modcallable *p)
86 rad_assert(p->type==MOD_SINGLE);
87 return (modsingle *)p;
89 static modgroup *mod_callabletogroup(modcallable *p)
91 rad_assert((p->type==MOD_GROUP) || /* this is getting silly... */
92 (p->type==MOD_LOAD_BALANCE) ||
94 (p->type==MOD_ELSE) ||
95 (p->type==MOD_ELSIF) ||
96 (p->type==MOD_REDUNDANT_LOAD_BALANCE));
99 static modcallable *mod_singletocallable(modsingle *p)
101 return (modcallable *)p;
103 static modcallable *mod_grouptocallable(modgroup *p)
105 return (modcallable *)p;
108 /* modgroups are grown by adding a modcallable to the end */
109 static void add_child(modgroup *g, modcallable *c)
111 modcallable **head = &g->children;
112 modcallable *node = *head;
113 modcallable **last = head;
122 rad_assert(c->next == NULL);
124 c->parent = mod_grouptocallable(g);
127 /* Here's where we recognize all of our keywords: first the rcodes, then the
129 static const LRAD_NAME_NUMBER rcode_table[] = {
130 { "reject", RLM_MODULE_REJECT },
131 { "fail", RLM_MODULE_FAIL },
132 { "ok", RLM_MODULE_OK },
133 { "handled", RLM_MODULE_HANDLED },
134 { "invalid", RLM_MODULE_INVALID },
135 { "userlock", RLM_MODULE_USERLOCK },
136 { "notfound", RLM_MODULE_NOTFOUND },
137 { "noop", RLM_MODULE_NOOP },
138 { "updated", RLM_MODULE_UPDATED },
144 * Compile action && rcode for later use.
146 static int compile_action(modcallable *c, const char *attr, const char *value,
147 const char *filename, int lineno)
151 if (!strcasecmp(value, "return"))
152 action = MOD_ACTION_RETURN;
154 else if (!strcasecmp(value, "reject"))
155 action = MOD_ACTION_REJECT;
157 else if (strspn(value, "0123456789")==strlen(value)) {
158 action = atoi(value);
161 * Don't allow priority zero, for future use.
163 if (action == 0) return 0;
166 "%s[%d] Unknown action '%s'.\n",
167 filename, lineno, value);
171 if (strcasecmp(attr, "default") != 0) {
174 rcode = lrad_str2int(rcode_table, attr, -1);
177 "%s[%d] Unknown module rcode '%s'.\n",
178 filename, lineno, attr);
181 c->actions[rcode] = action;
183 } else { /* set all unset values to the default */
186 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
187 if (!c->actions[i]) c->actions[i] = action;
194 /* Some short names for debugging output */
195 static const char * const comp2str[] = {
206 #ifdef HAVE_PTHREAD_H
208 * Lock the mutex for the module
210 static void safe_lock(module_instance_t *instance)
213 pthread_mutex_lock(instance->mutex);
217 * Unlock the mutex for the module
219 static void safe_unlock(module_instance_t *instance)
222 pthread_mutex_unlock(instance->mutex);
226 * No threads: these functions become NULL's.
228 #define safe_lock(foo)
229 #define safe_unlock(foo)
232 static int call_modsingle(int component, modsingle *sp, REQUEST *request,
235 int myresult = default_result;
237 DEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
238 comp2str[component], sp->modinst->name,
239 sp->modinst->entry->name, request->number);
240 safe_lock(sp->modinst);
243 * For logging unresponsive children.
245 request->module = sp->modinst->name;
247 myresult = sp->modinst->entry->module->methods[component](
248 sp->modinst->insthandle, request);
250 request->module = "<server-core>";
251 safe_unlock(sp->modinst);
252 DEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
253 comp2str[component], sp->modinst->name,
254 sp->modinst->entry->name, request->number);
260 static int default_component_results[RLM_COMPONENT_COUNT] = {
261 RLM_MODULE_REJECT, /* AUTH */
262 RLM_MODULE_NOTFOUND, /* AUTZ */
263 RLM_MODULE_NOOP, /* PREACCT */
264 RLM_MODULE_NOOP, /* ACCT */
265 RLM_MODULE_FAIL, /* SESS */
266 RLM_MODULE_NOOP, /* PRE_PROXY */
267 RLM_MODULE_NOOP, /* POST_PROXY */
268 RLM_MODULE_NOOP /* POST_AUTH */
271 static const char *group_name[] = {
274 "load-balance group",
275 "redundant-load-balance group",
281 static const char *modcall_spaces = " ";
283 #define MODCALL_STACK_MAX (32)
286 * Don't call the modules recursively. Instead, do them
287 * iteratively, and manage the call stack ourselves.
289 typedef struct modcall_stack {
292 int priority[MODCALL_STACK_MAX];
293 int result[MODCALL_STACK_MAX];
294 modcallable *children[MODCALL_STACK_MAX];
295 modcallable *start[MODCALL_STACK_MAX];
300 * Call a module, iteratively, with a local stack, rather than
301 * recursively. What did Paul Graham say about Lisp...?
303 int modcall(int component, modcallable *c, REQUEST *request)
307 modcallable *parent, *child;
309 int if_taken, was_if;
313 if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {
314 return RLM_MODULE_FAIL;
318 return default_component_results[component];
321 stack.priority[0] = 0;
322 stack.children[0] = c;
323 myresult = stack.result[0] = default_component_results[component];
324 was_if = if_taken = FALSE;
328 * A module has taken too long to process the request,
329 * and we've been told to stop processing it.
331 if (request->options & RAD_REQUEST_OPTION_STOP_NOW) {
332 myresult = RLM_MODULE_FAIL;
336 child = stack.children[stack.pointer];
337 rad_assert(child != NULL);
338 parent = child->parent;
340 if ((child->type == MOD_ELSE) || (child->type == MOD_ELSIF)) {
341 if (!was_if) { /* error */
342 DEBUG2("modcall:%.*s skipping %s for request %d: No preceding \"if\"",
343 stack.pointer, modcall_spaces,
344 group_name[child->type],
349 DEBUG2("modcall:%.*s skipping %s for request %d: Preceding \"if\" was taken",
350 stack.pointer, modcall_spaces,
351 group_name[child->type],
358 * "if", and the requested action wasn't the
359 * proper return code, skip the group.
361 if (((child->type == MOD_IF) || (child->type == MOD_ELSIF)) &&
362 !child->actions[myresult]) {
363 DEBUG2("modcall:%.*s skipping %s \"%s\" for request %d, return code was %s",
364 stack.pointer, modcall_spaces,
365 group_name[child->type],
366 child->name, request->number,
367 lrad_int2str(rcode_table, myresult, "??"));
368 stack.children[stack.pointer] = NULL;
372 } /* else process it, as a simple group */
375 * Child is a group that has children of it's own.
377 if (child->type != MOD_SINGLE) {
380 modgroup *g = mod_callabletogroup(child);
385 * Catastrophic error. This SHOULD have
386 * been caught when we were reading in the
391 if (stack.pointer >= MODCALL_STACK_MAX) {
392 radlog(L_ERR, "Internal sanity check failed: module stack is too deep");
396 stack.priority[stack.pointer] = 0;
397 stack.result[stack.pointer] = default_component_results[component];
398 switch (child->type) {
403 stack.children[stack.pointer] = g->children;
407 * See the "camel book" for why
410 * If (rand(0..n) < 1), pick the
411 * current realm. We add a scale
412 * factor of 65536, to avoid
415 case MOD_LOAD_BALANCE:
416 case MOD_REDUNDANT_LOAD_BALANCE:
418 for(p = g->children; p; p = p->next) {
427 if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
431 stack.children[stack.pointer] = q;
435 exit(1); /* internal sanity check failure */
440 stack.start[stack.pointer] = stack.children[stack.pointer];
442 DEBUG2("modcall:%.*s entering %s %s for request %d",
443 stack.pointer, modcall_spaces,
444 group_name[child->type],
445 child->name, request->number);
448 * Catch the special case of a NULL group.
450 if (!stack.children[stack.pointer]) {
452 * Print message for NULL group
454 DEBUG2("modcall[%s]: NULL object returns %s for request %d",
456 lrad_int2str(rcode_table,
457 stack.result[stack.pointer],
464 * The child may be a group, so we want to
465 * recurse into it's children, rather than
466 * falling through to the code below.
472 * Process a stand-alone child, and fall through
473 * to dealing with it's parent.
475 sp = mod_callabletosingle(child);
477 myresult = call_modsingle(component, sp, request,
478 default_component_results[component]);
479 DEBUG2(" modcall[%s]: module \"%s\" returns %s for request %d",
480 comp2str[component], child->name,
481 lrad_int2str(rcode_table, myresult, "??"),
486 * FIXME: Allow modules to push a modcallable
487 * onto this stack. This should simplify
488 * configuration a LOT!
490 * Once we do that, we can't do load-time
491 * checking of the maximum stack depth, and we've
492 * got to cache the stack pointer before storing
495 * Also, if the stack changed, we need to set
496 * children[ptr] to NULL, and process the next
497 * entry on the stack, rather than falling
498 * through to finalize the processing of this
501 * Don't put "myresult" on the stack here,
502 * we have to do so with priority.
506 * We roll back up the stack at this point.
510 * The child's action says return. Do so.
512 if (child->actions[myresult] == MOD_ACTION_RETURN) {
513 stack.result[stack.pointer] = myresult;
514 stack.children[stack.pointer] = NULL;
519 * If "reject", break out of the loop and return
522 if (child->actions[myresult] == MOD_ACTION_REJECT) {
523 stack.children[stack.pointer] = NULL;
524 stack.result[stack.pointer] = RLM_MODULE_REJECT;
529 * Otherwise, the action is a number, the
530 * preference level of this return code. If no
531 * higher preference has been seen yet, remember
534 if (child->actions[myresult] >= stack.priority[stack.pointer]) {
535 stack.result[stack.pointer] = myresult;
536 stack.priority[stack.pointer] = child->actions[myresult];
540 * No parent, we must be done.
543 rad_assert(stack.pointer == 0);
544 myresult = stack.result[0];
548 rad_assert(child != NULL);
551 * Go to the "next" child, whatever that is.
553 switch (parent->type) {
558 stack.children[stack.pointer] = child->next;
561 case MOD_LOAD_BALANCE:
562 stack.children[stack.pointer] = NULL;
565 case MOD_REDUNDANT_LOAD_BALANCE:
567 stack.children[stack.pointer] = child->next;
569 modgroup *g = mod_callabletogroup(parent);
571 stack.children[stack.pointer] = g->children;
573 if (stack.children[stack.pointer] == stack.start[stack.pointer]) {
574 stack.children[stack.pointer] = NULL;
582 * No child, we're done this group, and we return
583 * "myresult" to the caller by pushing it back up
586 if (!stack.children[stack.pointer]) {
588 rad_assert(stack.pointer > 0);
589 myresult = stack.result[stack.pointer];
592 DEBUG2("modcall:%.*s %s %s returns %s for request %d",
593 stack.pointer, modcall_spaces,
594 group_name[parent->type], parent->name,
595 lrad_int2str(rcode_table, myresult, "??"),
598 if (stack.pointer == 0) break;
600 if ((parent->type == MOD_IF) ||
601 (parent->type == MOD_ELSIF)) {
602 if_taken = was_if = TRUE;
604 if_taken = was_if = FALSE;
610 child = stack.children[stack.pointer];
611 parent = child->parent;
615 } /* loop until done */
622 static const char *action2str(int action)
625 if(action==MOD_ACTION_RETURN)
627 if(action==MOD_ACTION_REJECT)
629 snprintf(buf, sizeof buf, "%d", action);
633 /* If you suspect a bug in the parser, you'll want to use these dump
634 * functions. dump_tree should reproduce a whole tree exactly as it was found
635 * in radiusd.conf, but in long form (all actions explicitly defined) */
636 static void dump_mc(modcallable *c, int indent)
640 if(c->type==MOD_SINGLE) {
641 modsingle *single = mod_callabletosingle(c);
642 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
643 single->modinst->name);
645 modgroup *g = mod_callabletogroup(c);
647 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
648 group_name[c->type]);
649 for(p = g->children;p;p = p->next)
650 dump_mc(p, indent+1);
653 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
654 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
655 lrad_int2str(rcode_table, i, "??"),
656 action2str(c->actions[i]));
659 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
662 static void dump_tree(int comp, modcallable *c)
664 DEBUG("[%s]", comp2str[comp]);
668 #define dump_tree(a, b)
671 /* These are the default actions. For each component, the group{} block
672 * behaves like the code from the old module_*() function. redundant{} and
673 * append{} are based on my guesses of what they will be used for. --Pac. */
675 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
681 MOD_ACTION_RETURN, /* reject */
683 MOD_ACTION_RETURN, /* ok */
684 MOD_ACTION_RETURN, /* handled */
686 MOD_ACTION_RETURN, /* userlock */
687 MOD_ACTION_RETURN, /* notfound */
693 MOD_ACTION_RETURN, /* reject */
695 MOD_ACTION_RETURN, /* ok */
696 MOD_ACTION_RETURN, /* handled */
697 MOD_ACTION_RETURN, /* invalid */
698 MOD_ACTION_RETURN, /* userlock */
699 MOD_ACTION_RETURN, /* notfound */
700 MOD_ACTION_RETURN, /* noop */
701 MOD_ACTION_RETURN /* updated */
705 MOD_ACTION_RETURN, /* reject */
707 MOD_ACTION_RETURN, /* ok */
708 MOD_ACTION_RETURN, /* handled */
709 MOD_ACTION_RETURN, /* invalid */
710 MOD_ACTION_RETURN, /* userlock */
712 MOD_ACTION_RETURN, /* noop */
713 MOD_ACTION_RETURN /* updated */
720 MOD_ACTION_RETURN, /* reject */
721 MOD_ACTION_RETURN, /* fail */
723 MOD_ACTION_RETURN, /* handled */
724 MOD_ACTION_RETURN, /* invalid */
725 MOD_ACTION_RETURN, /* userlock */
732 MOD_ACTION_RETURN, /* reject */
734 MOD_ACTION_RETURN, /* ok */
735 MOD_ACTION_RETURN, /* handled */
736 MOD_ACTION_RETURN, /* invalid */
737 MOD_ACTION_RETURN, /* userlock */
738 MOD_ACTION_RETURN, /* notfound */
739 MOD_ACTION_RETURN, /* noop */
740 MOD_ACTION_RETURN /* updated */
744 MOD_ACTION_RETURN, /* reject */
746 MOD_ACTION_RETURN, /* ok */
747 MOD_ACTION_RETURN, /* handled */
748 MOD_ACTION_RETURN, /* invalid */
749 MOD_ACTION_RETURN, /* userlock */
751 MOD_ACTION_RETURN, /* noop */
752 MOD_ACTION_RETURN /* updated */
759 MOD_ACTION_RETURN, /* reject */
760 MOD_ACTION_RETURN, /* fail */
762 MOD_ACTION_RETURN, /* handled */
763 MOD_ACTION_RETURN, /* invalid */
764 MOD_ACTION_RETURN, /* userlock */
765 MOD_ACTION_RETURN, /* notfound */
771 MOD_ACTION_RETURN, /* reject */
773 MOD_ACTION_RETURN, /* ok */
774 MOD_ACTION_RETURN, /* handled */
775 MOD_ACTION_RETURN, /* invalid */
776 MOD_ACTION_RETURN, /* userlock */
777 MOD_ACTION_RETURN, /* notfound */
778 MOD_ACTION_RETURN, /* noop */
779 MOD_ACTION_RETURN /* updated */
783 MOD_ACTION_RETURN, /* reject */
785 MOD_ACTION_RETURN, /* ok */
786 MOD_ACTION_RETURN, /* handled */
787 MOD_ACTION_RETURN, /* invalid */
788 MOD_ACTION_RETURN, /* userlock */
790 MOD_ACTION_RETURN, /* noop */
791 MOD_ACTION_RETURN /* updated */
798 MOD_ACTION_RETURN, /* reject */
799 MOD_ACTION_RETURN, /* fail */
801 MOD_ACTION_RETURN, /* handled */
802 MOD_ACTION_RETURN, /* invalid */
803 MOD_ACTION_RETURN, /* userlock */
804 MOD_ACTION_RETURN, /* notfound */
812 MOD_ACTION_RETURN, /* ok */
813 MOD_ACTION_RETURN, /* handled */
822 MOD_ACTION_RETURN, /* reject */
824 MOD_ACTION_RETURN, /* ok */
825 MOD_ACTION_RETURN, /* handled */
826 MOD_ACTION_RETURN, /* invalid */
827 MOD_ACTION_RETURN, /* userlock */
829 MOD_ACTION_RETURN, /* noop */
830 MOD_ACTION_RETURN /* updated */
837 MOD_ACTION_RETURN, /* reject */
839 MOD_ACTION_RETURN, /* ok */
840 MOD_ACTION_RETURN, /* handled */
841 MOD_ACTION_RETURN, /* invalid */
842 MOD_ACTION_RETURN, /* userlock */
843 MOD_ACTION_RETURN, /* notfound */
844 MOD_ACTION_RETURN, /* noop */
845 MOD_ACTION_RETURN /* updated */
849 MOD_ACTION_RETURN, /* reject */
851 MOD_ACTION_RETURN, /* ok */
852 MOD_ACTION_RETURN, /* handled */
853 MOD_ACTION_RETURN, /* invalid */
854 MOD_ACTION_RETURN, /* userlock */
855 MOD_ACTION_RETURN, /* notfound */
856 MOD_ACTION_RETURN, /* noop */
857 MOD_ACTION_RETURN /* updated */
861 MOD_ACTION_RETURN, /* reject */
863 MOD_ACTION_RETURN, /* ok */
864 MOD_ACTION_RETURN, /* handled */
865 MOD_ACTION_RETURN, /* invalid */
866 MOD_ACTION_RETURN, /* userlock */
867 MOD_ACTION_RETURN, /* notfound */
868 MOD_ACTION_RETURN, /* noop */
869 MOD_ACTION_RETURN /* updated */
876 MOD_ACTION_RETURN, /* reject */
877 MOD_ACTION_RETURN, /* fail */
879 MOD_ACTION_RETURN, /* handled */
880 MOD_ACTION_RETURN, /* invalid */
881 MOD_ACTION_RETURN, /* userlock */
888 MOD_ACTION_RETURN, /* reject */
890 MOD_ACTION_RETURN, /* ok */
891 MOD_ACTION_RETURN, /* handled */
892 MOD_ACTION_RETURN, /* invalid */
893 MOD_ACTION_RETURN, /* userlock */
894 MOD_ACTION_RETURN, /* notfound */
895 MOD_ACTION_RETURN, /* noop */
896 MOD_ACTION_RETURN /* updated */
900 MOD_ACTION_RETURN, /* reject */
902 MOD_ACTION_RETURN, /* ok */
903 MOD_ACTION_RETURN, /* handled */
904 MOD_ACTION_RETURN, /* invalid */
905 MOD_ACTION_RETURN, /* userlock */
907 MOD_ACTION_RETURN, /* noop */
908 MOD_ACTION_RETURN /* updated */
915 MOD_ACTION_RETURN, /* reject */
916 MOD_ACTION_RETURN, /* fail */
918 MOD_ACTION_RETURN, /* handled */
919 MOD_ACTION_RETURN, /* invalid */
920 MOD_ACTION_RETURN, /* userlock */
927 MOD_ACTION_RETURN, /* reject */
929 MOD_ACTION_RETURN, /* ok */
930 MOD_ACTION_RETURN, /* handled */
931 MOD_ACTION_RETURN, /* invalid */
932 MOD_ACTION_RETURN, /* userlock */
933 MOD_ACTION_RETURN, /* notfound */
934 MOD_ACTION_RETURN, /* noop */
935 MOD_ACTION_RETURN /* updated */
939 MOD_ACTION_RETURN, /* reject */
941 MOD_ACTION_RETURN, /* ok */
942 MOD_ACTION_RETURN, /* handled */
943 MOD_ACTION_RETURN, /* invalid */
944 MOD_ACTION_RETURN, /* userlock */
946 MOD_ACTION_RETURN, /* noop */
947 MOD_ACTION_RETURN /* updated */
954 MOD_ACTION_RETURN, /* reject */
955 MOD_ACTION_RETURN, /* fail */
957 MOD_ACTION_RETURN, /* handled */
958 MOD_ACTION_RETURN, /* invalid */
959 MOD_ACTION_RETURN, /* userlock */
966 MOD_ACTION_RETURN, /* reject */
968 MOD_ACTION_RETURN, /* ok */
969 MOD_ACTION_RETURN, /* handled */
970 MOD_ACTION_RETURN, /* invalid */
971 MOD_ACTION_RETURN, /* userlock */
972 MOD_ACTION_RETURN, /* notfound */
973 MOD_ACTION_RETURN, /* noop */
974 MOD_ACTION_RETURN /* updated */
978 MOD_ACTION_RETURN, /* reject */
980 MOD_ACTION_RETURN, /* ok */
981 MOD_ACTION_RETURN, /* handled */
982 MOD_ACTION_RETURN, /* invalid */
983 MOD_ACTION_RETURN, /* userlock */
985 MOD_ACTION_RETURN, /* noop */
986 MOD_ACTION_RETURN /* updated */
992 static int condition2actions(modcallable *mc, const char *actions)
997 if (strlen(actions) >= sizeof(buffer)) {
1001 memset(mc->actions, 0, sizeof(mc->actions));
1004 * Copy, stripping space.
1008 if (*actions != ' ') {
1023 rcode = lrad_str2int(rcode_table, p, -1);
1024 if (rcode < 0) return -1;
1025 mc->actions[rcode] = 1;
1036 * Compile one entry of a module call.
1038 static modcallable *do_compile_modsingle(modcallable *parent,
1039 int component, CONF_ITEM *ci,
1040 const char *filename, int grouptype,
1041 const char **modname)
1044 const char *modrefname;
1046 modcallable *csingle;
1047 module_instance_t *this;
1049 if (cf_item_is_section(ci)) {
1050 CONF_SECTION *cs = cf_itemtosection(ci);
1051 const char *name2 = cf_section_name2(cs);
1053 lineno = cf_section_lineno(cs);
1054 modrefname = cf_section_name1(cs);
1055 if (!name2) name2 = "_UnNamedGroup";
1058 * group{}, redundant{}, or append{} may appear
1059 * where a single module instance was expected.
1060 * In that case, we hand it off to
1063 if (strcmp(modrefname, "group") == 0) {
1065 return do_compile_modgroup(parent, component, cs,
1069 } else if (strcmp(modrefname, "redundant") == 0) {
1071 return do_compile_modgroup(parent, component, cs,
1073 GROUPTYPE_REDUNDANT,
1075 } else if (strcmp(modrefname, "append") == 0) {
1077 return do_compile_modgroup(parent, component, cs,
1081 } else if (strcmp(modrefname, "load-balance") == 0) {
1083 csingle= do_compile_modgroup(parent, component, cs,
1087 if (!csingle) return NULL;
1088 csingle->type = MOD_LOAD_BALANCE;
1090 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1092 csingle= do_compile_modgroup(parent, component, cs,
1094 GROUPTYPE_REDUNDANT,
1096 if (!csingle) return NULL;
1097 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1099 } else if (strcmp(modrefname, "if") == 0) {
1100 if (!cf_section_name2(cs)) {
1101 radlog(L_ERR|L_CONS,
1102 "%s[%d] 'if' without condition.\n",
1108 csingle= do_compile_modgroup(parent, component, cs,
1112 if (!csingle) return NULL;
1113 csingle->type = MOD_IF;
1115 if (condition2actions(csingle, name2) < 0) {
1116 modcallable_free(&csingle);
1117 radlog(L_ERR|L_CONS,
1118 "%s[%d] Invalid module condition rcode '%s'.\n",
1119 filename, lineno, name2);
1124 } else if (strcmp(modrefname, "elsif") == 0) {
1126 ((parent->type == MOD_LOAD_BALANCE) ||
1127 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1128 radlog(L_ERR|L_CONS,
1129 "%s[%d] 'elsif' cannot be used in this section section.\n",
1134 if (!cf_section_name2(cs)) {
1135 radlog(L_ERR|L_CONS,
1136 "%s[%d] 'elsif' without condition.\n",
1142 csingle= do_compile_modgroup(parent, component, cs,
1146 if (!csingle) return NULL;
1147 csingle->type = MOD_ELSIF;
1149 if (condition2actions(csingle, name2) < 0) {
1150 modcallable_free(&csingle);
1151 radlog(L_ERR|L_CONS,
1152 "%s[%d] Invalid module condition rcode '%s'.\n",
1153 filename, lineno, name2);
1158 } else if (strcmp(modrefname, "else") == 0) {
1160 ((parent->type == MOD_LOAD_BALANCE) ||
1161 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1162 radlog(L_ERR|L_CONS,
1163 "%s[%d] 'else' cannot be used in this section section.\n",
1168 if (cf_section_name2(cs)) {
1169 radlog(L_ERR|L_CONS,
1170 "%s[%d] Cannot have conditions on 'else'.\n",
1176 csingle= do_compile_modgroup(parent, component, cs,
1180 if (!csingle) return NULL;
1181 csingle->type = MOD_ELSE;
1186 * Else it's a module reference, with updated return
1190 CONF_PAIR *cp = cf_itemtopair(ci);
1191 lineno = cf_pair_lineno(cp);
1192 modrefname = cf_pair_attr(cp);
1196 * See if the module is a virtual one. If so, return that,
1197 * rather than doing anything here.
1199 this = find_module_instance(cf_section_find("modules"), modrefname);
1201 CONF_SECTION *cs, *subcs;
1204 * Then, look for it in the "instantiate" section.
1206 if (((subcs = cf_section_find(NULL)) != NULL) &&
1207 ((cs = cf_section_sub_find_name2(subcs, "instantiate", NULL)) != NULL)) {
1208 subcs = cf_section_sub_find_name2(cs, NULL, modrefname);
1211 * As it's sole configuration, the
1212 * virtual module takes a section which
1215 return do_compile_modsingle(parent,
1217 cf_sectiontoitem(subcs),
1226 radlog(L_ERR|L_CONS, "%s[%d] Failed to find module \"%s\".", filename,
1227 lineno, modrefname);
1232 * We know it's all OK, allocate the structures, and fill
1235 single = rad_malloc(sizeof(*single));
1236 memset(single, 0, sizeof(*single));
1237 csingle = mod_singletocallable(single);
1238 csingle->parent = parent;
1239 csingle->next = NULL;
1240 csingle->lineno = lineno;
1241 memcpy(csingle->actions, defaultactions[component][grouptype],
1242 sizeof csingle->actions);
1243 rad_assert(modrefname != NULL);
1244 csingle->name = modrefname;
1245 csingle->type = MOD_SINGLE;
1248 * Singles can override the actions, virtual modules cannot.
1250 * FIXME: We may want to re-visit how to do this...
1251 * maybe a csingle as a ref?
1253 if (cf_item_is_section(ci)) {
1254 CONF_SECTION *cs = cf_itemtosection(ci);
1256 const char *attr, *value;
1258 for (ci=cf_item_find_next(cs, NULL);
1260 ci=cf_item_find_next(cs, ci)) {
1262 if (cf_item_is_section(ci)) {
1263 radlog(L_ERR|L_CONS,
1264 "%s[%d] Subsection of module instance call "
1265 "not allowed\n", filename,
1266 cf_section_lineno(cf_itemtosection(ci)));
1267 modcallable_free(&csingle);
1271 cp = cf_itemtopair(ci);
1272 attr = cf_pair_attr(cp);
1273 value = cf_pair_value(cp);
1274 lineno = cf_pair_lineno(cp);
1276 if (!compile_action(csingle, attr, value, filename,
1278 modcallable_free(&csingle);
1285 * Bail out if the module in question does not supply the
1288 if (!this->entry->module->methods[component]) {
1289 radlog(L_ERR|L_CONS,
1290 "%s[%d]: \"%s\" modules aren't allowed in '%s' sections -- they have no such method.",
1291 filename, lineno, this->entry->module->name,
1292 comp2str[component]);
1293 modcallable_free(&csingle);
1297 single->modinst = this;
1298 *modname = this->entry->module->name;
1302 modcallable *compile_modsingle(modcallable *parent,
1303 int component, CONF_ITEM *ci,
1304 const char *filename, const char **modname)
1306 modcallable *ret = do_compile_modsingle(parent, component, ci,
1310 dump_tree(component, ret);
1316 * Internal compile group code.
1318 static modcallable *do_compile_modgroup(modcallable *parent,
1319 int component, CONF_SECTION *cs,
1320 const char *filename, int grouptype,
1321 int parentgrouptype)
1328 g = rad_malloc(sizeof(*g));
1329 memset(g, 0, sizeof(*g));
1330 g->grouptype = grouptype;
1332 c = mod_grouptocallable(g);
1335 c->lineno = cf_section_lineno(cs);
1336 memset(c->actions, 0, sizeof(c->actions));
1339 * Remember the name for printing, etc.
1341 * FIXME: We may also want to put the names into a
1342 * rbtree, so that groups can reference each other...
1344 c->name = cf_section_name2(cs);
1345 if (!c->name) c->name = "";
1346 c->type = MOD_GROUP;
1350 * Loop over the children of this group.
1352 for (ci=cf_item_find_next(cs, NULL);
1354 ci=cf_item_find_next(cs, ci)) {
1357 * Sections are references to other groups, or
1358 * to modules with updated return codes.
1360 if (cf_item_is_section(ci)) {
1361 const char *junk = NULL;
1362 modcallable *single;
1364 CONF_SECTION *subcs = cf_itemtosection(ci);
1366 lineno = cf_section_lineno(subcs);
1368 single = do_compile_modsingle(c, component, ci,
1372 radlog(L_ERR|L_CONS,
1373 "%s[%d] Failed to parse \"%s\" subsection.\n",
1375 cf_section_name1(subcs));
1376 modcallable_free(&c);
1379 add_child(g, single);
1382 const char *attr, *value;
1383 CONF_PAIR *cp = cf_itemtopair(ci);
1386 attr = cf_pair_attr(cp);
1387 value = cf_pair_value(cp);
1388 lineno = cf_pair_lineno(cp);
1391 * A CONF_PAIR is either a module
1392 * instance with no actions
1395 if (value[0] == 0) {
1396 modcallable *single;
1397 const char *junk = NULL;
1399 single = do_compile_modsingle(c,
1406 radlog(L_ERR|L_CONS,
1407 "%s[%d] Failed to parse \"%s\" entry.\n",
1408 filename, lineno, attr);
1409 modcallable_free(&c);
1412 add_child(g, single);
1415 * Or a module instance with action.
1417 } else if (!compile_action(c, attr, value, filename,
1419 modcallable_free(&c);
1421 } /* else it worked */
1426 * Set the default actions, if they haven't already been
1429 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1430 if (!c->actions[i]) {
1431 c->actions[i] = defaultactions[component][parentgrouptype][i];
1436 * FIXME: If there are no children, return NULL?
1438 return mod_grouptocallable(g);
1441 modcallable *compile_modgroup(modcallable *parent,
1442 int component, CONF_SECTION *cs,
1443 const char *filename)
1445 modcallable *ret = do_compile_modgroup(parent, component, cs, filename,
1448 dump_tree(component, ret);
1452 void add_to_modcallable(modcallable **parent, modcallable *this,
1453 int component, const char *name)
1457 rad_assert(this != NULL);
1459 if (*parent == NULL) {
1462 g = rad_malloc(sizeof *g);
1463 memset(g, 0, sizeof(*g));
1464 g->grouptype = GROUPTYPE_SIMPLE;
1465 c = mod_grouptocallable(g);
1468 defaultactions[component][GROUPTYPE_SIMPLE],
1469 sizeof(c->actions));
1470 rad_assert(name != NULL);
1472 c->type = MOD_GROUP;
1475 *parent = mod_grouptocallable(g);
1477 g = mod_callabletogroup(*parent);
1483 void modcallable_free(modcallable **pc)
1485 modcallable *c, *loop, *next;
1487 if(c->type==MOD_GROUP) {
1488 for(loop = mod_callabletogroup(c)->children;
1492 modcallable_free(&loop);