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 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, MOD_POLICY } type;
53 int actions[RLM_MODULE_NUMCODES];
56 #define GROUPTYPE_SIMPLE 0
57 #define GROUPTYPE_REDUNDANT 1
58 #define GROUPTYPE_APPEND 2
59 #define GROUPTYPE_COUNT 3
62 modcallable mc; /* self */
63 int grouptype; /* after mc */
64 modcallable *children;
71 module_instance_t *modinst;
74 static const FR_NAME_NUMBER grouptype_table[] = {
75 { "", GROUPTYPE_SIMPLE },
76 { "redundant ", GROUPTYPE_REDUNDANT },
77 { "append ", GROUPTYPE_APPEND },
81 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
82 * so we often want to go back and forth between them. */
83 static modsingle *mod_callabletosingle(modcallable *p)
85 rad_assert(p->type==MOD_SINGLE);
86 return (modsingle *)p;
88 static modgroup *mod_callabletogroup(modcallable *p)
90 rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_POLICY));
94 static modcallable *mod_singletocallable(modsingle *p)
96 return (modcallable *)p;
98 static modcallable *mod_grouptocallable(modgroup *p)
100 return (modcallable *)p;
103 /* modgroups are grown by adding a modcallable to the end */
104 static void add_child(modgroup *g, modcallable *c)
106 modcallable **head = &g->children;
107 modcallable *node = *head;
108 modcallable **last = head;
117 rad_assert(c->next == NULL);
119 c->parent = mod_grouptocallable(g);
122 /* Here's where we recognize all of our keywords: first the rcodes, then the
124 static const FR_NAME_NUMBER rcode_table[] = {
125 { "reject", RLM_MODULE_REJECT },
126 { "fail", RLM_MODULE_FAIL },
127 { "ok", RLM_MODULE_OK },
128 { "handled", RLM_MODULE_HANDLED },
129 { "invalid", RLM_MODULE_INVALID },
130 { "userlock", RLM_MODULE_USERLOCK },
131 { "notfound", RLM_MODULE_NOTFOUND },
132 { "noop", RLM_MODULE_NOOP },
133 { "updated", RLM_MODULE_UPDATED },
139 * Compile action && rcode for later use.
141 static int compile_action(modcallable *c, CONF_PAIR *cp)
144 const char *attr, *value;
146 attr = cf_pair_attr(cp);
147 value = cf_pair_value(cp);
148 if (!value) return 0;
150 if (!strcasecmp(value, "return"))
151 action = MOD_ACTION_RETURN;
153 else if (!strcasecmp(value, "break"))
154 action = MOD_ACTION_RETURN;
156 else if (!strcasecmp(value, "reject"))
157 action = MOD_ACTION_REJECT;
159 else if (strspn(value, "0123456789")==strlen(value)) {
160 action = atoi(value);
163 * Don't allow priority zero, for future use.
165 if (action == 0) return 0;
167 cf_log_err(cf_pairtoitem(cp), "Unknown action '%s'.\n",
172 if (strcasecmp(attr, "default") != 0) {
175 rcode = fr_str2int(rcode_table, attr, -1);
177 cf_log_err(cf_pairtoitem(cp),
178 "Unknown module rcode '%s'.\n",
182 c->actions[rcode] = action;
184 } else { /* set all unset values to the default */
187 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
188 if (!c->actions[i]) c->actions[i] = action;
195 /* Some short names for debugging output */
196 static const char * const comp2str[] = {
207 #ifdef HAVE_PTHREAD_H
209 * Lock the mutex for the module
211 static void safe_lock(module_instance_t *instance)
214 pthread_mutex_lock(instance->mutex);
218 * Unlock the mutex for the module
220 static void safe_unlock(module_instance_t *instance)
223 pthread_mutex_unlock(instance->mutex);
227 * No threads: these functions become NULL's.
229 #define safe_lock(foo)
230 #define safe_unlock(foo)
233 static int call_modsingle(int component, modsingle *sp, REQUEST *request,
236 int myresult = default_result;
238 DEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
239 comp2str[component], sp->modinst->name,
240 sp->modinst->entry->name, request->number);
241 safe_lock(sp->modinst);
244 * For logging unresponsive children.
246 request->module = sp->modinst->name;
248 myresult = sp->modinst->entry->module->methods[component](
249 sp->modinst->insthandle, request);
251 request->module = "<server-core>";
252 safe_unlock(sp->modinst);
253 DEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
254 comp2str[component], sp->modinst->name,
255 sp->modinst->entry->name, request->number);
261 static int default_component_results[RLM_COMPONENT_COUNT] = {
262 RLM_MODULE_REJECT, /* AUTH */
263 RLM_MODULE_NOTFOUND, /* AUTZ */
264 RLM_MODULE_NOOP, /* PREACCT */
265 RLM_MODULE_NOOP, /* ACCT */
266 RLM_MODULE_FAIL, /* SESS */
267 RLM_MODULE_NOOP, /* PRE_PROXY */
268 RLM_MODULE_NOOP, /* POST_PROXY */
269 RLM_MODULE_NOOP /* POST_AUTH */
273 static const char *group_name[] = {
277 "load-balance group",
278 "redundant-load-balance group",
288 static const char *modcall_spaces = "++++++++++++++++++++++++++++++++";
290 #define MODCALL_STACK_MAX (32)
293 * Don't call the modules recursively. Instead, do them
294 * iteratively, and manage the call stack ourselves.
296 typedef struct modcall_stack {
299 int priority[MODCALL_STACK_MAX];
300 int result[MODCALL_STACK_MAX];
301 modcallable *children[MODCALL_STACK_MAX];
302 modcallable *start[MODCALL_STACK_MAX];
307 * Call a module, iteratively, with a local stack, rather than
308 * recursively. What did Paul Graham say about Lisp...?
310 int modcall(int component, modcallable *c, REQUEST *request)
314 modcallable *parent, *child;
316 int if_taken, was_if;
318 if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {
319 return RLM_MODULE_FAIL;
323 stack.priority[0] = 0;
324 stack.children[0] = c;
325 myresult = stack.result[0] = default_component_results[component];
326 was_if = if_taken = FALSE;
330 * A module has taken too long to process the request,
331 * and we've been told to stop processing it.
333 if ((request->master_state == REQUEST_STOP_PROCESSING) ||
335 (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
336 myresult = RLM_MODULE_FAIL;
340 child = stack.children[stack.pointer];
342 myresult = stack.result[stack.pointer];
345 parent = child->parent;
347 if ((child->type == MOD_ELSE) || (child->type == MOD_ELSIF)) {
348 myresult = stack.result[stack.pointer];
350 if (!was_if) { /* error */
351 DEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",
352 stack.pointer + 1, modcall_spaces,
353 group_name[child->type],
358 DEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
359 stack.pointer + 1, modcall_spaces,
360 group_name[child->type],
367 * "if" or "elsif". Evaluate the condition.
369 if ((child->type == MOD_IF) || (child->type == MOD_ELSIF)) {
370 int condition = TRUE;
371 const char *p = child->name;
373 DEBUG2("%.*s? %s %s",
374 stack.pointer + 1, modcall_spaces,
375 (child->type == MOD_IF) ? "if" : "elsif",
378 if (radius_evaluate_condition(request, myresult,
379 0, &p, TRUE, &condition)) {
380 DEBUG2("%.*s? %s %s -> %s",
381 stack.pointer + 1, modcall_spaces,
382 (child->type == MOD_IF) ? "if" : "elsif",
383 child->name, (condition != FALSE) ? "TRUE" : "FALSE");
386 * This should never happen, the
387 * condition is checked when the
388 * module section is loaded.
394 stack.result[stack.pointer] = myresult;
395 stack.children[stack.pointer] = NULL;
399 } /* else process it as a simple group */
402 if (child->type == MOD_UPDATE) {
404 modgroup *g = mod_callabletogroup(child);
406 rcode = radius_update_attrlist(request, g->cs,
407 g->vps, child->name);
408 if (rcode != RLM_MODULE_UPDATED) {
415 * Child is a group that has children of it's own.
417 if (child->type != MOD_SINGLE) {
419 modcallable *p, *q, *null_case;
420 modgroup *g = mod_callabletogroup(child);
425 * Catastrophic error. This SHOULD have
426 * been caught when we were reading in the
431 if (stack.pointer >= MODCALL_STACK_MAX) {
432 radlog(L_ERR, "Internal sanity check failed: module stack is too deep");
436 stack.priority[stack.pointer] = 0;
437 stack.result[stack.pointer] = default_component_results[component];
438 switch (child->type) {
446 case MOD_POLICY: /* same as MOD_GROUP */
447 stack.children[stack.pointer] = g->children;
451 * See the "camel book" for why
454 * If (rand(0..n) < 1), pick the
455 * current realm. We add a scale
456 * factor of 65536, to avoid
459 case MOD_LOAD_BALANCE:
460 case MOD_REDUNDANT_LOAD_BALANCE:
462 for(p = g->children; p; p = p->next) {
471 if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
475 stack.children[stack.pointer] = q;
479 radius_xlat(buffer, sizeof(buffer),
480 child->name, request, NULL);
482 null_case = q = NULL;
483 for(p = g->children; p; p = p->next) {
485 if (!null_case) null_case = p;
488 if (strcmp(buffer, p->name) == 0) {
494 if (!q) q = null_case;
496 stack.children[stack.pointer] = q;
500 DEBUG2("Internal sanity check failed in modcall %d", child->type);
501 exit(1); /* internal sanity check failure */
506 stack.start[stack.pointer] = stack.children[stack.pointer];
508 DEBUG2("%.*s- entering %s %s",
509 stack.pointer, modcall_spaces,
510 group_name[child->type],
511 child->name ? child->name : "");
514 * Catch the special case of a NULL group.
516 if (!stack.children[stack.pointer]) {
518 * Print message for NULL group
520 DEBUG2("%.*s- %s %s returns %s",
521 stack.pointer + 1, modcall_spaces,
522 group_name[child->type],
523 child->name ? child->name : "",
524 fr_int2str(rcode_table,
525 stack.result[stack.pointer],
531 * The child may be a group, so we want to
532 * recurse into it's children, rather than
533 * falling through to the code below.
539 * Process a stand-alone child, and fall through
540 * to dealing with it's parent.
542 sp = mod_callabletosingle(child);
544 myresult = call_modsingle(child->method, sp, request,
545 default_component_results[component]);
547 DEBUG2("%.*s[%s] returns %s",
548 stack.pointer + 1, modcall_spaces,
549 child->name ? child->name : "",
550 fr_int2str(rcode_table, myresult, "??"));
554 * FIXME: Allow modules to push a modcallable
555 * onto this stack. This should simplify
556 * configuration a LOT!
558 * Once we do that, we can't do load-time
559 * checking of the maximum stack depth, and we've
560 * got to cache the stack pointer before storing
563 * Also, if the stack changed, we need to set
564 * children[ptr] to NULL, and process the next
565 * entry on the stack, rather than falling
566 * through to finalize the processing of this
569 * Don't put "myresult" on the stack here,
570 * we have to do so with priority.
574 * We roll back up the stack at this point.
578 * The child's action says return. Do so.
580 if (child->actions[myresult] == MOD_ACTION_RETURN) {
581 stack.result[stack.pointer] = myresult;
582 stack.children[stack.pointer] = NULL;
587 * If "reject", break out of the loop and return
590 if (child->actions[myresult] == MOD_ACTION_REJECT) {
591 stack.children[stack.pointer] = NULL;
592 stack.result[stack.pointer] = RLM_MODULE_REJECT;
597 * Otherwise, the action is a number, the
598 * preference level of this return code. If no
599 * higher preference has been seen yet, remember
602 if (child->actions[myresult] >= stack.priority[stack.pointer]) {
603 stack.result[stack.pointer] = myresult;
604 stack.priority[stack.pointer] = child->actions[myresult];
610 * No parent, we must be done.
613 rad_assert(stack.pointer == 0);
614 myresult = stack.result[0];
618 rad_assert(child != NULL);
621 * Go to the "next" child, whatever that is.
623 switch (parent->type) {
629 case MOD_POLICY: /* same as MOD_GROUP */
630 stack.children[stack.pointer] = child->next;
634 case MOD_LOAD_BALANCE:
635 stack.children[stack.pointer] = NULL;
638 case MOD_REDUNDANT_LOAD_BALANCE:
640 stack.children[stack.pointer] = child->next;
642 modgroup *g = mod_callabletogroup(parent);
644 stack.children[stack.pointer] = g->children;
646 if (stack.children[stack.pointer] == stack.start[stack.pointer]) {
647 stack.children[stack.pointer] = NULL;
651 DEBUG2("Internal sanity check failed in modcall next %d", child->type);
656 * No child, we're done this group, and we return
657 * "myresult" to the caller by pushing it back up
660 if (!stack.children[stack.pointer]) {
662 rad_assert(stack.pointer > 0);
663 myresult = stack.result[stack.pointer];
666 if (stack.pointer == 0) break;
668 DEBUG2("%.*s- %s %s returns %s",
669 stack.pointer + 1, modcall_spaces,
670 group_name[parent->type],
671 parent->name ? parent->name : "",
672 fr_int2str(rcode_table, myresult, "??"));
674 if ((parent->type == MOD_IF) ||
675 (parent->type == MOD_ELSIF)) {
676 if_taken = was_if = TRUE;
678 if_taken = was_if = FALSE;
684 child = stack.children[stack.pointer];
685 parent = child->parent;
689 } /* loop until done */
696 static const char *action2str(int action)
699 if(action==MOD_ACTION_RETURN)
701 if(action==MOD_ACTION_REJECT)
703 snprintf(buf, sizeof buf, "%d", action);
707 /* If you suspect a bug in the parser, you'll want to use these dump
708 * functions. dump_tree should reproduce a whole tree exactly as it was found
709 * in radiusd.conf, but in long form (all actions explicitly defined) */
710 static void dump_mc(modcallable *c, int indent)
714 if(c->type==MOD_SINGLE) {
715 modsingle *single = mod_callabletosingle(c);
716 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
717 single->modinst->name);
719 modgroup *g = mod_callabletogroup(c);
721 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
722 group_name[c->type]);
723 for(p = g->children;p;p = p->next)
724 dump_mc(p, indent+1);
727 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
728 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
729 fr_int2str(rcode_table, i, "??"),
730 action2str(c->actions[i]));
733 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
736 static void dump_tree(int comp, modcallable *c)
738 DEBUG("[%s]", comp2str[comp]);
742 #define dump_tree(a, b)
745 /* These are the default actions. For each component, the group{} block
746 * behaves like the code from the old module_*() function. redundant{} and
747 * append{} are based on my guesses of what they will be used for. --Pac. */
749 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
755 MOD_ACTION_RETURN, /* reject */
757 MOD_ACTION_RETURN, /* ok */
758 MOD_ACTION_RETURN, /* handled */
760 MOD_ACTION_RETURN, /* userlock */
761 MOD_ACTION_RETURN, /* notfound */
767 MOD_ACTION_RETURN, /* reject */
769 MOD_ACTION_RETURN, /* ok */
770 MOD_ACTION_RETURN, /* handled */
771 MOD_ACTION_RETURN, /* invalid */
772 MOD_ACTION_RETURN, /* userlock */
773 MOD_ACTION_RETURN, /* notfound */
774 MOD_ACTION_RETURN, /* noop */
775 MOD_ACTION_RETURN /* updated */
779 MOD_ACTION_RETURN, /* reject */
781 MOD_ACTION_RETURN, /* ok */
782 MOD_ACTION_RETURN, /* handled */
783 MOD_ACTION_RETURN, /* invalid */
784 MOD_ACTION_RETURN, /* userlock */
786 MOD_ACTION_RETURN, /* noop */
787 MOD_ACTION_RETURN /* updated */
794 MOD_ACTION_RETURN, /* reject */
795 MOD_ACTION_RETURN, /* fail */
797 MOD_ACTION_RETURN, /* handled */
798 MOD_ACTION_RETURN, /* invalid */
799 MOD_ACTION_RETURN, /* userlock */
806 MOD_ACTION_RETURN, /* reject */
808 MOD_ACTION_RETURN, /* ok */
809 MOD_ACTION_RETURN, /* handled */
810 MOD_ACTION_RETURN, /* invalid */
811 MOD_ACTION_RETURN, /* userlock */
812 MOD_ACTION_RETURN, /* notfound */
813 MOD_ACTION_RETURN, /* noop */
814 MOD_ACTION_RETURN /* updated */
818 MOD_ACTION_RETURN, /* reject */
820 MOD_ACTION_RETURN, /* ok */
821 MOD_ACTION_RETURN, /* handled */
822 MOD_ACTION_RETURN, /* invalid */
823 MOD_ACTION_RETURN, /* userlock */
825 MOD_ACTION_RETURN, /* noop */
826 MOD_ACTION_RETURN /* updated */
833 MOD_ACTION_RETURN, /* reject */
834 MOD_ACTION_RETURN, /* fail */
836 MOD_ACTION_RETURN, /* handled */
837 MOD_ACTION_RETURN, /* invalid */
838 MOD_ACTION_RETURN, /* userlock */
839 MOD_ACTION_RETURN, /* notfound */
845 MOD_ACTION_RETURN, /* reject */
847 MOD_ACTION_RETURN, /* ok */
848 MOD_ACTION_RETURN, /* handled */
849 MOD_ACTION_RETURN, /* invalid */
850 MOD_ACTION_RETURN, /* userlock */
851 MOD_ACTION_RETURN, /* notfound */
852 MOD_ACTION_RETURN, /* noop */
853 MOD_ACTION_RETURN /* updated */
857 MOD_ACTION_RETURN, /* reject */
859 MOD_ACTION_RETURN, /* ok */
860 MOD_ACTION_RETURN, /* handled */
861 MOD_ACTION_RETURN, /* invalid */
862 MOD_ACTION_RETURN, /* userlock */
864 MOD_ACTION_RETURN, /* noop */
865 MOD_ACTION_RETURN /* updated */
872 MOD_ACTION_RETURN, /* reject */
873 MOD_ACTION_RETURN, /* fail */
875 MOD_ACTION_RETURN, /* handled */
876 MOD_ACTION_RETURN, /* invalid */
877 MOD_ACTION_RETURN, /* userlock */
878 MOD_ACTION_RETURN, /* notfound */
886 MOD_ACTION_RETURN, /* ok */
887 MOD_ACTION_RETURN, /* handled */
896 MOD_ACTION_RETURN, /* reject */
898 MOD_ACTION_RETURN, /* ok */
899 MOD_ACTION_RETURN, /* handled */
900 MOD_ACTION_RETURN, /* invalid */
901 MOD_ACTION_RETURN, /* userlock */
903 MOD_ACTION_RETURN, /* noop */
904 MOD_ACTION_RETURN /* updated */
911 MOD_ACTION_RETURN, /* reject */
913 MOD_ACTION_RETURN, /* ok */
914 MOD_ACTION_RETURN, /* handled */
915 MOD_ACTION_RETURN, /* invalid */
916 MOD_ACTION_RETURN, /* userlock */
917 MOD_ACTION_RETURN, /* notfound */
918 MOD_ACTION_RETURN, /* noop */
919 MOD_ACTION_RETURN /* updated */
923 MOD_ACTION_RETURN, /* reject */
925 MOD_ACTION_RETURN, /* ok */
926 MOD_ACTION_RETURN, /* handled */
927 MOD_ACTION_RETURN, /* invalid */
928 MOD_ACTION_RETURN, /* userlock */
929 MOD_ACTION_RETURN, /* notfound */
930 MOD_ACTION_RETURN, /* noop */
931 MOD_ACTION_RETURN /* updated */
935 MOD_ACTION_RETURN, /* reject */
937 MOD_ACTION_RETURN, /* ok */
938 MOD_ACTION_RETURN, /* handled */
939 MOD_ACTION_RETURN, /* invalid */
940 MOD_ACTION_RETURN, /* userlock */
941 MOD_ACTION_RETURN, /* notfound */
942 MOD_ACTION_RETURN, /* noop */
943 MOD_ACTION_RETURN /* updated */
950 MOD_ACTION_RETURN, /* reject */
951 MOD_ACTION_RETURN, /* fail */
953 MOD_ACTION_RETURN, /* handled */
954 MOD_ACTION_RETURN, /* invalid */
955 MOD_ACTION_RETURN, /* userlock */
962 MOD_ACTION_RETURN, /* reject */
964 MOD_ACTION_RETURN, /* ok */
965 MOD_ACTION_RETURN, /* handled */
966 MOD_ACTION_RETURN, /* invalid */
967 MOD_ACTION_RETURN, /* userlock */
968 MOD_ACTION_RETURN, /* notfound */
969 MOD_ACTION_RETURN, /* noop */
970 MOD_ACTION_RETURN /* updated */
974 MOD_ACTION_RETURN, /* reject */
976 MOD_ACTION_RETURN, /* ok */
977 MOD_ACTION_RETURN, /* handled */
978 MOD_ACTION_RETURN, /* invalid */
979 MOD_ACTION_RETURN, /* userlock */
981 MOD_ACTION_RETURN, /* noop */
982 MOD_ACTION_RETURN /* updated */
989 MOD_ACTION_RETURN, /* reject */
990 MOD_ACTION_RETURN, /* fail */
992 MOD_ACTION_RETURN, /* handled */
993 MOD_ACTION_RETURN, /* invalid */
994 MOD_ACTION_RETURN, /* userlock */
1001 MOD_ACTION_RETURN, /* reject */
1003 MOD_ACTION_RETURN, /* ok */
1004 MOD_ACTION_RETURN, /* handled */
1005 MOD_ACTION_RETURN, /* invalid */
1006 MOD_ACTION_RETURN, /* userlock */
1007 MOD_ACTION_RETURN, /* notfound */
1008 MOD_ACTION_RETURN, /* noop */
1009 MOD_ACTION_RETURN /* updated */
1013 MOD_ACTION_RETURN, /* reject */
1015 MOD_ACTION_RETURN, /* ok */
1016 MOD_ACTION_RETURN, /* handled */
1017 MOD_ACTION_RETURN, /* invalid */
1018 MOD_ACTION_RETURN, /* userlock */
1020 MOD_ACTION_RETURN, /* noop */
1021 MOD_ACTION_RETURN /* updated */
1028 MOD_ACTION_RETURN, /* reject */
1029 MOD_ACTION_RETURN, /* fail */
1031 MOD_ACTION_RETURN, /* handled */
1032 MOD_ACTION_RETURN, /* invalid */
1033 MOD_ACTION_RETURN, /* userlock */
1040 MOD_ACTION_RETURN, /* reject */
1042 MOD_ACTION_RETURN, /* ok */
1043 MOD_ACTION_RETURN, /* handled */
1044 MOD_ACTION_RETURN, /* invalid */
1045 MOD_ACTION_RETURN, /* userlock */
1046 MOD_ACTION_RETURN, /* notfound */
1047 MOD_ACTION_RETURN, /* noop */
1048 MOD_ACTION_RETURN /* updated */
1052 MOD_ACTION_RETURN, /* reject */
1054 MOD_ACTION_RETURN, /* ok */
1055 MOD_ACTION_RETURN, /* handled */
1056 MOD_ACTION_RETURN, /* invalid */
1057 MOD_ACTION_RETURN, /* userlock */
1059 MOD_ACTION_RETURN, /* noop */
1060 MOD_ACTION_RETURN /* updated */
1066 static modcallable *do_compile_modupdate(modcallable *parent,
1067 int component, CONF_SECTION *cs,
1072 modcallable *csingle;
1074 VALUE_PAIR *head, **tail;
1076 static const char *attrlist_names[] = {
1077 "request", "reply", "proxy-request", "proxy-reply",
1078 "config", "control",
1079 "outer.request", "outer.reply",
1080 "outer.config", "outer.control",
1084 component = component; /* -Wunused */
1086 if (!cf_section_name2(cs)) {
1087 cf_log_err(cf_sectiontoitem(cs),
1088 "Require list name for 'update'.\n");
1092 for (i = 0; attrlist_names[i] != NULL; i++) {
1093 if (strcmp(name2, attrlist_names[i]) == 0) {
1100 cf_log_err(cf_sectiontoitem(cs),
1101 "Unknown attribute list \"%s\"",
1110 * Walk through the children of the update section,
1111 * ensuring that they're all known attributes.
1113 for (ci=cf_item_find_next(cs, NULL);
1115 ci=cf_item_find_next(cs, ci)) {
1119 if (cf_item_is_section(ci)) {
1120 cf_log_err(ci, "\"update\" sections cannot have subsections");
1124 if (!cf_item_is_pair(ci)) continue;
1126 cp = cf_itemtopair(ci); /* can't return NULL */
1127 vp = cf_pairtovp(cp);
1130 cf_log_err(ci, "ERROR: %s", librad_errstr);
1134 if ((vp->operator != T_OP_EQ) &&
1135 (vp->operator != T_OP_CMP_EQ) &&
1136 (vp->operator != T_OP_ADD) &&
1137 (vp->operator != T_OP_SUB) &&
1138 (vp->operator != T_OP_LE) &&
1139 (vp->operator != T_OP_GE) &&
1140 (vp->operator != T_OP_SET)) {
1143 cf_log_err(ci, "Invalid operator for attribute");
1148 * A few more sanity checks. The enforcement of
1149 * <= or >= can only happen for integer
1152 if ((vp->operator == T_OP_LE) ||
1153 (vp->operator == T_OP_GE)) {
1154 if ((vp->type != PW_TYPE_BYTE) &&
1155 (vp->type != PW_TYPE_SHORT) &&
1156 (vp->type != PW_TYPE_INTEGER)) {
1159 cf_log_err(ci, "Enforcment of <= or >= is possible only for integer attributes");
1169 cf_log_err(cf_sectiontoitem(cs),
1170 "ERROR: update %s section cannot be empty",
1175 g = rad_malloc(sizeof(*g)); /* never fails */
1176 memset(g, 0, sizeof(*g));
1177 csingle = mod_grouptocallable(g);
1179 csingle->parent = parent;
1180 csingle->next = NULL;
1181 csingle->name = name2;
1182 csingle->type = MOD_UPDATE;
1183 csingle->method = component;
1185 g->grouptype = GROUPTYPE_SIMPLE;
1194 static modcallable *do_compile_modswitch(modcallable *parent,
1195 int component, CONF_SECTION *cs)
1197 modcallable *csingle;
1199 int had_seen_default = FALSE;
1201 component = component; /* -Wunused */
1203 if (!cf_section_name2(cs)) {
1204 cf_log_err(cf_sectiontoitem(cs),
1205 "You must specify a variable to switch over for 'switch'.");
1209 if (!cf_item_find_next(cs, NULL)) {
1210 cf_log_err(cf_sectiontoitem(cs), "'switch' statments cannot be empty.");
1215 * Walk through the children of the switch section,
1216 * ensuring that they're all 'case' statements
1218 for (ci=cf_item_find_next(cs, NULL);
1220 ci=cf_item_find_next(cs, ci)) {
1221 CONF_SECTION *subcs;
1222 const char *name1, *name2;
1224 if (!cf_item_is_section(ci)) {
1225 if (!cf_item_is_pair(ci)) continue;
1227 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1231 subcs = cf_itemtosection(ci); /* can't return NULL */
1232 name1 = cf_section_name1(subcs);
1234 if (strcmp(name1, "case") != 0) {
1235 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1239 name2 = cf_section_name2(subcs);
1240 if (!name2 && !had_seen_default) {
1241 had_seen_default = TRUE;
1245 if (!name2 || (name2[0] == '\0')) {
1246 cf_log_err(ci, "\"case\" sections must have a name");
1251 csingle= do_compile_modgroup(parent, component, cs,
1252 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1253 if (!csingle) return NULL;
1254 csingle->type = MOD_SWITCH;
1259 * redundant, etc. can refer to modules or groups, but not much else.
1261 static int all_children_are_modules(CONF_SECTION *cs, const char *name)
1265 for (ci=cf_item_find_next(cs, NULL);
1267 ci=cf_item_find_next(cs, ci)) {
1269 * If we're a redundant, etc. group, then the
1270 * intention is to call modules, rather than
1271 * processing logic. These checks aren't
1272 * *strictly* necessary, but they keep the users
1273 * from doing crazy things.
1275 if (cf_item_is_section(ci)) {
1276 CONF_SECTION *subcs = cf_itemtosection(ci);
1277 const char *name1 = cf_section_name1(subcs);
1279 if ((strcmp(name1, "if") == 0) ||
1280 (strcmp(name1, "else") == 0) ||
1281 (strcmp(name1, "elsif") == 0) ||
1282 (strcmp(name1, "update") == 0) ||
1283 (strcmp(name1, "switch") == 0) ||
1284 (strcmp(name1, "case") == 0)) {
1285 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
1292 if (cf_item_is_pair(ci)) {
1293 CONF_PAIR *cp = cf_itemtopair(ci);
1294 if (cf_pair_value(cp) != NULL) {
1295 cf_log_err(ci, "Invalid entry in %s section");
1306 * Compile one entry of a module call.
1308 static modcallable *do_compile_modsingle(modcallable *parent,
1309 int component, CONF_ITEM *ci,
1311 const char **modname)
1314 const char *modrefname;
1316 modcallable *csingle;
1317 module_instance_t *this;
1318 CONF_SECTION *cs, *subcs, *modules;
1320 if (cf_item_is_section(ci)) {
1323 cs = cf_itemtosection(ci);
1324 modrefname = cf_section_name1(cs);
1325 name2 = cf_section_name2(cs);
1326 if (!name2) name2 = "_UnNamedGroup";
1329 * group{}, redundant{}, or append{} may appear
1330 * where a single module instance was expected.
1331 * In that case, we hand it off to
1334 if (strcmp(modrefname, "group") == 0) {
1336 return do_compile_modgroup(parent, component, cs,
1340 } else if (strcmp(modrefname, "redundant") == 0) {
1343 if (!all_children_are_modules(cs, modrefname)) {
1347 return do_compile_modgroup(parent, component, cs,
1348 GROUPTYPE_REDUNDANT,
1351 } else if (strcmp(modrefname, "append") == 0) {
1353 return do_compile_modgroup(parent, component, cs,
1357 } else if (strcmp(modrefname, "load-balance") == 0) {
1360 if (!all_children_are_modules(cs, modrefname)) {
1364 csingle= do_compile_modgroup(parent, component, cs,
1367 if (!csingle) return NULL;
1368 csingle->type = MOD_LOAD_BALANCE;
1371 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1374 if (!all_children_are_modules(cs, modrefname)) {
1378 csingle= do_compile_modgroup(parent, component, cs,
1379 GROUPTYPE_REDUNDANT,
1381 if (!csingle) return NULL;
1382 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1385 } else if (strcmp(modrefname, "if") == 0) {
1386 if (!cf_section_name2(cs)) {
1387 cf_log_err(ci, "'if' without condition.");
1392 csingle= do_compile_modgroup(parent, component, cs,
1395 if (!csingle) return NULL;
1396 csingle->type = MOD_IF;
1398 if (!radius_evaluate_condition(NULL, 0, 0, modname,
1400 modcallable_free(&csingle);
1407 } else if (strcmp(modrefname, "elsif") == 0) {
1409 ((parent->type == MOD_LOAD_BALANCE) ||
1410 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1411 cf_log_err(ci, "'elsif' cannot be used in this section section.");
1415 if (!cf_section_name2(cs)) {
1416 cf_log_err(ci, "'elsif' without condition.");
1421 csingle= do_compile_modgroup(parent, component, cs,
1424 if (!csingle) return NULL;
1425 csingle->type = MOD_ELSIF;
1427 if (!radius_evaluate_condition(NULL, 0, 0, modname,
1429 modcallable_free(&csingle);
1436 } else if (strcmp(modrefname, "else") == 0) {
1438 ((parent->type == MOD_LOAD_BALANCE) ||
1439 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1440 cf_log_err(ci, "'else' cannot be used in this section section.");
1444 if (cf_section_name2(cs)) {
1445 cf_log_err(ci, "Cannot have conditions on 'else'.");
1450 csingle= do_compile_modgroup(parent, component, cs,
1453 if (!csingle) return NULL;
1454 csingle->type = MOD_ELSE;
1457 } else if (strcmp(modrefname, "update") == 0) {
1460 csingle = do_compile_modupdate(parent, component, cs,
1462 if (!csingle) return NULL;
1466 } else if (strcmp(modrefname, "switch") == 0) {
1469 csingle = do_compile_modswitch(parent, component, cs);
1470 if (!csingle) return NULL;
1474 } else if (strcmp(modrefname, "case") == 0) {
1480 * FIXME: How to tell that the parent can only
1481 * be a "switch" statement?
1484 cf_log_err(ci, "\"case\" statements may only appear within a \"switch\" section");
1488 csingle= do_compile_modgroup(parent, component, cs,
1491 if (!csingle) return NULL;
1492 csingle->type = MOD_CASE;
1493 csingle->name = cf_section_name2(cs); /* may be NULL */
1496 * Set all of it's codes to return, so that
1497 * when we pick a 'case' statement, we don't
1498 * fall through to processing the next one.
1500 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1501 csingle->actions[i] = MOD_ACTION_RETURN;
1506 } /* else it's something like sql { fail = 1 ...} */
1508 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
1512 * Else it's a module reference, with updated return
1516 CONF_PAIR *cp = cf_itemtopair(ci);
1517 modrefname = cf_pair_attr(cp);
1520 * Actions (ok = 1), etc. are orthoganal to just
1521 * about everything else.
1523 if (cf_pair_value(cp) != NULL) {
1524 cf_log_err(ci, "Entry is not a reference to a module");
1529 * See if the module is a virtual one. If so,
1530 * return that, rather than doing anything here.
1533 cs = cf_section_find("instantiate");
1535 cs = cf_section_find("policy");
1536 if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
1540 DEBUG2(" Module: Loading virtual module %s",
1544 * redundant foo {} is a single.
1546 if (cf_section_name2(subcs)) {
1547 return do_compile_modsingle(parent,
1549 cf_sectiontoitem(subcs),
1554 * foo {} is a group.
1556 return do_compile_modgroup(parent,
1566 * Not a virtual module. It must be a real module.
1568 modules = cf_section_find("modules");
1571 if (modules && cf_section_sub_find_name2(modules, NULL, modrefname)) {
1572 this = find_module_instance(modules, modrefname);
1580 * Maybe it's module.method
1582 p = strchr(modrefname, '.');
1583 if (p) for (i = RLM_COMPONENT_AUTH;
1584 i < RLM_COMPONENT_COUNT;
1586 if (strcmp(p + 1, comp2str[i]) == 0) {
1589 strlcpy(buffer, modrefname, sizeof(buffer));
1590 buffer[p - modrefname] = '\0';
1593 this = find_module_instance(cf_section_find("modules"), buffer);
1595 !this->entry->module->methods[i]) {
1597 cf_log_err(ci, "Module %s has no such method %s", buffer, comp2str[i]);
1606 cf_log_err(ci, "Failed to find module \"%s\".", modrefname);
1612 * We know it's all OK, allocate the structures, and fill
1615 single = rad_malloc(sizeof(*single));
1616 memset(single, 0, sizeof(*single));
1617 csingle = mod_singletocallable(single);
1618 csingle->parent = parent;
1619 csingle->next = NULL;
1620 memcpy(csingle->actions, defaultactions[component][grouptype],
1621 sizeof csingle->actions);
1622 rad_assert(modrefname != NULL);
1623 csingle->name = modrefname;
1624 csingle->type = MOD_SINGLE;
1625 csingle->method = component;
1628 * Singles can override the actions, virtual modules cannot.
1630 * FIXME: We may want to re-visit how to do this...
1631 * maybe a csingle as a ref?
1633 if (cf_item_is_section(ci)) {
1634 cs = cf_itemtosection(ci);
1636 for (ci=cf_item_find_next(cs, NULL);
1638 ci=cf_item_find_next(cs, ci)) {
1640 if (cf_item_is_section(ci)) {
1641 cf_log_err(ci, "Subsection of module instance call not allowed");
1642 modcallable_free(&csingle);
1646 if (!cf_item_is_pair(ci)) continue;
1648 if (!compile_action(csingle, cf_itemtopair(ci))) {
1649 modcallable_free(&csingle);
1656 * Bail out if the module in question does not supply the
1659 if (!this->entry->module->methods[component]) {
1660 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
1661 comp2str[component]);
1662 modcallable_free(&csingle);
1666 single->modinst = this;
1667 *modname = this->entry->module->name;
1671 modcallable *compile_modsingle(modcallable *parent,
1672 int component, CONF_ITEM *ci,
1673 const char **modname)
1675 modcallable *ret = do_compile_modsingle(parent, component, ci,
1678 dump_tree(component, ret);
1684 * Internal compile group code.
1686 static modcallable *do_compile_modgroup(modcallable *parent,
1687 int component, CONF_SECTION *cs,
1688 int grouptype, int parentgrouptype)
1695 g = rad_malloc(sizeof(*g));
1696 memset(g, 0, sizeof(*g));
1697 g->grouptype = grouptype;
1699 c = mod_grouptocallable(g);
1701 c->type = MOD_GROUP;
1703 memset(c->actions, 0, sizeof(c->actions));
1706 * Remember the name for printing, etc.
1708 * FIXME: We may also want to put the names into a
1709 * rbtree, so that groups can reference each other...
1711 c->name = cf_section_name2(cs);
1713 c->name = cf_section_name1(cs);
1714 if (strcmp(c->name, "group") == 0) {
1717 c->type = MOD_POLICY;
1723 * Loop over the children of this group.
1725 for (ci=cf_item_find_next(cs, NULL);
1727 ci=cf_item_find_next(cs, ci)) {
1730 * Sections are references to other groups, or
1731 * to modules with updated return codes.
1733 if (cf_item_is_section(ci)) {
1734 const char *junk = NULL;
1735 modcallable *single;
1736 CONF_SECTION *subcs = cf_itemtosection(ci);
1738 single = do_compile_modsingle(c, component, ci,
1741 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
1742 cf_section_name1(subcs));
1743 modcallable_free(&c);
1746 add_child(g, single);
1748 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
1752 const char *attr, *value;
1753 CONF_PAIR *cp = cf_itemtopair(ci);
1755 attr = cf_pair_attr(cp);
1756 value = cf_pair_value(cp);
1759 * A CONF_PAIR is either a module
1760 * instance with no actions
1764 modcallable *single;
1765 const char *junk = NULL;
1767 single = do_compile_modsingle(c,
1774 "Failed to parse \"%s\" entry.",
1776 modcallable_free(&c);
1779 add_child(g, single);
1782 * Or a module instance with action.
1784 } else if (!compile_action(c, cp)) {
1785 modcallable_free(&c);
1787 } /* else it worked */
1792 * Set the default actions, if they haven't already been
1795 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1796 if (!c->actions[i]) {
1797 c->actions[i] = defaultactions[component][parentgrouptype][i];
1802 * FIXME: If there are no children, return NULL?
1804 return mod_grouptocallable(g);
1807 modcallable *compile_modgroup(modcallable *parent,
1808 int component, CONF_SECTION *cs)
1810 modcallable *ret = do_compile_modgroup(parent, component, cs,
1813 dump_tree(component, ret);
1817 void add_to_modcallable(modcallable **parent, modcallable *this,
1818 int component, const char *name)
1822 rad_assert(this != NULL);
1824 if (*parent == NULL) {
1827 g = rad_malloc(sizeof *g);
1828 memset(g, 0, sizeof(*g));
1829 g->grouptype = GROUPTYPE_SIMPLE;
1830 c = mod_grouptocallable(g);
1833 defaultactions[component][GROUPTYPE_SIMPLE],
1834 sizeof(c->actions));
1835 rad_assert(name != NULL);
1837 c->type = MOD_GROUP;
1838 c->method = component;
1841 *parent = mod_grouptocallable(g);
1843 g = mod_callabletogroup(*parent);
1849 void modcallable_free(modcallable **pc)
1851 modcallable *c, *loop, *next;
1853 if (c->type != MOD_SINGLE) {
1854 modgroup *g = mod_callabletogroup(c);
1856 for(loop = g->children;
1860 modcallable_free(&loop);