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/radiusd.h>
27 #include <freeradius-devel/modpriv.h>
28 #include <freeradius-devel/modcall.h>
29 #include <freeradius-devel/rad_assert.h>
32 /* mutually-recursive static functions need a prototype up front */
33 static modcallable *do_compile_modgroup(modcallable *,
37 /* Actions may be a positive integer (the highest one returned in the group
38 * will be returned), or the keyword "return", represented here by
39 * MOD_ACTION_RETURN, to cause an immediate return.
40 * There's also the keyword "reject", represented here by MOD_ACTION_REJECT
41 * to cause an immediate reject. */
42 #define MOD_ACTION_RETURN (-1)
43 #define MOD_ACTION_REJECT (-2)
45 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
46 * explanation of what they are all about, see ../../doc/README.failover */
49 struct modcallable *next;
51 int actions[RLM_MODULE_NUMCODES];
52 enum { MOD_SINGLE = 1, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE, MOD_IF, MOD_ELSE, MOD_ELSIF, MOD_UPDATE, MOD_SWITCH, MOD_CASE } type;
55 #define GROUPTYPE_SIMPLE 0
56 #define GROUPTYPE_REDUNDANT 1
57 #define GROUPTYPE_APPEND 2
58 #define GROUPTYPE_COUNT 3
61 modcallable mc; /* self */
62 int grouptype; /* after mc */
63 modcallable *children;
70 module_instance_t *modinst;
73 static const LRAD_NAME_NUMBER grouptype_table[] = {
74 { "", GROUPTYPE_SIMPLE },
75 { "redundant ", GROUPTYPE_REDUNDANT },
76 { "append ", GROUPTYPE_APPEND },
80 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
81 * so we often want to go back and forth between them. */
82 static modsingle *mod_callabletosingle(modcallable *p)
84 rad_assert(p->type==MOD_SINGLE);
85 return (modsingle *)p;
87 static modgroup *mod_callabletogroup(modcallable *p)
89 rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_CASE));
93 static modcallable *mod_singletocallable(modsingle *p)
95 return (modcallable *)p;
97 static modcallable *mod_grouptocallable(modgroup *p)
99 return (modcallable *)p;
102 /* modgroups are grown by adding a modcallable to the end */
103 static void add_child(modgroup *g, modcallable *c)
105 modcallable **head = &g->children;
106 modcallable *node = *head;
107 modcallable **last = head;
116 rad_assert(c->next == NULL);
118 c->parent = mod_grouptocallable(g);
121 /* Here's where we recognize all of our keywords: first the rcodes, then the
123 static const LRAD_NAME_NUMBER rcode_table[] = {
124 { "reject", RLM_MODULE_REJECT },
125 { "fail", RLM_MODULE_FAIL },
126 { "ok", RLM_MODULE_OK },
127 { "handled", RLM_MODULE_HANDLED },
128 { "invalid", RLM_MODULE_INVALID },
129 { "userlock", RLM_MODULE_USERLOCK },
130 { "notfound", RLM_MODULE_NOTFOUND },
131 { "noop", RLM_MODULE_NOOP },
132 { "updated", RLM_MODULE_UPDATED },
138 * Compile action && rcode for later use.
140 static int compile_action(modcallable *c, CONF_PAIR *cp)
143 const char *attr, *value;
145 attr = cf_pair_attr(cp);
146 value = cf_pair_value(cp);
147 if (!value) return 0;
149 if (!strcasecmp(value, "return"))
150 action = MOD_ACTION_RETURN;
152 else if (!strcasecmp(value, "reject"))
153 action = MOD_ACTION_REJECT;
155 else if (strspn(value, "0123456789")==strlen(value)) {
156 action = atoi(value);
159 * Don't allow priority zero, for future use.
161 if (action == 0) return 0;
163 cf_log_err(cf_pairtoitem(cp), "Unknown action '%s'.\n",
168 if (strcasecmp(attr, "default") != 0) {
171 rcode = lrad_str2int(rcode_table, attr, -1);
173 cf_log_err(cf_pairtoitem(cp),
174 "Unknown module rcode '%s'.\n",
178 c->actions[rcode] = action;
180 } else { /* set all unset values to the default */
183 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
184 if (!c->actions[i]) c->actions[i] = action;
191 /* Some short names for debugging output */
192 static const char * const comp2str[] = {
203 #ifdef HAVE_PTHREAD_H
205 * Lock the mutex for the module
207 static void safe_lock(module_instance_t *instance)
210 pthread_mutex_lock(instance->mutex);
214 * Unlock the mutex for the module
216 static void safe_unlock(module_instance_t *instance)
219 pthread_mutex_unlock(instance->mutex);
223 * No threads: these functions become NULL's.
225 #define safe_lock(foo)
226 #define safe_unlock(foo)
229 static int call_modsingle(int component, modsingle *sp, REQUEST *request,
232 int myresult = default_result;
234 DEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
235 comp2str[component], sp->modinst->name,
236 sp->modinst->entry->name, request->number);
237 safe_lock(sp->modinst);
240 * For logging unresponsive children.
242 request->module = sp->modinst->name;
244 myresult = sp->modinst->entry->module->methods[component](
245 sp->modinst->insthandle, request);
247 request->module = "<server-core>";
248 safe_unlock(sp->modinst);
249 DEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
250 comp2str[component], sp->modinst->name,
251 sp->modinst->entry->name, request->number);
257 static int default_component_results[RLM_COMPONENT_COUNT] = {
258 RLM_MODULE_REJECT, /* AUTH */
259 RLM_MODULE_NOTFOUND, /* AUTZ */
260 RLM_MODULE_NOOP, /* PREACCT */
261 RLM_MODULE_NOOP, /* ACCT */
262 RLM_MODULE_FAIL, /* SESS */
263 RLM_MODULE_NOOP, /* PRE_PROXY */
264 RLM_MODULE_NOOP, /* POST_PROXY */
265 RLM_MODULE_NOOP /* POST_AUTH */
269 static const char *group_name[] = {
273 "load-balance group",
274 "redundant-load-balance group",
283 static const char *modcall_spaces = "++++++++++++++++++++++++++++++++";
285 #define MODCALL_STACK_MAX (32)
288 * Don't call the modules recursively. Instead, do them
289 * iteratively, and manage the call stack ourselves.
291 typedef struct modcall_stack {
294 int priority[MODCALL_STACK_MAX];
295 int result[MODCALL_STACK_MAX];
296 modcallable *children[MODCALL_STACK_MAX];
297 modcallable *start[MODCALL_STACK_MAX];
302 * Call a module, iteratively, with a local stack, rather than
303 * recursively. What did Paul Graham say about Lisp...?
305 int modcall(int component, modcallable *c, REQUEST *request)
309 modcallable *parent, *child;
311 int if_taken, was_if;
313 if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {
314 return RLM_MODULE_FAIL;
318 stack.priority[0] = 0;
319 stack.children[0] = c;
320 myresult = stack.result[0] = default_component_results[component];
321 was_if = if_taken = FALSE;
325 * A module has taken too long to process the request,
326 * and we've been told to stop processing it.
328 if ((request->master_state == REQUEST_STOP_PROCESSING) ||
330 (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
331 myresult = RLM_MODULE_FAIL;
335 child = stack.children[stack.pointer];
337 myresult = stack.result[stack.pointer];
340 parent = child->parent;
342 if ((child->type == MOD_ELSE) || (child->type == MOD_ELSIF)) {
343 myresult = stack.result[stack.pointer];
345 if (!was_if) { /* error */
346 DEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",
347 stack.pointer + 1, modcall_spaces,
348 group_name[child->type],
353 DEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
354 stack.pointer + 1, modcall_spaces,
355 group_name[child->type],
362 * "if" or "elsif". Evaluate the condition.
364 if ((child->type == MOD_IF) || (child->type == MOD_ELSIF)) {
365 int condition = TRUE;
366 const char *p = child->name;
368 DEBUG2("%.*s? %s %s",
369 stack.pointer + 1, modcall_spaces,
370 (child->type == MOD_IF) ? "if" : "elsif",
373 if (radius_evaluate_condition(request, myresult,
374 0, &p, TRUE, &condition)) {
375 DEBUG2("%.*s? %s %s -> %s",
376 stack.pointer + 1, modcall_spaces,
377 (child->type == MOD_IF) ? "if" : "elsif",
378 child->name, (condition != FALSE) ? "TRUE" : "FALSE");
381 * This should never happen, the
382 * condition is checked when the
383 * module section is loaded.
389 stack.result[stack.pointer] = myresult;
390 stack.children[stack.pointer] = NULL;
394 } /* else process it as a simple group */
397 if (child->type == MOD_UPDATE) {
399 modgroup *g = mod_callabletogroup(child);
401 rcode = radius_update_attrlist(request, g->cs,
402 g->vps, child->name);
403 if (rcode != RLM_MODULE_UPDATED) {
410 * Child is a group that has children of it's own.
412 if (child->type != MOD_SINGLE) {
414 modcallable *p, *q, *null_case;
415 modgroup *g = mod_callabletogroup(child);
420 * Catastrophic error. This SHOULD have
421 * been caught when we were reading in the
426 if (stack.pointer >= MODCALL_STACK_MAX) {
427 radlog(L_ERR, "Internal sanity check failed: module stack is too deep");
431 stack.priority[stack.pointer] = 0;
432 stack.result[stack.pointer] = default_component_results[component];
433 switch (child->type) {
441 stack.children[stack.pointer] = g->children;
445 * See the "camel book" for why
448 * If (rand(0..n) < 1), pick the
449 * current realm. We add a scale
450 * factor of 65536, to avoid
453 case MOD_LOAD_BALANCE:
454 case MOD_REDUNDANT_LOAD_BALANCE:
456 for(p = g->children; p; p = p->next) {
465 if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
469 stack.children[stack.pointer] = q;
473 radius_xlat(buffer, sizeof(buffer),
474 child->name, request, NULL);
476 null_case = q = NULL;
477 for(p = g->children; p; p = p->next) {
479 if (!null_case) null_case = p;
482 if (strcmp(buffer, p->name) == 0) {
488 if (!q) q = null_case;
490 stack.children[stack.pointer] = q;
494 DEBUG2("Internal sanity check failed in modcall %d", child->type);
495 exit(1); /* internal sanity check failure */
500 stack.start[stack.pointer] = stack.children[stack.pointer];
502 DEBUG2("%.*s- entering %s %s",
503 stack.pointer, modcall_spaces,
504 group_name[child->type],
505 child->name ? child->name : "");
508 * Catch the special case of a NULL group.
510 if (!stack.children[stack.pointer]) {
512 * Print message for NULL group
514 DEBUG2("%.*s- %s %s returns %s",
515 stack.pointer + 1, modcall_spaces,
516 group_name[child->type],
517 child->name ? child->name : "",
518 lrad_int2str(rcode_table,
519 stack.result[stack.pointer],
525 * The child may be a group, so we want to
526 * recurse into it's children, rather than
527 * falling through to the code below.
533 * Process a stand-alone child, and fall through
534 * to dealing with it's parent.
536 sp = mod_callabletosingle(child);
538 myresult = call_modsingle(component, sp, request,
539 default_component_results[component]);
541 DEBUG2("%.*s[%s] returns %s",
542 stack.pointer + 1, modcall_spaces,
543 child->name ? child->name : "",
544 lrad_int2str(rcode_table, myresult, "??"));
548 * FIXME: Allow modules to push a modcallable
549 * onto this stack. This should simplify
550 * configuration a LOT!
552 * Once we do that, we can't do load-time
553 * checking of the maximum stack depth, and we've
554 * got to cache the stack pointer before storing
557 * Also, if the stack changed, we need to set
558 * children[ptr] to NULL, and process the next
559 * entry on the stack, rather than falling
560 * through to finalize the processing of this
563 * Don't put "myresult" on the stack here,
564 * we have to do so with priority.
568 * We roll back up the stack at this point.
572 * The child's action says return. Do so.
574 if (child->actions[myresult] == MOD_ACTION_RETURN) {
575 stack.result[stack.pointer] = myresult;
576 stack.children[stack.pointer] = NULL;
581 * If "reject", break out of the loop and return
584 if (child->actions[myresult] == MOD_ACTION_REJECT) {
585 stack.children[stack.pointer] = NULL;
586 stack.result[stack.pointer] = RLM_MODULE_REJECT;
591 * Otherwise, the action is a number, the
592 * preference level of this return code. If no
593 * higher preference has been seen yet, remember
596 if (child->actions[myresult] >= stack.priority[stack.pointer]) {
597 stack.result[stack.pointer] = myresult;
598 stack.priority[stack.pointer] = child->actions[myresult];
604 * No parent, we must be done.
607 rad_assert(stack.pointer == 0);
608 myresult = stack.result[0];
612 rad_assert(child != NULL);
615 * Go to the "next" child, whatever that is.
617 switch (parent->type) {
623 stack.children[stack.pointer] = child->next;
627 case MOD_LOAD_BALANCE:
628 stack.children[stack.pointer] = NULL;
631 case MOD_REDUNDANT_LOAD_BALANCE:
633 stack.children[stack.pointer] = child->next;
635 modgroup *g = mod_callabletogroup(parent);
637 stack.children[stack.pointer] = g->children;
639 if (stack.children[stack.pointer] == stack.start[stack.pointer]) {
640 stack.children[stack.pointer] = NULL;
644 DEBUG2("Internal sanity check failed in modcall next %d", child->type);
649 * No child, we're done this group, and we return
650 * "myresult" to the caller by pushing it back up
653 if (!stack.children[stack.pointer]) {
655 rad_assert(stack.pointer > 0);
656 myresult = stack.result[stack.pointer];
659 if (stack.pointer == 0) break;
661 DEBUG2("%.*s- %s %s returns %s",
662 stack.pointer + 1, modcall_spaces,
663 group_name[parent->type],
664 parent->name ? parent->name : "",
665 lrad_int2str(rcode_table, myresult, "??"));
667 if ((parent->type == MOD_IF) ||
668 (parent->type == MOD_ELSIF)) {
669 if_taken = was_if = TRUE;
671 if_taken = was_if = FALSE;
677 child = stack.children[stack.pointer];
678 parent = child->parent;
682 } /* loop until done */
689 static const char *action2str(int action)
692 if(action==MOD_ACTION_RETURN)
694 if(action==MOD_ACTION_REJECT)
696 snprintf(buf, sizeof buf, "%d", action);
700 /* If you suspect a bug in the parser, you'll want to use these dump
701 * functions. dump_tree should reproduce a whole tree exactly as it was found
702 * in radiusd.conf, but in long form (all actions explicitly defined) */
703 static void dump_mc(modcallable *c, int indent)
707 if(c->type==MOD_SINGLE) {
708 modsingle *single = mod_callabletosingle(c);
709 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
710 single->modinst->name);
712 modgroup *g = mod_callabletogroup(c);
714 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
715 group_name[c->type]);
716 for(p = g->children;p;p = p->next)
717 dump_mc(p, indent+1);
720 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
721 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
722 lrad_int2str(rcode_table, i, "??"),
723 action2str(c->actions[i]));
726 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
729 static void dump_tree(int comp, modcallable *c)
731 DEBUG("[%s]", comp2str[comp]);
735 #define dump_tree(a, b)
738 /* These are the default actions. For each component, the group{} block
739 * behaves like the code from the old module_*() function. redundant{} and
740 * append{} are based on my guesses of what they will be used for. --Pac. */
742 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
748 MOD_ACTION_RETURN, /* reject */
750 MOD_ACTION_RETURN, /* ok */
751 MOD_ACTION_RETURN, /* handled */
753 MOD_ACTION_RETURN, /* userlock */
754 MOD_ACTION_RETURN, /* notfound */
760 MOD_ACTION_RETURN, /* reject */
762 MOD_ACTION_RETURN, /* ok */
763 MOD_ACTION_RETURN, /* handled */
764 MOD_ACTION_RETURN, /* invalid */
765 MOD_ACTION_RETURN, /* userlock */
766 MOD_ACTION_RETURN, /* notfound */
767 MOD_ACTION_RETURN, /* noop */
768 MOD_ACTION_RETURN /* updated */
772 MOD_ACTION_RETURN, /* reject */
774 MOD_ACTION_RETURN, /* ok */
775 MOD_ACTION_RETURN, /* handled */
776 MOD_ACTION_RETURN, /* invalid */
777 MOD_ACTION_RETURN, /* userlock */
779 MOD_ACTION_RETURN, /* noop */
780 MOD_ACTION_RETURN /* updated */
787 MOD_ACTION_RETURN, /* reject */
788 MOD_ACTION_RETURN, /* fail */
790 MOD_ACTION_RETURN, /* handled */
791 MOD_ACTION_RETURN, /* invalid */
792 MOD_ACTION_RETURN, /* userlock */
799 MOD_ACTION_RETURN, /* reject */
801 MOD_ACTION_RETURN, /* ok */
802 MOD_ACTION_RETURN, /* handled */
803 MOD_ACTION_RETURN, /* invalid */
804 MOD_ACTION_RETURN, /* userlock */
805 MOD_ACTION_RETURN, /* notfound */
806 MOD_ACTION_RETURN, /* noop */
807 MOD_ACTION_RETURN /* updated */
811 MOD_ACTION_RETURN, /* reject */
813 MOD_ACTION_RETURN, /* ok */
814 MOD_ACTION_RETURN, /* handled */
815 MOD_ACTION_RETURN, /* invalid */
816 MOD_ACTION_RETURN, /* userlock */
818 MOD_ACTION_RETURN, /* noop */
819 MOD_ACTION_RETURN /* updated */
826 MOD_ACTION_RETURN, /* reject */
827 MOD_ACTION_RETURN, /* fail */
829 MOD_ACTION_RETURN, /* handled */
830 MOD_ACTION_RETURN, /* invalid */
831 MOD_ACTION_RETURN, /* userlock */
832 MOD_ACTION_RETURN, /* notfound */
838 MOD_ACTION_RETURN, /* reject */
840 MOD_ACTION_RETURN, /* ok */
841 MOD_ACTION_RETURN, /* handled */
842 MOD_ACTION_RETURN, /* invalid */
843 MOD_ACTION_RETURN, /* userlock */
844 MOD_ACTION_RETURN, /* notfound */
845 MOD_ACTION_RETURN, /* noop */
846 MOD_ACTION_RETURN /* updated */
850 MOD_ACTION_RETURN, /* reject */
852 MOD_ACTION_RETURN, /* ok */
853 MOD_ACTION_RETURN, /* handled */
854 MOD_ACTION_RETURN, /* invalid */
855 MOD_ACTION_RETURN, /* userlock */
857 MOD_ACTION_RETURN, /* noop */
858 MOD_ACTION_RETURN /* updated */
865 MOD_ACTION_RETURN, /* reject */
866 MOD_ACTION_RETURN, /* fail */
868 MOD_ACTION_RETURN, /* handled */
869 MOD_ACTION_RETURN, /* invalid */
870 MOD_ACTION_RETURN, /* userlock */
871 MOD_ACTION_RETURN, /* notfound */
879 MOD_ACTION_RETURN, /* ok */
880 MOD_ACTION_RETURN, /* handled */
889 MOD_ACTION_RETURN, /* reject */
891 MOD_ACTION_RETURN, /* ok */
892 MOD_ACTION_RETURN, /* handled */
893 MOD_ACTION_RETURN, /* invalid */
894 MOD_ACTION_RETURN, /* userlock */
896 MOD_ACTION_RETURN, /* noop */
897 MOD_ACTION_RETURN /* updated */
904 MOD_ACTION_RETURN, /* reject */
906 MOD_ACTION_RETURN, /* ok */
907 MOD_ACTION_RETURN, /* handled */
908 MOD_ACTION_RETURN, /* invalid */
909 MOD_ACTION_RETURN, /* userlock */
910 MOD_ACTION_RETURN, /* notfound */
911 MOD_ACTION_RETURN, /* noop */
912 MOD_ACTION_RETURN /* updated */
916 MOD_ACTION_RETURN, /* reject */
918 MOD_ACTION_RETURN, /* ok */
919 MOD_ACTION_RETURN, /* handled */
920 MOD_ACTION_RETURN, /* invalid */
921 MOD_ACTION_RETURN, /* userlock */
922 MOD_ACTION_RETURN, /* notfound */
923 MOD_ACTION_RETURN, /* noop */
924 MOD_ACTION_RETURN /* updated */
928 MOD_ACTION_RETURN, /* reject */
930 MOD_ACTION_RETURN, /* ok */
931 MOD_ACTION_RETURN, /* handled */
932 MOD_ACTION_RETURN, /* invalid */
933 MOD_ACTION_RETURN, /* userlock */
934 MOD_ACTION_RETURN, /* notfound */
935 MOD_ACTION_RETURN, /* noop */
936 MOD_ACTION_RETURN /* updated */
943 MOD_ACTION_RETURN, /* reject */
944 MOD_ACTION_RETURN, /* fail */
946 MOD_ACTION_RETURN, /* handled */
947 MOD_ACTION_RETURN, /* invalid */
948 MOD_ACTION_RETURN, /* userlock */
955 MOD_ACTION_RETURN, /* reject */
957 MOD_ACTION_RETURN, /* ok */
958 MOD_ACTION_RETURN, /* handled */
959 MOD_ACTION_RETURN, /* invalid */
960 MOD_ACTION_RETURN, /* userlock */
961 MOD_ACTION_RETURN, /* notfound */
962 MOD_ACTION_RETURN, /* noop */
963 MOD_ACTION_RETURN /* updated */
967 MOD_ACTION_RETURN, /* reject */
969 MOD_ACTION_RETURN, /* ok */
970 MOD_ACTION_RETURN, /* handled */
971 MOD_ACTION_RETURN, /* invalid */
972 MOD_ACTION_RETURN, /* userlock */
974 MOD_ACTION_RETURN, /* noop */
975 MOD_ACTION_RETURN /* updated */
982 MOD_ACTION_RETURN, /* reject */
983 MOD_ACTION_RETURN, /* fail */
985 MOD_ACTION_RETURN, /* handled */
986 MOD_ACTION_RETURN, /* invalid */
987 MOD_ACTION_RETURN, /* userlock */
994 MOD_ACTION_RETURN, /* reject */
996 MOD_ACTION_RETURN, /* ok */
997 MOD_ACTION_RETURN, /* handled */
998 MOD_ACTION_RETURN, /* invalid */
999 MOD_ACTION_RETURN, /* userlock */
1000 MOD_ACTION_RETURN, /* notfound */
1001 MOD_ACTION_RETURN, /* noop */
1002 MOD_ACTION_RETURN /* updated */
1006 MOD_ACTION_RETURN, /* reject */
1008 MOD_ACTION_RETURN, /* ok */
1009 MOD_ACTION_RETURN, /* handled */
1010 MOD_ACTION_RETURN, /* invalid */
1011 MOD_ACTION_RETURN, /* userlock */
1013 MOD_ACTION_RETURN, /* noop */
1014 MOD_ACTION_RETURN /* updated */
1021 MOD_ACTION_RETURN, /* reject */
1022 MOD_ACTION_RETURN, /* fail */
1024 MOD_ACTION_RETURN, /* handled */
1025 MOD_ACTION_RETURN, /* invalid */
1026 MOD_ACTION_RETURN, /* userlock */
1033 MOD_ACTION_RETURN, /* reject */
1035 MOD_ACTION_RETURN, /* ok */
1036 MOD_ACTION_RETURN, /* handled */
1037 MOD_ACTION_RETURN, /* invalid */
1038 MOD_ACTION_RETURN, /* userlock */
1039 MOD_ACTION_RETURN, /* notfound */
1040 MOD_ACTION_RETURN, /* noop */
1041 MOD_ACTION_RETURN /* updated */
1045 MOD_ACTION_RETURN, /* reject */
1047 MOD_ACTION_RETURN, /* ok */
1048 MOD_ACTION_RETURN, /* handled */
1049 MOD_ACTION_RETURN, /* invalid */
1050 MOD_ACTION_RETURN, /* userlock */
1052 MOD_ACTION_RETURN, /* noop */
1053 MOD_ACTION_RETURN /* updated */
1059 static modcallable *do_compile_modupdate(modcallable *parent,
1060 int component, CONF_SECTION *cs,
1065 modcallable *csingle;
1067 VALUE_PAIR *head, **tail;
1069 static const char *attrlist_names[] = {
1070 "request", "reply", "proxy-request", "proxy-reply",
1071 "config", "control", NULL
1074 component = component; /* -Wunused */
1076 if (!cf_section_name2(cs)) {
1077 cf_log_err(cf_sectiontoitem(cs),
1078 "Require list name for 'update'.\n");
1082 for (i = 0; attrlist_names[i] != NULL; i++) {
1083 if (strcmp(name2, attrlist_names[i]) == 0) {
1090 cf_log_err(cf_sectiontoitem(cs),
1091 "Unknown attribute list \"%s\"",
1100 * Walk through the children of the update section,
1101 * ensuring that they're all known attributes.
1103 for (ci=cf_item_find_next(cs, NULL);
1105 ci=cf_item_find_next(cs, ci)) {
1109 if (cf_item_is_section(ci)) {
1110 cf_log_err(ci, "\"update\" sections cannot have subsections");
1114 if (!cf_item_is_pair(ci)) continue;
1116 cp = cf_itemtopair(ci); /* can't return NULL */
1117 vp = cf_pairtovp(cp);
1120 cf_log_err(ci, "ERROR: %s", librad_errstr);
1124 if ((vp->operator != T_OP_EQ) &&
1125 (vp->operator != T_OP_ADD) &&
1126 (vp->operator != T_OP_SUB) &&
1127 (vp->operator != T_OP_LE) &&
1128 (vp->operator != T_OP_GE) &&
1129 (vp->operator != T_OP_SET)) {
1131 cf_log_err(ci, "Invalid operator for attribute");
1136 * A few more sanity checks. The enforcement of
1137 * <= or >= can only happen for integer
1140 if ((vp->operator == T_OP_LE) ||
1141 (vp->operator == T_OP_GE)) {
1142 if ((vp->type != PW_TYPE_BYTE) &&
1143 (vp->type != PW_TYPE_SHORT) &&
1144 (vp->type != PW_TYPE_INTEGER)) {
1146 cf_log_err(ci, "Enforcment of <= or >= is possible only for integer attributes");
1156 cf_log_err(cf_sectiontoitem(cs),
1157 "ERROR: update %s section cannot be empty",
1162 g = rad_malloc(sizeof(*g)); /* never fails */
1163 memset(g, 0, sizeof(*g));
1164 csingle = mod_grouptocallable(g);
1166 csingle->parent = parent;
1167 csingle->next = NULL;
1168 csingle->name = name2;
1169 csingle->type = MOD_UPDATE;
1171 g->grouptype = GROUPTYPE_SIMPLE;
1180 static modcallable *do_compile_modswitch(modcallable *parent,
1181 int component, CONF_SECTION *cs)
1183 modcallable *csingle;
1185 int had_seen_default = FALSE;
1187 component = component; /* -Wunused */
1189 if (!cf_section_name2(cs)) {
1190 cf_log_err(cf_sectiontoitem(cs),
1191 "You must specify a variable to switch over for 'switch'.");
1195 if (!cf_item_find_next(cs, NULL)) {
1196 cf_log_err(cf_sectiontoitem(cs), "'switch' statments cannot be empty.");
1201 * Walk through the children of the switch section,
1202 * ensuring that they're all 'case' statements
1204 for (ci=cf_item_find_next(cs, NULL);
1206 ci=cf_item_find_next(cs, ci)) {
1207 CONF_SECTION *subcs;
1208 const char *name1, *name2;
1210 if (!cf_item_is_section(ci)) {
1211 if (!cf_item_is_pair(ci)) continue;
1213 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1217 subcs = cf_itemtosection(ci); /* can't return NULL */
1218 name1 = cf_section_name1(subcs);
1220 if (strcmp(name1, "case") != 0) {
1221 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1225 name2 = cf_section_name2(subcs);
1226 if (!name2 && !had_seen_default) {
1227 had_seen_default = TRUE;
1231 if (!name2 || (name2[0] == '\0')) {
1232 cf_log_err(ci, "\"case\" sections must have a name");
1237 csingle= do_compile_modgroup(parent, component, cs,
1238 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1239 if (!csingle) return NULL;
1240 csingle->type = MOD_SWITCH;
1245 * redundant, etc. can refer to modules or groups, but not much else.
1247 static int all_children_are_modules(CONF_SECTION *cs, const char *name)
1251 for (ci=cf_item_find_next(cs, NULL);
1253 ci=cf_item_find_next(cs, ci)) {
1255 * If we're a redundant, etc. group, then the
1256 * intention is to call modules, rather than
1257 * processing logic. These checks aren't
1258 * *strictly* necessary, but they keep the users
1259 * from doing crazy things.
1261 if (cf_item_is_section(ci)) {
1262 CONF_SECTION *subcs = cf_itemtosection(ci);
1263 const char *name1 = cf_section_name1(subcs);
1265 if ((strcmp(name1, "if") == 0) ||
1266 (strcmp(name1, "else") == 0) ||
1267 (strcmp(name1, "elsif") == 0) ||
1268 (strcmp(name1, "update") == 0) ||
1269 (strcmp(name1, "switch") == 0) ||
1270 (strcmp(name1, "case") == 0)) {
1271 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
1278 if (cf_item_is_pair(ci)) {
1279 CONF_PAIR *cp = cf_itemtopair(ci);
1280 if (cf_pair_value(cp) != NULL) {
1281 cf_log_err(ci, "Invalid entry in %s section");
1292 * Compile one entry of a module call.
1294 static modcallable *do_compile_modsingle(modcallable *parent,
1295 int component, CONF_ITEM *ci,
1297 const char **modname)
1300 const char *modrefname;
1302 modcallable *csingle;
1303 module_instance_t *this;
1304 CONF_SECTION *cs, *subcs;
1306 if (cf_item_is_section(ci)) {
1307 cs = cf_itemtosection(ci);
1308 const char *name2 = cf_section_name2(cs);
1310 modrefname = cf_section_name1(cs);
1311 if (!name2) name2 = "_UnNamedGroup";
1314 * group{}, redundant{}, or append{} may appear
1315 * where a single module instance was expected.
1316 * In that case, we hand it off to
1319 if (strcmp(modrefname, "group") == 0) {
1321 return do_compile_modgroup(parent, component, cs,
1325 } else if (strcmp(modrefname, "redundant") == 0) {
1328 if (!all_children_are_modules(cs, modrefname)) {
1332 return do_compile_modgroup(parent, component, cs,
1333 GROUPTYPE_REDUNDANT,
1336 } else if (strcmp(modrefname, "append") == 0) {
1338 return do_compile_modgroup(parent, component, cs,
1342 } else if (strcmp(modrefname, "load-balance") == 0) {
1345 if (!all_children_are_modules(cs, modrefname)) {
1349 csingle= do_compile_modgroup(parent, component, cs,
1352 if (!csingle) return NULL;
1353 csingle->type = MOD_LOAD_BALANCE;
1356 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1359 if (!all_children_are_modules(cs, modrefname)) {
1363 csingle= do_compile_modgroup(parent, component, cs,
1364 GROUPTYPE_REDUNDANT,
1366 if (!csingle) return NULL;
1367 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1370 } else if (strcmp(modrefname, "if") == 0) {
1371 if (!cf_section_name2(cs)) {
1372 cf_log_err(ci, "'if' without condition.");
1377 csingle= do_compile_modgroup(parent, component, cs,
1380 if (!csingle) return NULL;
1381 csingle->type = MOD_IF;
1383 if (!radius_evaluate_condition(NULL, 0, 0, modname,
1385 modcallable_free(&csingle);
1392 } else if (strcmp(modrefname, "elsif") == 0) {
1394 ((parent->type == MOD_LOAD_BALANCE) ||
1395 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1396 cf_log_err(ci, "'elsif' cannot be used in this section section.");
1400 if (!cf_section_name2(cs)) {
1401 cf_log_err(ci, "'elsif' without condition.");
1406 csingle= do_compile_modgroup(parent, component, cs,
1409 if (!csingle) return NULL;
1410 csingle->type = MOD_ELSIF;
1412 if (!radius_evaluate_condition(NULL, 0, 0, modname,
1414 modcallable_free(&csingle);
1421 } else if (strcmp(modrefname, "else") == 0) {
1423 ((parent->type == MOD_LOAD_BALANCE) ||
1424 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1425 cf_log_err(ci, "'else' cannot be used in this section section.");
1429 if (cf_section_name2(cs)) {
1430 cf_log_err(ci, "Cannot have conditions on 'else'.");
1435 csingle= do_compile_modgroup(parent, component, cs,
1438 if (!csingle) return NULL;
1439 csingle->type = MOD_ELSE;
1442 } else if (strcmp(modrefname, "update") == 0) {
1445 csingle = do_compile_modupdate(parent, component, cs,
1447 if (!csingle) return NULL;
1451 } else if (strcmp(modrefname, "switch") == 0) {
1454 csingle = do_compile_modswitch(parent, component, cs);
1455 if (!csingle) return NULL;
1459 } else if (strcmp(modrefname, "case") == 0) {
1465 * FIXME: How to tell that the parent can only
1466 * be a "switch" statement?
1469 cf_log_err(ci, "\"case\" statements may only appear within a \"switch\" section");
1473 csingle= do_compile_modgroup(parent, component, cs,
1476 if (!csingle) return NULL;
1477 csingle->type = MOD_CASE;
1478 csingle->name = cf_section_name2(cs); /* may be NULL */
1481 * Set all of it's codes to return, so that
1482 * when we pick a 'case' statement, we don't
1483 * fall through to processing the next one.
1485 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1486 csingle->actions[i] = MOD_ACTION_RETURN;
1492 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
1496 * Else it's a module reference, with updated return
1500 CONF_PAIR *cp = cf_itemtopair(ci);
1501 modrefname = cf_pair_attr(cp);
1504 * Actions (ok = 1), etc. are orthoganal to just
1505 * about everything else.
1507 if (cf_pair_value(cp) != NULL) {
1508 cf_log_err(ci, "Entry is not a reference to a module");
1514 * See if the module is a virtual one. If so, return that,
1515 * rather than doing anything here.
1517 if (((cs = cf_section_find("instantiate")) != NULL) &&
1518 (subcs = cf_section_sub_find_name2(cs, NULL, modrefname)) != NULL) {
1519 DEBUG2(" Module: Loading virtual module %s", modrefname);
1522 * As it's sole configuration, the
1523 * virtual module takes a section which
1526 return do_compile_modsingle(parent,
1528 cf_sectiontoitem(subcs),
1534 * Not a virtual module. It must be a real module.
1536 this = find_module_instance(cf_section_find("modules"), modrefname);
1539 cf_log_err(ci, "Failed to find module \"%s\".", modrefname);
1544 * We know it's all OK, allocate the structures, and fill
1547 single = rad_malloc(sizeof(*single));
1548 memset(single, 0, sizeof(*single));
1549 csingle = mod_singletocallable(single);
1550 csingle->parent = parent;
1551 csingle->next = NULL;
1552 memcpy(csingle->actions, defaultactions[component][grouptype],
1553 sizeof csingle->actions);
1554 rad_assert(modrefname != NULL);
1555 csingle->name = modrefname;
1556 csingle->type = MOD_SINGLE;
1559 * Singles can override the actions, virtual modules cannot.
1561 * FIXME: We may want to re-visit how to do this...
1562 * maybe a csingle as a ref?
1564 if (cf_item_is_section(ci)) {
1565 cs = cf_itemtosection(ci);
1567 for (ci=cf_item_find_next(cs, NULL);
1569 ci=cf_item_find_next(cs, ci)) {
1571 if (cf_item_is_section(ci)) {
1572 cf_log_err(ci, "Subsection of module instance call not allowed");
1573 modcallable_free(&csingle);
1577 if (!cf_item_is_pair(ci)) continue;
1579 if (!compile_action(csingle, cf_itemtopair(ci))) {
1580 modcallable_free(&csingle);
1587 * Bail out if the module in question does not supply the
1590 if (!this->entry->module->methods[component]) {
1591 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
1592 comp2str[component]);
1593 modcallable_free(&csingle);
1597 single->modinst = this;
1598 *modname = this->entry->module->name;
1602 modcallable *compile_modsingle(modcallable *parent,
1603 int component, CONF_ITEM *ci,
1604 const char **modname)
1606 modcallable *ret = do_compile_modsingle(parent, component, ci,
1609 dump_tree(component, ret);
1615 * Internal compile group code.
1617 static modcallable *do_compile_modgroup(modcallable *parent,
1618 int component, CONF_SECTION *cs,
1619 int grouptype, int parentgrouptype)
1626 g = rad_malloc(sizeof(*g));
1627 memset(g, 0, sizeof(*g));
1628 g->grouptype = grouptype;
1630 c = mod_grouptocallable(g);
1633 memset(c->actions, 0, sizeof(c->actions));
1636 * Remember the name for printing, etc.
1638 * FIXME: We may also want to put the names into a
1639 * rbtree, so that groups can reference each other...
1641 c->name = cf_section_name2(cs);
1642 if (!c->name) c->name = "";
1643 c->type = MOD_GROUP;
1647 * Loop over the children of this group.
1649 for (ci=cf_item_find_next(cs, NULL);
1651 ci=cf_item_find_next(cs, ci)) {
1654 * Sections are references to other groups, or
1655 * to modules with updated return codes.
1657 if (cf_item_is_section(ci)) {
1658 const char *junk = NULL;
1659 modcallable *single;
1660 CONF_SECTION *subcs = cf_itemtosection(ci);
1662 single = do_compile_modsingle(c, component, ci,
1665 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
1666 cf_section_name1(subcs));
1667 modcallable_free(&c);
1670 add_child(g, single);
1672 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
1676 const char *attr, *value;
1677 CONF_PAIR *cp = cf_itemtopair(ci);
1679 attr = cf_pair_attr(cp);
1680 value = cf_pair_value(cp);
1683 * A CONF_PAIR is either a module
1684 * instance with no actions
1688 modcallable *single;
1689 const char *junk = NULL;
1691 single = do_compile_modsingle(c,
1698 "Failed to parse \"%s\" entry.",
1700 modcallable_free(&c);
1703 add_child(g, single);
1706 * Or a module instance with action.
1708 } else if (!compile_action(c, cp)) {
1709 modcallable_free(&c);
1711 } /* else it worked */
1716 * Set the default actions, if they haven't already been
1719 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1720 if (!c->actions[i]) {
1721 c->actions[i] = defaultactions[component][parentgrouptype][i];
1726 * FIXME: If there are no children, return NULL?
1728 return mod_grouptocallable(g);
1731 modcallable *compile_modgroup(modcallable *parent,
1732 int component, CONF_SECTION *cs)
1734 modcallable *ret = do_compile_modgroup(parent, component, cs,
1737 dump_tree(component, ret);
1741 void add_to_modcallable(modcallable **parent, modcallable *this,
1742 int component, const char *name)
1746 rad_assert(this != NULL);
1748 if (*parent == NULL) {
1751 g = rad_malloc(sizeof *g);
1752 memset(g, 0, sizeof(*g));
1753 g->grouptype = GROUPTYPE_SIMPLE;
1754 c = mod_grouptocallable(g);
1757 defaultactions[component][GROUPTYPE_SIMPLE],
1758 sizeof(c->actions));
1759 rad_assert(name != NULL);
1761 c->type = MOD_GROUP;
1764 *parent = mod_grouptocallable(g);
1766 g = mod_callabletogroup(*parent);
1772 void modcallable_free(modcallable **pc)
1774 modcallable *c, *loop, *next;
1776 if (c->type != MOD_SINGLE) {
1777 modgroup *g = mod_callabletogroup(c);
1779 for(loop = g->children;
1783 modcallable_free(&loop);