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,
53 MOD_IF, MOD_ELSE, MOD_ELSIF, MOD_UPDATE, MOD_SWITCH, MOD_CASE,
56 MOD_POLICY, MOD_REFERENCE, MOD_XLAT } type;
58 int actions[RLM_MODULE_NUMCODES];
61 #define GROUPTYPE_SIMPLE 0
62 #define GROUPTYPE_REDUNDANT 1
63 #define GROUPTYPE_APPEND 2
64 #define GROUPTYPE_COUNT 3
67 modcallable mc; /* self */
68 int grouptype; /* after mc */
69 modcallable *children;
76 module_instance_t *modinst;
91 static const FR_NAME_NUMBER grouptype_table[] = {
92 { "", GROUPTYPE_SIMPLE },
93 { "redundant ", GROUPTYPE_REDUNDANT },
94 { "append ", GROUPTYPE_APPEND },
98 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
99 * so we often want to go back and forth between them. */
100 static modsingle *mod_callabletosingle(modcallable *p)
102 rad_assert(p->type==MOD_SINGLE);
103 return (modsingle *)p;
105 static modgroup *mod_callabletogroup(modcallable *p)
107 rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_POLICY));
109 return (modgroup *)p;
111 static modcallable *mod_singletocallable(modsingle *p)
113 return (modcallable *)p;
115 static modcallable *mod_grouptocallable(modgroup *p)
117 return (modcallable *)p;
120 static modref *mod_callabletoref(modcallable *p)
122 rad_assert(p->type==MOD_REFERENCE);
125 static modcallable *mod_reftocallable(modref *p)
127 return (modcallable *)p;
130 static modxlat *mod_callabletoxlat(modcallable *p)
132 rad_assert(p->type==MOD_XLAT);
135 static modcallable *mod_xlattocallable(modxlat *p)
137 return (modcallable *)p;
140 /* modgroups are grown by adding a modcallable to the end */
141 /* FIXME: This is O(N^2) */
142 static void add_child(modgroup *g, modcallable *c)
144 modcallable **head = &g->children;
145 modcallable *node = *head;
146 modcallable **last = head;
155 rad_assert(c->next == NULL);
157 c->parent = mod_grouptocallable(g);
160 /* Here's where we recognize all of our keywords: first the rcodes, then the
162 static const FR_NAME_NUMBER rcode_table[] = {
163 { "reject", RLM_MODULE_REJECT },
164 { "fail", RLM_MODULE_FAIL },
165 { "ok", RLM_MODULE_OK },
166 { "handled", RLM_MODULE_HANDLED },
167 { "invalid", RLM_MODULE_INVALID },
168 { "userlock", RLM_MODULE_USERLOCK },
169 { "notfound", RLM_MODULE_NOTFOUND },
170 { "noop", RLM_MODULE_NOOP },
171 { "updated", RLM_MODULE_UPDATED },
177 * Compile action && rcode for later use.
179 static int compile_action(modcallable *c, CONF_PAIR *cp)
182 const char *attr, *value;
184 attr = cf_pair_attr(cp);
185 value = cf_pair_value(cp);
186 if (!value) return 0;
188 if (!strcasecmp(value, "return"))
189 action = MOD_ACTION_RETURN;
191 else if (!strcasecmp(value, "break"))
192 action = MOD_ACTION_RETURN;
194 else if (!strcasecmp(value, "reject"))
195 action = MOD_ACTION_REJECT;
197 else if (strspn(value, "0123456789")==strlen(value)) {
198 action = atoi(value);
201 * Don't allow priority zero, for future use.
203 if (action == 0) return 0;
205 cf_log_err(cf_pairtoitem(cp), "Unknown action '%s'.\n",
210 if (strcasecmp(attr, "default") != 0) {
213 rcode = fr_str2int(rcode_table, attr, -1);
215 cf_log_err(cf_pairtoitem(cp),
216 "Unknown module rcode '%s'.\n",
220 c->actions[rcode] = action;
222 } else { /* set all unset values to the default */
225 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
226 if (!c->actions[i]) c->actions[i] = action;
233 /* Some short names for debugging output */
234 static const char * const comp2str[] = {
250 #ifdef HAVE_PTHREAD_H
252 * Lock the mutex for the module
254 static void safe_lock(module_instance_t *instance)
257 pthread_mutex_lock(instance->mutex);
261 * Unlock the mutex for the module
263 static void safe_unlock(module_instance_t *instance)
266 pthread_mutex_unlock(instance->mutex);
270 * No threads: these functions become NULL's.
272 #define safe_lock(foo)
273 #define safe_unlock(foo)
276 static int call_modsingle(int component, modsingle *sp, REQUEST *request)
280 rad_assert(request != NULL);
282 RDEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
283 comp2str[component], sp->modinst->name,
284 sp->modinst->entry->name, request->number);
286 if (sp->modinst->dead) {
287 myresult = RLM_MODULE_FAIL;
291 safe_lock(sp->modinst);
294 * For logging unresponsive children.
296 request->module = sp->modinst->name;
298 myresult = sp->modinst->entry->module->methods[component](
299 sp->modinst->insthandle, request);
301 request->module = "";
302 safe_unlock(sp->modinst);
305 RDEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
306 comp2str[component], sp->modinst->name,
307 sp->modinst->entry->name, request->number);
313 static int default_component_results[RLM_COMPONENT_COUNT] = {
314 RLM_MODULE_REJECT, /* AUTH */
315 RLM_MODULE_NOTFOUND, /* AUTZ */
316 RLM_MODULE_NOOP, /* PREACCT */
317 RLM_MODULE_NOOP, /* ACCT */
318 RLM_MODULE_FAIL, /* SESS */
319 RLM_MODULE_NOOP, /* PRE_PROXY */
320 RLM_MODULE_NOOP, /* POST_PROXY */
321 RLM_MODULE_NOOP /* POST_AUTH */
324 RLM_MODULE_NOOP, /* RECV_COA_TYPE */
325 RLM_MODULE_NOOP /* SEND_COA_TYPE */
330 static const char *group_name[] = {
334 "load-balance group",
335 "redundant-load-balance group",
348 static const char *modcall_spaces = "++++++++++++++++++++++++++++++++";
350 #define MODCALL_STACK_MAX (32)
353 * Don't call the modules recursively. Instead, do them
354 * iteratively, and manage the call stack ourselves.
356 typedef struct modcall_stack {
359 int priority[MODCALL_STACK_MAX];
360 int result[MODCALL_STACK_MAX];
361 modcallable *children[MODCALL_STACK_MAX];
362 modcallable *start[MODCALL_STACK_MAX];
367 * Call a module, iteratively, with a local stack, rather than
368 * recursively. What did Paul Graham say about Lisp...?
370 int modcall(int component, modcallable *c, REQUEST *request)
374 modcallable *parent, *child;
376 int if_taken, was_if;
378 if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {
379 return RLM_MODULE_FAIL;
383 stack.priority[0] = 0;
384 stack.children[0] = c;
385 stack.start[0] = NULL;
386 myresult = stack.result[0] = default_component_results[component];
387 was_if = if_taken = FALSE;
391 * A module has taken too long to process the request,
392 * and we've been told to stop processing it.
394 if ((request->master_state == REQUEST_STOP_PROCESSING) ||
396 (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
397 myresult = RLM_MODULE_FAIL;
401 child = stack.children[stack.pointer];
403 myresult = stack.result[stack.pointer];
406 parent = child->parent;
409 if ((child->type == MOD_ELSE) || (child->type == MOD_ELSIF)) {
410 myresult = stack.result[stack.pointer];
412 if (!was_if) { /* error */
413 RDEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",
414 stack.pointer + 1, modcall_spaces,
415 group_name[child->type],
420 RDEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
421 stack.pointer + 1, modcall_spaces,
422 group_name[child->type],
429 * "if" or "elsif". Evaluate the condition.
431 if ((child->type == MOD_IF) || (child->type == MOD_ELSIF)) {
432 int condition = TRUE;
433 const char *p = child->name;
435 RDEBUG2("%.*s? %s %s",
436 stack.pointer + 1, modcall_spaces,
437 (child->type == MOD_IF) ? "if" : "elsif",
440 if (radius_evaluate_condition(request, myresult,
441 0, &p, TRUE, &condition)) {
442 RDEBUG2("%.*s? %s %s -> %s",
443 stack.pointer + 1, modcall_spaces,
444 (child->type == MOD_IF) ? "if" : "elsif",
445 child->name, (condition != FALSE) ? "TRUE" : "FALSE");
448 * This should never happen, the
449 * condition is checked when the
450 * module section is loaded.
456 stack.result[stack.pointer] = myresult;
457 stack.children[stack.pointer] = NULL;
461 } /* else process it as a simple group */
464 if (child->type == MOD_UPDATE) {
466 modgroup *g = mod_callabletogroup(child);
468 rcode = radius_update_attrlist(request, g->cs,
469 g->vps, child->name);
470 if (rcode != RLM_MODULE_UPDATED) {
474 * FIXME: Set priority based on
475 * previous priority, so that we
476 * don't stop on reject when the
477 * default priority was to
485 if (child->type == MOD_FOREACH) {
488 modgroup *g = mod_callabletogroup(child);
490 for (i = 0; i < 8; i++) {
491 if (!request_data_get(request, radius_get_vp, i)) {
498 RDEBUG("ERROR: Foreach Nesting too deep!");
499 myresult = RLM_MODULE_FAIL;
503 if (radius_get_vp(request, child->name, &vp)) {
504 RDEBUG2("Foreach %s", child->name);
506 request_data_add(request, modcall,
509 myresult = modcall(component,
512 if (myresult == MOD_ACTION_RETURN) {
513 myresult = RLM_MODULE_OK;
516 vp = pairfind(vp->next,
522 * Delete the cached attribute.
524 request_data_get(request, radius_get_vp, depth);
527 myresult = RLM_MODULE_OK;
532 if (child->type == MOD_REFERENCE) {
533 modref *mr = mod_callabletoref(child);
534 const char *server = request->server;
536 if (server == mr->ref_name) {
537 RDEBUG("WARNING: Suppressing recursive call to server %s", server);
538 myresult = RLM_MODULE_NOOP;
542 request->server = mr->ref_name;
543 RDEBUG("server %s { # nested call", mr->ref_name);
544 myresult = indexed_modcall(component, 0, request);
545 RDEBUG("} # server %s with nested call", mr->ref_name);
546 request->server = server;
550 if (child->type == MOD_XLAT) {
551 modxlat *mx = mod_callabletoxlat(child);
555 radius_xlat(buffer, sizeof(buffer),
556 mx->xlat_name, request, NULL);
558 RDEBUG("`%s`", mx->xlat_name);
559 radius_exec_program(mx->xlat_name, request,
561 request->packet->vps,
569 * Child is a group that has children of it's own.
571 if (child->type != MOD_SINGLE) {
575 modcallable *null_case;
577 modgroup *g = mod_callabletogroup(child);
582 * Catastrophic error. This SHOULD have
583 * been caught when we were reading in the
588 if (stack.pointer >= MODCALL_STACK_MAX) {
589 radlog(L_ERR, "Internal sanity check failed: module stack is too deep");
593 stack.priority[stack.pointer] = 0;
594 stack.result[stack.pointer] = default_component_results[component];
595 switch (child->type) {
606 case MOD_POLICY: /* same as MOD_GROUP */
607 stack.children[stack.pointer] = g->children;
611 * See the "camel book" for why
614 * If (rand(0..n) < 1), pick the
615 * current realm. We add a scale
616 * factor of 65536, to avoid
619 case MOD_LOAD_BALANCE:
620 case MOD_REDUNDANT_LOAD_BALANCE:
622 for(p = g->children; p; p = p->next) {
631 if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
635 stack.children[stack.pointer] = q;
640 if (!strchr(child->name, '%')) {
641 VALUE_PAIR *vp = NULL;
643 radius_get_vp(request, child->name,
646 vp_prints_value(buffer,
653 radius_xlat(buffer, sizeof(buffer),
654 child->name, request, NULL);
656 null_case = q = NULL;
657 for(p = g->children; p; p = p->next) {
659 if (!null_case) null_case = p;
662 if (strcmp(buffer, p->name) == 0) {
668 if (!q) q = null_case;
670 stack.children[stack.pointer] = q;
675 RDEBUG2("Internal sanity check failed in modcall %d", child->type);
676 exit(1); /* internal sanity check failure */
681 stack.start[stack.pointer] = stack.children[stack.pointer];
683 RDEBUG2("%.*s- entering %s %s {...}",
684 stack.pointer, modcall_spaces,
685 group_name[child->type],
686 child->name ? child->name : "");
689 * Catch the special case of a NULL group.
691 if (!stack.children[stack.pointer]) {
693 * Print message for NULL group
695 RDEBUG2("%.*s- %s %s returns %s",
696 stack.pointer + 1, modcall_spaces,
697 group_name[child->type],
698 child->name ? child->name : "",
699 fr_int2str(rcode_table,
700 stack.result[stack.pointer],
706 * The child may be a group, so we want to
707 * recurse into it's children, rather than
708 * falling through to the code below.
714 * Process a stand-alone child, and fall through
715 * to dealing with it's parent.
717 sp = mod_callabletosingle(child);
719 myresult = call_modsingle(child->method, sp, request);
721 RDEBUG2("%.*s[%s] returns %s",
722 stack.pointer + 1, modcall_spaces,
723 child->name ? child->name : "",
724 fr_int2str(rcode_table, myresult, "??"));
727 * This is a bit of a hack...
729 if (component != RLM_COMPONENT_SESS) request->simul_max = myresult;
732 * FIXME: Allow modules to push a modcallable
733 * onto this stack. This should simplify
734 * configuration a LOT!
736 * Once we do that, we can't do load-time
737 * checking of the maximum stack depth, and we've
738 * got to cache the stack pointer before storing
741 * Also, if the stack changed, we need to set
742 * children[ptr] to NULL, and process the next
743 * entry on the stack, rather than falling
744 * through to finalize the processing of this
747 * Don't put "myresult" on the stack here,
748 * we have to do so with priority.
752 * We roll back up the stack at this point.
756 * The child's action says return. Do so.
758 if (child->actions[myresult] == MOD_ACTION_RETURN) {
759 stack.result[stack.pointer] = myresult;
760 stack.children[stack.pointer] = NULL;
765 * If "reject", break out of the loop and return
768 if (child->actions[myresult] == MOD_ACTION_REJECT) {
769 stack.children[stack.pointer] = NULL;
770 stack.result[stack.pointer] = RLM_MODULE_REJECT;
775 * Otherwise, the action is a number, the
776 * preference level of this return code. If no
777 * higher preference has been seen yet, remember
780 if (child->actions[myresult] >= stack.priority[stack.pointer]) {
781 stack.result[stack.pointer] = myresult;
782 stack.priority[stack.pointer] = child->actions[myresult];
790 * No parent, we must be done.
793 rad_assert(stack.pointer == 0);
794 myresult = stack.result[0];
798 rad_assert(child != NULL);
801 * Go to the "next" child, whatever that is.
803 switch (parent->type) {
812 case MOD_POLICY: /* same as MOD_GROUP */
813 stack.children[stack.pointer] = child->next;
819 case MOD_LOAD_BALANCE:
820 stack.children[stack.pointer] = NULL;
823 case MOD_REDUNDANT_LOAD_BALANCE:
825 stack.children[stack.pointer] = child->next;
827 modgroup *g = mod_callabletogroup(parent);
829 stack.children[stack.pointer] = g->children;
831 if (stack.children[stack.pointer] == stack.start[stack.pointer]) {
832 stack.children[stack.pointer] = NULL;
836 RDEBUG2("Internal sanity check failed in modcall next %d", child->type);
841 * No child, we're done this group, and we return
842 * "myresult" to the caller by pushing it back up
845 if (!stack.children[stack.pointer]) {
847 myresult = stack.result[stack.pointer];
848 if (stack.pointer == 0) break;
850 if (stack.pointer == 0) break;
852 RDEBUG2("%.*s- %s %s returns %s",
853 stack.pointer + 1, modcall_spaces,
854 group_name[parent->type],
855 parent->name ? parent->name : "",
856 fr_int2str(rcode_table, myresult, "??"));
859 if ((parent->type == MOD_IF) ||
860 (parent->type == MOD_ELSIF)) {
861 if_taken = was_if = TRUE;
863 if_taken = was_if = FALSE;
870 child = stack.children[stack.pointer];
871 parent = child->parent;
875 } /* loop until done */
882 static const char *action2str(int action)
885 if(action==MOD_ACTION_RETURN)
887 if(action==MOD_ACTION_REJECT)
889 snprintf(buf, sizeof buf, "%d", action);
893 /* If you suspect a bug in the parser, you'll want to use these dump
894 * functions. dump_tree should reproduce a whole tree exactly as it was found
895 * in radiusd.conf, but in long form (all actions explicitly defined) */
896 static void dump_mc(modcallable *c, int indent)
900 if(c->type==MOD_SINGLE) {
901 modsingle *single = mod_callabletosingle(c);
902 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
903 single->modinst->name);
905 modgroup *g = mod_callabletogroup(c);
907 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
908 group_name[c->type]);
909 for(p = g->children;p;p = p->next)
910 dump_mc(p, indent+1);
913 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
914 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
915 fr_int2str(rcode_table, i, "??"),
916 action2str(c->actions[i]));
919 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
922 static void dump_tree(int comp, modcallable *c)
924 DEBUG("[%s]", comp2str[comp]);
928 #define dump_tree(a, b)
931 /* These are the default actions. For each component, the group{} block
932 * behaves like the code from the old module_*() function. redundant{} and
933 * append{} are based on my guesses of what they will be used for. --Pac. */
935 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
941 MOD_ACTION_RETURN, /* reject */
943 MOD_ACTION_RETURN, /* ok */
944 MOD_ACTION_RETURN, /* handled */
946 MOD_ACTION_RETURN, /* userlock */
947 MOD_ACTION_RETURN, /* notfound */
953 MOD_ACTION_RETURN, /* reject */
955 MOD_ACTION_RETURN, /* ok */
956 MOD_ACTION_RETURN, /* handled */
957 MOD_ACTION_RETURN, /* invalid */
958 MOD_ACTION_RETURN, /* userlock */
959 MOD_ACTION_RETURN, /* notfound */
960 MOD_ACTION_RETURN, /* noop */
961 MOD_ACTION_RETURN /* updated */
965 MOD_ACTION_RETURN, /* reject */
967 MOD_ACTION_RETURN, /* ok */
968 MOD_ACTION_RETURN, /* handled */
969 MOD_ACTION_RETURN, /* invalid */
970 MOD_ACTION_RETURN, /* userlock */
972 MOD_ACTION_RETURN, /* noop */
973 MOD_ACTION_RETURN /* updated */
980 MOD_ACTION_RETURN, /* reject */
981 MOD_ACTION_RETURN, /* fail */
983 MOD_ACTION_RETURN, /* handled */
984 MOD_ACTION_RETURN, /* invalid */
985 MOD_ACTION_RETURN, /* userlock */
992 MOD_ACTION_RETURN, /* reject */
994 MOD_ACTION_RETURN, /* ok */
995 MOD_ACTION_RETURN, /* handled */
996 MOD_ACTION_RETURN, /* invalid */
997 MOD_ACTION_RETURN, /* userlock */
998 MOD_ACTION_RETURN, /* notfound */
999 MOD_ACTION_RETURN, /* noop */
1000 MOD_ACTION_RETURN /* updated */
1004 MOD_ACTION_RETURN, /* reject */
1006 MOD_ACTION_RETURN, /* ok */
1007 MOD_ACTION_RETURN, /* handled */
1008 MOD_ACTION_RETURN, /* invalid */
1009 MOD_ACTION_RETURN, /* userlock */
1011 MOD_ACTION_RETURN, /* noop */
1012 MOD_ACTION_RETURN /* updated */
1019 MOD_ACTION_RETURN, /* reject */
1020 MOD_ACTION_RETURN, /* fail */
1022 MOD_ACTION_RETURN, /* handled */
1023 MOD_ACTION_RETURN, /* invalid */
1024 MOD_ACTION_RETURN, /* userlock */
1025 MOD_ACTION_RETURN, /* notfound */
1031 MOD_ACTION_RETURN, /* reject */
1033 MOD_ACTION_RETURN, /* ok */
1034 MOD_ACTION_RETURN, /* handled */
1035 MOD_ACTION_RETURN, /* invalid */
1036 MOD_ACTION_RETURN, /* userlock */
1037 MOD_ACTION_RETURN, /* notfound */
1038 MOD_ACTION_RETURN, /* noop */
1039 MOD_ACTION_RETURN /* updated */
1043 MOD_ACTION_RETURN, /* reject */
1045 MOD_ACTION_RETURN, /* ok */
1046 MOD_ACTION_RETURN, /* handled */
1047 MOD_ACTION_RETURN, /* invalid */
1048 MOD_ACTION_RETURN, /* userlock */
1050 MOD_ACTION_RETURN, /* noop */
1051 MOD_ACTION_RETURN /* updated */
1058 MOD_ACTION_RETURN, /* reject */
1059 MOD_ACTION_RETURN, /* fail */
1061 MOD_ACTION_RETURN, /* handled */
1062 MOD_ACTION_RETURN, /* invalid */
1063 MOD_ACTION_RETURN, /* userlock */
1064 MOD_ACTION_RETURN, /* notfound */
1072 MOD_ACTION_RETURN, /* ok */
1073 MOD_ACTION_RETURN, /* handled */
1082 MOD_ACTION_RETURN, /* reject */
1084 MOD_ACTION_RETURN, /* ok */
1085 MOD_ACTION_RETURN, /* handled */
1086 MOD_ACTION_RETURN, /* invalid */
1087 MOD_ACTION_RETURN, /* userlock */
1089 MOD_ACTION_RETURN, /* noop */
1090 MOD_ACTION_RETURN /* updated */
1097 MOD_ACTION_RETURN, /* reject */
1099 MOD_ACTION_RETURN, /* ok */
1100 MOD_ACTION_RETURN, /* handled */
1101 MOD_ACTION_RETURN, /* invalid */
1102 MOD_ACTION_RETURN, /* userlock */
1103 MOD_ACTION_RETURN, /* notfound */
1104 MOD_ACTION_RETURN, /* noop */
1105 MOD_ACTION_RETURN /* updated */
1109 MOD_ACTION_RETURN, /* reject */
1111 MOD_ACTION_RETURN, /* ok */
1112 MOD_ACTION_RETURN, /* handled */
1113 MOD_ACTION_RETURN, /* invalid */
1114 MOD_ACTION_RETURN, /* userlock */
1115 MOD_ACTION_RETURN, /* notfound */
1116 MOD_ACTION_RETURN, /* noop */
1117 MOD_ACTION_RETURN /* updated */
1121 MOD_ACTION_RETURN, /* reject */
1123 MOD_ACTION_RETURN, /* ok */
1124 MOD_ACTION_RETURN, /* handled */
1125 MOD_ACTION_RETURN, /* invalid */
1126 MOD_ACTION_RETURN, /* userlock */
1127 MOD_ACTION_RETURN, /* notfound */
1128 MOD_ACTION_RETURN, /* noop */
1129 MOD_ACTION_RETURN /* updated */
1136 MOD_ACTION_RETURN, /* reject */
1137 MOD_ACTION_RETURN, /* fail */
1139 MOD_ACTION_RETURN, /* handled */
1140 MOD_ACTION_RETURN, /* invalid */
1141 MOD_ACTION_RETURN, /* userlock */
1148 MOD_ACTION_RETURN, /* reject */
1150 MOD_ACTION_RETURN, /* ok */
1151 MOD_ACTION_RETURN, /* handled */
1152 MOD_ACTION_RETURN, /* invalid */
1153 MOD_ACTION_RETURN, /* userlock */
1154 MOD_ACTION_RETURN, /* notfound */
1155 MOD_ACTION_RETURN, /* noop */
1156 MOD_ACTION_RETURN /* updated */
1160 MOD_ACTION_RETURN, /* reject */
1162 MOD_ACTION_RETURN, /* ok */
1163 MOD_ACTION_RETURN, /* handled */
1164 MOD_ACTION_RETURN, /* invalid */
1165 MOD_ACTION_RETURN, /* userlock */
1167 MOD_ACTION_RETURN, /* noop */
1168 MOD_ACTION_RETURN /* updated */
1175 MOD_ACTION_RETURN, /* reject */
1176 MOD_ACTION_RETURN, /* fail */
1178 MOD_ACTION_RETURN, /* handled */
1179 MOD_ACTION_RETURN, /* invalid */
1180 MOD_ACTION_RETURN, /* userlock */
1187 MOD_ACTION_RETURN, /* reject */
1189 MOD_ACTION_RETURN, /* ok */
1190 MOD_ACTION_RETURN, /* handled */
1191 MOD_ACTION_RETURN, /* invalid */
1192 MOD_ACTION_RETURN, /* userlock */
1193 MOD_ACTION_RETURN, /* notfound */
1194 MOD_ACTION_RETURN, /* noop */
1195 MOD_ACTION_RETURN /* updated */
1199 MOD_ACTION_RETURN, /* reject */
1201 MOD_ACTION_RETURN, /* ok */
1202 MOD_ACTION_RETURN, /* handled */
1203 MOD_ACTION_RETURN, /* invalid */
1204 MOD_ACTION_RETURN, /* userlock */
1206 MOD_ACTION_RETURN, /* noop */
1207 MOD_ACTION_RETURN /* updated */
1214 MOD_ACTION_RETURN, /* reject */
1215 MOD_ACTION_RETURN, /* fail */
1217 MOD_ACTION_RETURN, /* handled */
1218 MOD_ACTION_RETURN, /* invalid */
1219 MOD_ACTION_RETURN, /* userlock */
1226 MOD_ACTION_RETURN, /* reject */
1228 MOD_ACTION_RETURN, /* ok */
1229 MOD_ACTION_RETURN, /* handled */
1230 MOD_ACTION_RETURN, /* invalid */
1231 MOD_ACTION_RETURN, /* userlock */
1232 MOD_ACTION_RETURN, /* notfound */
1233 MOD_ACTION_RETURN, /* noop */
1234 MOD_ACTION_RETURN /* updated */
1238 MOD_ACTION_RETURN, /* reject */
1240 MOD_ACTION_RETURN, /* ok */
1241 MOD_ACTION_RETURN, /* handled */
1242 MOD_ACTION_RETURN, /* invalid */
1243 MOD_ACTION_RETURN, /* userlock */
1245 MOD_ACTION_RETURN, /* noop */
1246 MOD_ACTION_RETURN /* updated */
1255 MOD_ACTION_RETURN, /* reject */
1256 MOD_ACTION_RETURN, /* fail */
1258 MOD_ACTION_RETURN, /* handled */
1259 MOD_ACTION_RETURN, /* invalid */
1260 MOD_ACTION_RETURN, /* userlock */
1267 MOD_ACTION_RETURN, /* reject */
1269 MOD_ACTION_RETURN, /* ok */
1270 MOD_ACTION_RETURN, /* handled */
1271 MOD_ACTION_RETURN, /* invalid */
1272 MOD_ACTION_RETURN, /* userlock */
1273 MOD_ACTION_RETURN, /* notfound */
1274 MOD_ACTION_RETURN, /* noop */
1275 MOD_ACTION_RETURN /* updated */
1279 MOD_ACTION_RETURN, /* reject */
1281 MOD_ACTION_RETURN, /* ok */
1282 MOD_ACTION_RETURN, /* handled */
1283 MOD_ACTION_RETURN, /* invalid */
1284 MOD_ACTION_RETURN, /* userlock */
1286 MOD_ACTION_RETURN, /* noop */
1287 MOD_ACTION_RETURN /* updated */
1294 MOD_ACTION_RETURN, /* reject */
1295 MOD_ACTION_RETURN, /* fail */
1297 MOD_ACTION_RETURN, /* handled */
1298 MOD_ACTION_RETURN, /* invalid */
1299 MOD_ACTION_RETURN, /* userlock */
1306 MOD_ACTION_RETURN, /* reject */
1308 MOD_ACTION_RETURN, /* ok */
1309 MOD_ACTION_RETURN, /* handled */
1310 MOD_ACTION_RETURN, /* invalid */
1311 MOD_ACTION_RETURN, /* userlock */
1312 MOD_ACTION_RETURN, /* notfound */
1313 MOD_ACTION_RETURN, /* noop */
1314 MOD_ACTION_RETURN /* updated */
1318 MOD_ACTION_RETURN, /* reject */
1320 MOD_ACTION_RETURN, /* ok */
1321 MOD_ACTION_RETURN, /* handled */
1322 MOD_ACTION_RETURN, /* invalid */
1323 MOD_ACTION_RETURN, /* userlock */
1325 MOD_ACTION_RETURN, /* noop */
1326 MOD_ACTION_RETURN /* updated */
1334 static modcallable *do_compile_modupdate(modcallable *parent,
1335 int component, CONF_SECTION *cs,
1339 const char *vp_name;
1341 modcallable *csingle;
1343 VALUE_PAIR *head, **tail;
1345 static const char *attrlist_names[] = {
1346 "request", "reply", "proxy-request", "proxy-reply",
1347 "config", "control",
1348 "coa", "coa-reply", "disconnect", "disconnect-reply",
1352 component = component; /* -Wunused */
1354 if (!cf_section_name2(cs)) {
1355 cf_log_err(cf_sectiontoitem(cs),
1356 "Require list name for 'update'.\n");
1361 if (strncmp(vp_name, "outer.", 6) == 0) {
1365 for (i = 0; attrlist_names[i] != NULL; i++) {
1366 if (strcmp(vp_name, attrlist_names[i]) == 0) {
1373 cf_log_err(cf_sectiontoitem(cs),
1374 "Unknown attribute list \"%s\"",
1383 * Walk through the children of the update section,
1384 * ensuring that they're all known attributes.
1386 for (ci=cf_item_find_next(cs, NULL);
1388 ci=cf_item_find_next(cs, ci)) {
1392 if (cf_item_is_section(ci)) {
1393 cf_log_err(ci, "\"update\" sections cannot have subsections");
1397 if (!cf_item_is_pair(ci)) continue;
1399 cp = cf_itemtopair(ci); /* can't return NULL */
1400 vp = cf_pairtovp(cp);
1403 cf_log_err(ci, "ERROR: %s", fr_strerror());
1407 if ((vp->operator != T_OP_EQ) &&
1408 (vp->operator != T_OP_CMP_EQ) &&
1409 (vp->operator != T_OP_ADD) &&
1410 (vp->operator != T_OP_SUB) &&
1411 (vp->operator != T_OP_LE) &&
1412 (vp->operator != T_OP_GE) &&
1413 (vp->operator != T_OP_CMP_FALSE) &&
1414 (vp->operator != T_OP_SET)) {
1417 cf_log_err(ci, "Invalid operator for attribute");
1422 * A few more sanity checks. The enforcement of
1423 * <= or >= can only happen for integer
1426 if ((vp->operator == T_OP_LE) ||
1427 (vp->operator == T_OP_GE)) {
1428 if ((vp->type != PW_TYPE_BYTE) &&
1429 (vp->type != PW_TYPE_SHORT) &&
1430 (vp->type != PW_TYPE_INTEGER)) {
1433 cf_log_err(ci, "Enforcment of <= or >= is possible only for integer attributes");
1443 cf_log_err(cf_sectiontoitem(cs),
1444 "ERROR: update %s section cannot be empty",
1449 g = rad_malloc(sizeof(*g)); /* never fails */
1450 memset(g, 0, sizeof(*g));
1451 csingle = mod_grouptocallable(g);
1453 csingle->parent = parent;
1454 csingle->next = NULL;
1455 csingle->name = name2;
1456 csingle->type = MOD_UPDATE;
1457 csingle->method = component;
1459 g->grouptype = GROUPTYPE_SIMPLE;
1468 static modcallable *do_compile_modswitch(modcallable *parent,
1469 int component, CONF_SECTION *cs)
1471 modcallable *csingle;
1473 int had_seen_default = FALSE;
1475 component = component; /* -Wunused */
1477 if (!cf_section_name2(cs)) {
1478 cf_log_err(cf_sectiontoitem(cs),
1479 "You must specify a variable to switch over for 'switch'.");
1483 if (!cf_item_find_next(cs, NULL)) {
1484 cf_log_err(cf_sectiontoitem(cs), "'switch' statements cannot be empty.");
1489 * Walk through the children of the switch section,
1490 * ensuring that they're all 'case' statements
1492 for (ci=cf_item_find_next(cs, NULL);
1494 ci=cf_item_find_next(cs, ci)) {
1495 CONF_SECTION *subcs;
1496 const char *name1, *name2;
1498 if (!cf_item_is_section(ci)) {
1499 if (!cf_item_is_pair(ci)) continue;
1501 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1505 subcs = cf_itemtosection(ci); /* can't return NULL */
1506 name1 = cf_section_name1(subcs);
1508 if (strcmp(name1, "case") != 0) {
1509 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1513 name2 = cf_section_name2(subcs);
1514 if (!name2 && !had_seen_default) {
1515 had_seen_default = TRUE;
1519 if (!name2 || (name2[0] == '\0')) {
1520 cf_log_err(ci, "\"case\" sections must have a name");
1525 csingle= do_compile_modgroup(parent, component, cs,
1526 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1527 if (!csingle) return NULL;
1528 csingle->type = MOD_SWITCH;
1532 static modcallable *do_compile_modforeach(modcallable *parent,
1533 int component, CONF_SECTION *cs,
1536 modcallable *csingle;
1538 component = component; /* -Wunused */
1540 if (!cf_section_name2(cs)) {
1541 cf_log_err(cf_sectiontoitem(cs),
1542 "You must specify an attribute to loop over in 'foreach'.");
1546 if (!cf_item_find_next(cs, NULL)) {
1547 cf_log_err(cf_sectiontoitem(cs), "'foreach' blocks cannot be empty.");
1551 csingle= do_compile_modgroup(parent, component, cs,
1552 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1553 if (!csingle) return NULL;
1554 csingle->name = name2;
1555 csingle->type = MOD_FOREACH;
1560 static modcallable *do_compile_modserver(modcallable *parent,
1561 int component, CONF_ITEM *ci,
1566 modcallable *csingle;
1567 CONF_SECTION *subcs;
1570 subcs = cf_section_sub_find_name2(cs, comp2str[component], NULL);
1572 cf_log_err(ci, "Server %s has no %s section",
1573 server, comp2str[component]);
1577 mr = rad_malloc(sizeof(*mr));
1578 memset(mr, 0, sizeof(*mr));
1580 csingle = mod_reftocallable(mr);
1581 csingle->parent = parent;
1582 csingle->next = NULL;
1583 csingle->name = name;
1584 csingle->type = MOD_REFERENCE;
1585 csingle->method = component;
1587 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1588 sizeof(csingle->actions));
1590 mr->ref_name = strdup(server);
1596 static modcallable *do_compile_modxlat(modcallable *parent,
1597 int component, const char *fmt)
1599 modcallable *csingle;
1602 mx = rad_malloc(sizeof(*mx));
1603 memset(mx, 0, sizeof(*mx));
1605 csingle = mod_xlattocallable(mx);
1606 csingle->parent = parent;
1607 csingle->next = NULL;
1608 csingle->name = "expand";
1609 csingle->type = MOD_XLAT;
1610 csingle->method = component;
1612 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1613 sizeof(csingle->actions));
1615 mx->xlat_name = strdup(fmt);
1616 if (fmt[0] != '%') {
1620 strcpy(mx->xlat_name, fmt + 1);
1621 p = strrchr(mx->xlat_name, '`');
1629 * redundant, etc. can refer to modules or groups, but not much else.
1631 static int all_children_are_modules(CONF_SECTION *cs, const char *name)
1635 for (ci=cf_item_find_next(cs, NULL);
1637 ci=cf_item_find_next(cs, ci)) {
1639 * If we're a redundant, etc. group, then the
1640 * intention is to call modules, rather than
1641 * processing logic. These checks aren't
1642 * *strictly* necessary, but they keep the users
1643 * from doing crazy things.
1645 if (cf_item_is_section(ci)) {
1646 CONF_SECTION *subcs = cf_itemtosection(ci);
1647 const char *name1 = cf_section_name1(subcs);
1649 if ((strcmp(name1, "if") == 0) ||
1650 (strcmp(name1, "else") == 0) ||
1651 (strcmp(name1, "elsif") == 0) ||
1652 (strcmp(name1, "update") == 0) ||
1653 (strcmp(name1, "switch") == 0) ||
1654 (strcmp(name1, "case") == 0)) {
1655 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
1662 if (cf_item_is_pair(ci)) {
1663 CONF_PAIR *cp = cf_itemtopair(ci);
1664 if (cf_pair_value(cp) != NULL) {
1666 "Entry with no value is invalid");
1677 * Compile one entry of a module call.
1679 static modcallable *do_compile_modsingle(modcallable *parent,
1680 int component, CONF_ITEM *ci,
1682 const char **modname)
1687 const char *modrefname;
1689 modcallable *csingle;
1690 module_instance_t *this;
1691 CONF_SECTION *cs, *subcs, *modules;
1693 if (cf_item_is_section(ci)) {
1696 cs = cf_itemtosection(ci);
1697 modrefname = cf_section_name1(cs);
1698 name2 = cf_section_name2(cs);
1699 if (!name2) name2 = "_UnNamedGroup";
1702 * group{}, redundant{}, or append{} may appear
1703 * where a single module instance was expected.
1704 * In that case, we hand it off to
1707 if (strcmp(modrefname, "group") == 0) {
1709 return do_compile_modgroup(parent, component, cs,
1713 } else if (strcmp(modrefname, "redundant") == 0) {
1716 if (!all_children_are_modules(cs, modrefname)) {
1720 return do_compile_modgroup(parent, component, cs,
1721 GROUPTYPE_REDUNDANT,
1724 } else if (strcmp(modrefname, "append") == 0) {
1726 return do_compile_modgroup(parent, component, cs,
1730 } else if (strcmp(modrefname, "load-balance") == 0) {
1733 if (!all_children_are_modules(cs, modrefname)) {
1737 csingle= do_compile_modgroup(parent, component, cs,
1740 if (!csingle) return NULL;
1741 csingle->type = MOD_LOAD_BALANCE;
1744 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1747 if (!all_children_are_modules(cs, modrefname)) {
1751 csingle= do_compile_modgroup(parent, component, cs,
1752 GROUPTYPE_REDUNDANT,
1754 if (!csingle) return NULL;
1755 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1759 } else if (strcmp(modrefname, "if") == 0) {
1760 if (!cf_section_name2(cs)) {
1761 cf_log_err(ci, "'if' without condition.");
1766 csingle= do_compile_modgroup(parent, component, cs,
1769 if (!csingle) return NULL;
1770 csingle->type = MOD_IF;
1772 if (!radius_evaluate_condition(NULL, 0, 0, modname,
1774 modcallable_free(&csingle);
1781 } else if (strcmp(modrefname, "elsif") == 0) {
1783 ((parent->type == MOD_LOAD_BALANCE) ||
1784 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1785 cf_log_err(ci, "'elsif' cannot be used in this section section.");
1789 if (!cf_section_name2(cs)) {
1790 cf_log_err(ci, "'elsif' without condition.");
1795 csingle= do_compile_modgroup(parent, component, cs,
1798 if (!csingle) return NULL;
1799 csingle->type = MOD_ELSIF;
1801 if (!radius_evaluate_condition(NULL, 0, 0, modname,
1803 modcallable_free(&csingle);
1810 } else if (strcmp(modrefname, "else") == 0) {
1812 ((parent->type == MOD_LOAD_BALANCE) ||
1813 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1814 cf_log_err(ci, "'else' cannot be used in this section section.");
1818 if (cf_section_name2(cs)) {
1819 cf_log_err(ci, "Cannot have conditions on 'else'.");
1824 csingle= do_compile_modgroup(parent, component, cs,
1827 if (!csingle) return NULL;
1828 csingle->type = MOD_ELSE;
1831 } else if (strcmp(modrefname, "update") == 0) {
1834 csingle = do_compile_modupdate(parent, component, cs,
1836 if (!csingle) return NULL;
1840 } else if (strcmp(modrefname, "switch") == 0) {
1843 csingle = do_compile_modswitch(parent, component, cs);
1844 if (!csingle) return NULL;
1848 } else if (strcmp(modrefname, "case") == 0) {
1854 * FIXME: How to tell that the parent can only
1855 * be a "switch" statement?
1858 cf_log_err(ci, "\"case\" statements may only appear within a \"switch\" section");
1862 csingle= do_compile_modgroup(parent, component, cs,
1865 if (!csingle) return NULL;
1866 csingle->type = MOD_CASE;
1867 csingle->name = cf_section_name2(cs); /* may be NULL */
1870 * Set all of it's codes to return, so that
1871 * when we pick a 'case' statement, we don't
1872 * fall through to processing the next one.
1874 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1875 csingle->actions[i] = MOD_ACTION_RETURN;
1880 } else if (strcmp(modrefname, "foreach") == 0) {
1883 csingle = do_compile_modforeach(parent, component, cs,
1885 if (!csingle) return NULL;
1889 } /* else it's something like sql { fail = 1 ...} */
1891 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
1895 * Else it's a module reference, with updated return
1899 CONF_PAIR *cp = cf_itemtopair(ci);
1900 modrefname = cf_pair_attr(cp);
1903 * Actions (ok = 1), etc. are orthoganal to just
1904 * about everything else.
1906 if (cf_pair_value(cp) != NULL) {
1907 cf_log_err(ci, "Entry is not a reference to a module");
1911 if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
1912 (modrefname[0] == '`')) {
1913 return do_compile_modxlat(parent, component,
1918 * See if the module is a virtual one. If so,
1919 * return that, rather than doing anything here.
1922 cs = cf_section_find("instantiate");
1923 if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
1926 cs = cf_section_find("policy");
1927 if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
1931 DEBUG2(" Module: Loading virtual module %s",
1935 * redundant foo {} is a single.
1937 if (cf_section_name2(subcs)) {
1938 return do_compile_modsingle(parent,
1940 cf_sectiontoitem(subcs),
1945 * foo {} is a group.
1947 return do_compile_modgroup(parent,
1957 * Not a virtual module. It must be a real module.
1959 modules = cf_section_find("modules");
1962 if (modules && cf_section_sub_find_name2(modules, NULL, modrefname)) {
1963 this = find_module_instance(modules, modrefname, 1);
1971 * Maybe it's module.method
1973 p = strrchr(modrefname, '.');
1974 if (p) for (i = RLM_COMPONENT_AUTH;
1975 i < RLM_COMPONENT_COUNT;
1977 if (strcmp(p + 1, comp2str[i]) == 0) {
1980 strlcpy(buffer, modrefname, sizeof(buffer));
1981 buffer[p - modrefname] = '\0';
1984 this = find_module_instance(cf_section_find("modules"), buffer, 1);
1986 !this->entry->module->methods[i]) {
1988 cf_log_err(ci, "Module %s has no such method %s", buffer, comp2str[i]);
1996 if (strncmp(modrefname, "server[", 7) == 0) {
1999 strlcpy(buffer, modrefname + 7, sizeof(buffer));
2000 p = strrchr(buffer, ']');
2001 if (!p || p[1] != '\0' || (p == buffer)) {
2002 cf_log_err(ci, "Invalid server reference in \"%s\".", modrefname);
2007 cs = cf_section_sub_find_name2(NULL, "server", buffer);
2009 cf_log_err(ci, "No such server \"%s\".", buffer);
2013 return do_compile_modserver(parent, component, ci,
2014 modrefname, cs, buffer);
2018 cf_log_err(ci, "Failed to load module \"%s\".", modrefname);
2023 * We know it's all OK, allocate the structures, and fill
2026 single = rad_malloc(sizeof(*single));
2027 memset(single, 0, sizeof(*single));
2028 csingle = mod_singletocallable(single);
2029 csingle->parent = parent;
2030 csingle->next = NULL;
2031 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2032 memcpy(csingle->actions, defaultactions[component][grouptype],
2033 sizeof csingle->actions);
2034 } else { /* inside Auth-Type has different rules */
2035 memcpy(csingle->actions, defaultactions[RLM_COMPONENT_AUTZ][grouptype],
2036 sizeof csingle->actions);
2038 rad_assert(modrefname != NULL);
2039 csingle->name = modrefname;
2040 csingle->type = MOD_SINGLE;
2041 csingle->method = component;
2044 * Singles can override the actions, virtual modules cannot.
2046 * FIXME: We may want to re-visit how to do this...
2047 * maybe a csingle as a ref?
2049 if (cf_item_is_section(ci)) {
2050 cs = cf_itemtosection(ci);
2052 for (ci=cf_item_find_next(cs, NULL);
2054 ci=cf_item_find_next(cs, ci)) {
2056 if (cf_item_is_section(ci)) {
2057 cf_log_err(ci, "Subsection of module instance call not allowed");
2058 modcallable_free(&csingle);
2062 if (!cf_item_is_pair(ci)) continue;
2064 if (!compile_action(csingle, cf_itemtopair(ci))) {
2065 modcallable_free(&csingle);
2072 * Bail out if the module in question does not supply the
2075 if (!this->entry->module->methods[component]) {
2076 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
2077 comp2str[component]);
2078 modcallable_free(&csingle);
2082 single->modinst = this;
2083 *modname = this->entry->module->name;
2087 modcallable *compile_modsingle(modcallable *parent,
2088 int component, CONF_ITEM *ci,
2089 const char **modname)
2091 modcallable *ret = do_compile_modsingle(parent, component, ci,
2094 dump_tree(component, ret);
2100 * Internal compile group code.
2102 static modcallable *do_compile_modgroup(modcallable *parent,
2103 int component, CONF_SECTION *cs,
2104 int grouptype, int parentgrouptype)
2111 g = rad_malloc(sizeof(*g));
2112 memset(g, 0, sizeof(*g));
2113 g->grouptype = grouptype;
2115 c = mod_grouptocallable(g);
2117 c->type = MOD_GROUP;
2119 memset(c->actions, 0, sizeof(c->actions));
2122 * Remember the name for printing, etc.
2124 * FIXME: We may also want to put the names into a
2125 * rbtree, so that groups can reference each other...
2127 c->name = cf_section_name2(cs);
2129 c->name = cf_section_name1(cs);
2130 if (strcmp(c->name, "group") == 0) {
2133 c->type = MOD_POLICY;
2139 * Loop over the children of this group.
2141 for (ci=cf_item_find_next(cs, NULL);
2143 ci=cf_item_find_next(cs, ci)) {
2146 * Sections are references to other groups, or
2147 * to modules with updated return codes.
2149 if (cf_item_is_section(ci)) {
2150 const char *junk = NULL;
2151 modcallable *single;
2152 CONF_SECTION *subcs = cf_itemtosection(ci);
2154 single = do_compile_modsingle(c, component, ci,
2157 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
2158 cf_section_name1(subcs));
2159 modcallable_free(&c);
2162 add_child(g, single);
2164 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
2168 const char *attr, *value;
2169 CONF_PAIR *cp = cf_itemtopair(ci);
2171 attr = cf_pair_attr(cp);
2172 value = cf_pair_value(cp);
2175 * A CONF_PAIR is either a module
2176 * instance with no actions
2180 modcallable *single;
2181 const char *junk = NULL;
2183 single = do_compile_modsingle(c,
2190 "Failed to parse \"%s\" entry.",
2192 modcallable_free(&c);
2195 add_child(g, single);
2198 * Or a module instance with action.
2200 } else if (!compile_action(c, cp)) {
2201 modcallable_free(&c);
2203 } /* else it worked */
2208 * Set the default actions, if they haven't already been
2211 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2212 if (!c->actions[i]) {
2213 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2214 c->actions[i] = defaultactions[component][parentgrouptype][i];
2215 } else { /* inside Auth-Type has different rules */
2216 c->actions[i] = defaultactions[RLM_COMPONENT_AUTZ][parentgrouptype][i];
2222 * FIXME: If there are no children, return NULL?
2224 return mod_grouptocallable(g);
2227 modcallable *compile_modgroup(modcallable *parent,
2228 int component, CONF_SECTION *cs)
2230 modcallable *ret = do_compile_modgroup(parent, component, cs,
2233 dump_tree(component, ret);
2237 void add_to_modcallable(modcallable **parent, modcallable *this,
2238 int component, const char *name)
2242 rad_assert(this != NULL);
2244 if (*parent == NULL) {
2247 g = rad_malloc(sizeof *g);
2248 memset(g, 0, sizeof(*g));
2249 g->grouptype = GROUPTYPE_SIMPLE;
2250 c = mod_grouptocallable(g);
2253 defaultactions[component][GROUPTYPE_SIMPLE],
2254 sizeof(c->actions));
2255 rad_assert(name != NULL);
2257 c->type = MOD_GROUP;
2258 c->method = component;
2261 *parent = mod_grouptocallable(g);
2263 g = mod_callabletogroup(*parent);
2269 void modcallable_free(modcallable **pc)
2271 modcallable *c, *loop, *next;
2273 if (c->type != MOD_SINGLE) {
2274 modgroup *g = mod_callabletogroup(c);
2276 for(loop = g->children;
2280 modcallable_free(&loop);