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>
31 extern int radius_get_vp(REQUEST *request, const char *name, VALUE_PAIR **vp_p);
33 /* mutually-recursive static functions need a prototype up front */
34 static modcallable *do_compile_modgroup(modcallable *,
38 /* Actions may be a positive integer (the highest one returned in the group
39 * will be returned), or the keyword "return", represented here by
40 * MOD_ACTION_RETURN, to cause an immediate return.
41 * There's also the keyword "reject", represented here by MOD_ACTION_REJECT
42 * to cause an immediate reject. */
43 #define MOD_ACTION_RETURN (-1)
44 #define MOD_ACTION_REJECT (-2)
46 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
47 * explanation of what they are all about, see ../../doc/README.failover */
50 struct modcallable *next;
52 enum { MOD_SINGLE = 1, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE,
54 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)
281 rad_assert(request != NULL);
284 * If the request should stop, refuse to do anything.
286 blocked = (request->master_state == REQUEST_STOP_PROCESSING);
287 if (blocked) return RLM_MODULE_NOOP;
289 RDEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
290 comp2str[component], sp->modinst->name,
291 sp->modinst->entry->name, request->number);
293 if (sp->modinst->dead) {
294 myresult = RLM_MODULE_FAIL;
298 safe_lock(sp->modinst);
301 * For logging unresponsive children.
303 request->module = sp->modinst->name;
305 myresult = sp->modinst->entry->module->methods[component](
306 sp->modinst->insthandle, request);
308 request->module = "";
309 safe_unlock(sp->modinst);
312 * Wasn't blocked, and now is. Complain!
314 blocked = (request->master_state == REQUEST_STOP_PROCESSING);
316 radlog(L_INFO, "WARNING: Module %s became unblocked for request %u",
317 sp->modinst->entry->name, request->number);
321 RDEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
322 comp2str[component], sp->modinst->name,
323 sp->modinst->entry->name, request->number);
329 static int default_component_results[RLM_COMPONENT_COUNT] = {
330 RLM_MODULE_REJECT, /* AUTH */
331 RLM_MODULE_NOTFOUND, /* AUTZ */
332 RLM_MODULE_NOOP, /* PREACCT */
333 RLM_MODULE_NOOP, /* ACCT */
334 RLM_MODULE_FAIL, /* SESS */
335 RLM_MODULE_NOOP, /* PRE_PROXY */
336 RLM_MODULE_NOOP, /* POST_PROXY */
337 RLM_MODULE_NOOP /* POST_AUTH */
340 RLM_MODULE_NOOP, /* RECV_COA_TYPE */
341 RLM_MODULE_NOOP /* SEND_COA_TYPE */
346 static const char *group_name[] = {
350 "load-balance group",
351 "redundant-load-balance group",
363 /* Here's where we recognize all of our keywords: first the rcodes, then the
365 const FR_NAME_NUMBER mod_rcode_table[] = {
366 { "reject", RLM_MODULE_REJECT },
367 { "fail", RLM_MODULE_FAIL },
368 { "ok", RLM_MODULE_OK },
369 { "handled", RLM_MODULE_HANDLED },
370 { "invalid", RLM_MODULE_INVALID },
371 { "userlock", RLM_MODULE_USERLOCK },
372 { "notfound", RLM_MODULE_NOTFOUND },
373 { "noop", RLM_MODULE_NOOP },
374 { "updated", RLM_MODULE_UPDATED },
378 static const char *modcall_spaces = "++++++++++++++++++++++++++++++++";
380 #define MODCALL_STACK_MAX (32)
382 #define MOD_LOG_OPEN_BRACE(_name) RDEBUG2("%.*s%s %s {", depth + 1, modcall_spaces, _name, c->name)
383 #define MOD_LOG_CLOSE_BRACE() RDEBUG2("%.*s} # %s %s = %s", depth + 1, modcall_spaces, \
384 group_name[c->type], c->name ? c->name : "", \
385 fr_int2str(mod_rcode_table, result, "<invalid>"))
388 * Don't call the modules recursively. Instead, do them
389 * iteratively, and manage the call stack ourselves.
391 typedef struct modcall_stack_entry_t {
395 } modcall_stack_entry_t;
398 static int modcall_recurse(REQUEST *request, int component, int depth,
399 modcall_stack_entry_t *entry);
402 * Call a child of a block.
404 static void modcall_child(REQUEST *request, int component, int depth,
405 modcall_stack_entry_t *entry, modcallable *c,
406 int *result, int *priority)
408 modcall_stack_entry_t *next;
410 if (depth >= MODCALL_STACK_MAX) {
411 radlog(L_ERR, "Internal sanity check failed: module stack is too deep");
416 * Initialize the childs stack frame.
420 next->result = entry->result;
423 if (!modcall_recurse(request, component,
425 *result = RLM_MODULE_FAIL;
429 *result = next->result;
430 *priority = next->priority;
436 * Interpret the various types of blocks.
438 static int modcall_recurse(REQUEST *request, int component, int depth,
439 modcall_stack_entry_t *entry)
441 int if_taken, was_if;
443 int result, priority;
445 was_if = if_taken = FALSE;
446 result = RLM_MODULE_FAIL;
453 * Nothing more to do. Return the code and priority
454 * which was set by the caller.
459 * We've been asked to stop. Do so.
461 if ((request->master_state == REQUEST_STOP_PROCESSING) ||
463 (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
464 entry->result = RLM_MODULE_FAIL;
465 entry->priority = 9999;
470 * Handle "if" conditions.
472 if (c->type == MOD_IF) {
478 g = mod_callabletogroup(c);
481 RDEBUG2("%.*s? %s %s", depth + 1, modcall_spaces,
482 group_name[c->type], c->name);
484 if (radius_evaluate_condition(request, entry->result,
485 0, &p, TRUE, &condition)) {
486 RDEBUG2("%.*s? %s %s -> %s", depth + 1, modcall_spaces,
488 c->name, condition ? "TRUE" : "FALSE");
494 * Didn't pass. Remember that.
503 * We took the "if". Go recurse into its' children.
511 * "else" if the previous "if" was taken.
512 * "if" if the previous if wasn't taken.
514 if (c->type == MOD_ELSIF) {
515 if (!was_if) goto elsif_error;
518 * Like MOD_ELSE, but allow for a later "else"
521 RDEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
522 depth + 1, modcall_spaces,
523 group_name[c->type], request->number);
530 * Check the "if" condition.
536 * "else" for a preceding "if".
538 if (c->type == MOD_ELSE) {
539 if (!was_if) { /* error */
541 RDEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",
542 depth + 1, modcall_spaces,
543 group_name[c->type], request->number);
548 RDEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
549 depth + 1, modcall_spaces,
550 group_name[c->type], request->number);
557 * We need to process it. Go do that.
565 * We're no longer processing if/else/elsif. Reset the
566 * trackers for those conditions.
571 if (c->type == MOD_SINGLE) {
575 * Process a stand-alone child, and fall through
576 * to dealing with it's parent.
578 sp = mod_callabletosingle(c);
580 result = call_modsingle(c->method, sp, request);
581 RDEBUG2("%.*s[%s] = %s", depth + 1, modcall_spaces, c->name ? c->name : "",
582 fr_int2str(mod_rcode_table, result, "<invalid>"));
583 goto calculate_result;
587 * Update attribute(s)
589 if (c->type == MOD_UPDATE) {
591 modgroup *g = mod_callabletogroup(c);
593 MOD_LOG_OPEN_BRACE("update");
594 rcode = radius_update_attrlist(request, g->cs,
596 if (rcode != RLM_MODULE_UPDATED) {
598 MOD_LOG_CLOSE_BRACE();
599 goto calculate_result;
602 result = RLM_MODULE_NOOP;
603 MOD_LOG_CLOSE_BRACE();
608 * Child is a group that has children of it's own.
610 if ((c->type == MOD_GROUP) || (c->type == MOD_POLICY) ||
611 (c->type == MOD_CASE)) {
615 g = mod_callabletogroup(c);
617 MOD_LOG_OPEN_BRACE(group_name[c->type]);
618 modcall_child(request, component,
619 depth + 1, entry, g->children,
621 MOD_LOG_CLOSE_BRACE();
622 goto calculate_result;
625 if (c->type == MOD_SWITCH) {
626 modcallable *this, *found, *null_case;
630 MOD_LOG_OPEN_BRACE("switch");
633 * If there's no %, it refers to an attribute.
634 * Otherwise, expand it.
636 if (!strchr(c->name, '%')) {
637 VALUE_PAIR *vp = NULL;
639 radius_get_vp(request, c->name, &vp);
641 vp_prints_value(buffer,
648 radius_xlat(buffer, sizeof(buffer),
649 c->name, request, NULL);
653 * Find either the exact matching name, or the
654 * "case {...}" statement.
656 g = mod_callabletogroup(c);
657 null_case = found = NULL;
658 for (this = g->children; this; this = this->next) {
660 if (!null_case) null_case = this;
663 if (strcmp(buffer, this->name) == 0) {
669 if (!found) found = null_case;
671 MOD_LOG_OPEN_BRACE(group_name[c->type]);
672 modcall_child(request, component,
673 depth + 1, entry, found,
675 MOD_LOG_CLOSE_BRACE();
676 goto calculate_result;
679 if ((c->type == MOD_LOAD_BALANCE) ||
680 (c->type == MOD_REDUNDANT_LOAD_BALANCE)) {
682 modcallable *this, *found;
685 MOD_LOG_OPEN_BRACE("load-balance");
687 g = mod_callabletogroup(c);
689 for (this = g->children; this; this = this->next) {
697 if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
702 MOD_LOG_OPEN_BRACE(group_name[c->type]);
704 if (c->type == MOD_LOAD_BALANCE) {
705 modcall_child(request, component,
706 depth + 1, entry, found,
713 * Loop over all children in this
714 * section. If we get FAIL, then
715 * continue. Otherwise, stop.
717 for (i = 1; i < count; i++) {
718 modcall_child(request, component,
719 depth + 1, entry, found,
721 if (c->actions[result] == MOD_ACTION_RETURN) {
727 MOD_LOG_CLOSE_BRACE();
728 goto calculate_result;
729 } /* MOD_LOAD_BALANCE */
732 * Reference another virtual server.
734 * This should really be deleted, and replaced with a
735 * more abstracted / functional version.
737 if (c->type == MOD_REFERENCE) {
738 modref *mr = mod_callabletoref(c);
739 char const *server = request->server;
741 if (server == mr->ref_name) {
742 radlog(L_INFO, "WARNING: Suppressing recursive call to server %s", server);
746 request->server = mr->ref_name;
747 RDEBUG("server %s { # nested call", mr->ref_name);
748 result = indexed_modcall(component, 0, request);
749 RDEBUG("} # server %s with nested call", mr->ref_name);
750 request->server = server;
751 goto calculate_result;
752 } /* MOD_REFERENCE */
755 * xlat a string without doing anything else
757 * This should really be deleted, and replaced with a
758 * more abstracted / functional version.
760 if (c->type == MOD_XLAT) {
761 modxlat *mx = mod_callabletoxlat(c);
765 radius_xlat(buffer, sizeof(buffer),
766 mx->xlat_name, request, NULL);
768 RDEBUG("`%s`", mx->xlat_name);
769 radius_exec_program(mx->xlat_name, request,
771 request->packet->vps,
779 * Add new module types here.
784 * The child's action says return. Do so.
786 if ((c->actions[result] == MOD_ACTION_RETURN) &&
788 entry->result = result;
793 * If "reject", break out of the loop and return
796 if (c->actions[result] == MOD_ACTION_REJECT) {
797 entry->result = RLM_MODULE_REJECT;
802 * The array holds a default priority for this return
803 * code. Grab it in preference to any unset priority.
805 if (priority < 0) priority = c->actions[result];
808 * We're higher than any previous priority, remember this
809 * return code and priority.
811 if (priority > entry->priority) {
812 entry->result = result;
813 entry->priority = priority;
817 * If we're processing a "case" statement, we return once
818 * it's done, rather than going to the next "case" statement.
820 if (c->type == MOD_CASE) return TRUE;
823 entry->c = entry->c->next;
825 if (entry->c) goto redo;
835 * @brief Call a module, iteratively, with a local stack, rather than
836 * recursively. What did Paul Graham say about Lisp...?
838 int modcall(int component, modcallable *c, REQUEST *request)
840 modcall_stack_entry_t stack[MODCALL_STACK_MAX];
842 if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {
843 return RLM_MODULE_FAIL;
847 * Set up the initial stack frame.
850 stack[0].result = default_component_results[component];
851 stack[0].priority = 0;
854 * Call the main handler.
856 if (!modcall_recurse(request, component, 0, &stack[0])) {
857 return RLM_MODULE_FAIL;
863 return stack[0].result;
867 static const char *action2str(int action)
870 if(action==MOD_ACTION_RETURN)
872 if(action==MOD_ACTION_REJECT)
874 snprintf(buf, sizeof buf, "%d", action);
878 /* If you suspect a bug in the parser, you'll want to use these dump
879 * functions. dump_tree should reproduce a whole tree exactly as it was found
880 * in radiusd.conf, but in long form (all actions explicitly defined) */
881 static void dump_mc(modcallable *c, int indent)
885 if(c->type==MOD_SINGLE) {
886 modsingle *single = mod_callabletosingle(c);
887 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
888 single->modinst->name);
889 } else if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
890 modgroup *g = mod_callabletogroup(c);
892 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
893 group_name[c->type]);
894 for(p = g->children;p;p = p->next)
895 dump_mc(p, indent+1);
896 } /* else ignore it for now */
898 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
899 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
900 fr_int2str(rcode_table, i, "??"),
901 action2str(c->actions[i]));
904 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
907 static void dump_tree(int comp, modcallable *c)
909 RDEBUG("[%s]", comp2str[comp]);
913 #define dump_tree(a, b)
916 /* These are the default actions. For each component, the group{} block
917 * behaves like the code from the old module_*() function. redundant{} and
918 * append{} are based on my guesses of what they will be used for. --Pac. */
920 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
926 MOD_ACTION_RETURN, /* reject */
928 MOD_ACTION_RETURN, /* ok */
929 MOD_ACTION_RETURN, /* handled */
931 MOD_ACTION_RETURN, /* userlock */
932 MOD_ACTION_RETURN, /* notfound */
938 MOD_ACTION_RETURN, /* reject */
940 MOD_ACTION_RETURN, /* ok */
941 MOD_ACTION_RETURN, /* handled */
942 MOD_ACTION_RETURN, /* invalid */
943 MOD_ACTION_RETURN, /* userlock */
944 MOD_ACTION_RETURN, /* notfound */
945 MOD_ACTION_RETURN, /* noop */
946 MOD_ACTION_RETURN /* updated */
950 MOD_ACTION_RETURN, /* reject */
952 MOD_ACTION_RETURN, /* ok */
953 MOD_ACTION_RETURN, /* handled */
954 MOD_ACTION_RETURN, /* invalid */
955 MOD_ACTION_RETURN, /* userlock */
957 MOD_ACTION_RETURN, /* noop */
958 MOD_ACTION_RETURN /* updated */
965 MOD_ACTION_RETURN, /* reject */
966 MOD_ACTION_RETURN, /* fail */
968 MOD_ACTION_RETURN, /* handled */
969 MOD_ACTION_RETURN, /* invalid */
970 MOD_ACTION_RETURN, /* userlock */
977 MOD_ACTION_RETURN, /* reject */
979 MOD_ACTION_RETURN, /* ok */
980 MOD_ACTION_RETURN, /* handled */
981 MOD_ACTION_RETURN, /* invalid */
982 MOD_ACTION_RETURN, /* userlock */
983 MOD_ACTION_RETURN, /* notfound */
984 MOD_ACTION_RETURN, /* noop */
985 MOD_ACTION_RETURN /* updated */
989 MOD_ACTION_RETURN, /* reject */
991 MOD_ACTION_RETURN, /* ok */
992 MOD_ACTION_RETURN, /* handled */
993 MOD_ACTION_RETURN, /* invalid */
994 MOD_ACTION_RETURN, /* userlock */
996 MOD_ACTION_RETURN, /* noop */
997 MOD_ACTION_RETURN /* updated */
1004 MOD_ACTION_RETURN, /* reject */
1005 MOD_ACTION_RETURN, /* fail */
1007 MOD_ACTION_RETURN, /* handled */
1008 MOD_ACTION_RETURN, /* invalid */
1009 MOD_ACTION_RETURN, /* userlock */
1010 MOD_ACTION_RETURN, /* notfound */
1016 MOD_ACTION_RETURN, /* reject */
1018 MOD_ACTION_RETURN, /* ok */
1019 MOD_ACTION_RETURN, /* handled */
1020 MOD_ACTION_RETURN, /* invalid */
1021 MOD_ACTION_RETURN, /* userlock */
1022 MOD_ACTION_RETURN, /* notfound */
1023 MOD_ACTION_RETURN, /* noop */
1024 MOD_ACTION_RETURN /* updated */
1028 MOD_ACTION_RETURN, /* reject */
1030 MOD_ACTION_RETURN, /* ok */
1031 MOD_ACTION_RETURN, /* handled */
1032 MOD_ACTION_RETURN, /* invalid */
1033 MOD_ACTION_RETURN, /* userlock */
1035 MOD_ACTION_RETURN, /* noop */
1036 MOD_ACTION_RETURN /* updated */
1043 MOD_ACTION_RETURN, /* reject */
1044 MOD_ACTION_RETURN, /* fail */
1046 MOD_ACTION_RETURN, /* handled */
1047 MOD_ACTION_RETURN, /* invalid */
1048 MOD_ACTION_RETURN, /* userlock */
1049 MOD_ACTION_RETURN, /* notfound */
1057 MOD_ACTION_RETURN, /* ok */
1058 MOD_ACTION_RETURN, /* handled */
1067 MOD_ACTION_RETURN, /* reject */
1069 MOD_ACTION_RETURN, /* ok */
1070 MOD_ACTION_RETURN, /* handled */
1071 MOD_ACTION_RETURN, /* invalid */
1072 MOD_ACTION_RETURN, /* userlock */
1074 MOD_ACTION_RETURN, /* noop */
1075 MOD_ACTION_RETURN /* updated */
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 */
1088 MOD_ACTION_RETURN, /* notfound */
1089 MOD_ACTION_RETURN, /* noop */
1090 MOD_ACTION_RETURN /* updated */
1094 MOD_ACTION_RETURN, /* reject */
1096 MOD_ACTION_RETURN, /* ok */
1097 MOD_ACTION_RETURN, /* handled */
1098 MOD_ACTION_RETURN, /* invalid */
1099 MOD_ACTION_RETURN, /* userlock */
1100 MOD_ACTION_RETURN, /* notfound */
1101 MOD_ACTION_RETURN, /* noop */
1102 MOD_ACTION_RETURN /* updated */
1106 MOD_ACTION_RETURN, /* reject */
1108 MOD_ACTION_RETURN, /* ok */
1109 MOD_ACTION_RETURN, /* handled */
1110 MOD_ACTION_RETURN, /* invalid */
1111 MOD_ACTION_RETURN, /* userlock */
1112 MOD_ACTION_RETURN, /* notfound */
1113 MOD_ACTION_RETURN, /* noop */
1114 MOD_ACTION_RETURN /* updated */
1121 MOD_ACTION_RETURN, /* reject */
1122 MOD_ACTION_RETURN, /* fail */
1124 MOD_ACTION_RETURN, /* handled */
1125 MOD_ACTION_RETURN, /* invalid */
1126 MOD_ACTION_RETURN, /* userlock */
1133 MOD_ACTION_RETURN, /* reject */
1135 MOD_ACTION_RETURN, /* ok */
1136 MOD_ACTION_RETURN, /* handled */
1137 MOD_ACTION_RETURN, /* invalid */
1138 MOD_ACTION_RETURN, /* userlock */
1139 MOD_ACTION_RETURN, /* notfound */
1140 MOD_ACTION_RETURN, /* noop */
1141 MOD_ACTION_RETURN /* updated */
1145 MOD_ACTION_RETURN, /* reject */
1147 MOD_ACTION_RETURN, /* ok */
1148 MOD_ACTION_RETURN, /* handled */
1149 MOD_ACTION_RETURN, /* invalid */
1150 MOD_ACTION_RETURN, /* userlock */
1152 MOD_ACTION_RETURN, /* noop */
1153 MOD_ACTION_RETURN /* updated */
1160 MOD_ACTION_RETURN, /* reject */
1161 MOD_ACTION_RETURN, /* fail */
1163 MOD_ACTION_RETURN, /* handled */
1164 MOD_ACTION_RETURN, /* invalid */
1165 MOD_ACTION_RETURN, /* userlock */
1172 MOD_ACTION_RETURN, /* reject */
1174 MOD_ACTION_RETURN, /* ok */
1175 MOD_ACTION_RETURN, /* handled */
1176 MOD_ACTION_RETURN, /* invalid */
1177 MOD_ACTION_RETURN, /* userlock */
1178 MOD_ACTION_RETURN, /* notfound */
1179 MOD_ACTION_RETURN, /* noop */
1180 MOD_ACTION_RETURN /* updated */
1184 MOD_ACTION_RETURN, /* reject */
1186 MOD_ACTION_RETURN, /* ok */
1187 MOD_ACTION_RETURN, /* handled */
1188 MOD_ACTION_RETURN, /* invalid */
1189 MOD_ACTION_RETURN, /* userlock */
1191 MOD_ACTION_RETURN, /* noop */
1192 MOD_ACTION_RETURN /* updated */
1199 MOD_ACTION_RETURN, /* reject */
1200 MOD_ACTION_RETURN, /* fail */
1202 MOD_ACTION_RETURN, /* handled */
1203 MOD_ACTION_RETURN, /* invalid */
1204 MOD_ACTION_RETURN, /* userlock */
1211 MOD_ACTION_RETURN, /* reject */
1213 MOD_ACTION_RETURN, /* ok */
1214 MOD_ACTION_RETURN, /* handled */
1215 MOD_ACTION_RETURN, /* invalid */
1216 MOD_ACTION_RETURN, /* userlock */
1217 MOD_ACTION_RETURN, /* notfound */
1218 MOD_ACTION_RETURN, /* noop */
1219 MOD_ACTION_RETURN /* updated */
1223 MOD_ACTION_RETURN, /* reject */
1225 MOD_ACTION_RETURN, /* ok */
1226 MOD_ACTION_RETURN, /* handled */
1227 MOD_ACTION_RETURN, /* invalid */
1228 MOD_ACTION_RETURN, /* userlock */
1230 MOD_ACTION_RETURN, /* noop */
1231 MOD_ACTION_RETURN /* updated */
1240 MOD_ACTION_RETURN, /* reject */
1241 MOD_ACTION_RETURN, /* fail */
1243 MOD_ACTION_RETURN, /* handled */
1244 MOD_ACTION_RETURN, /* invalid */
1245 MOD_ACTION_RETURN, /* userlock */
1252 MOD_ACTION_RETURN, /* reject */
1254 MOD_ACTION_RETURN, /* ok */
1255 MOD_ACTION_RETURN, /* handled */
1256 MOD_ACTION_RETURN, /* invalid */
1257 MOD_ACTION_RETURN, /* userlock */
1258 MOD_ACTION_RETURN, /* notfound */
1259 MOD_ACTION_RETURN, /* noop */
1260 MOD_ACTION_RETURN /* updated */
1264 MOD_ACTION_RETURN, /* reject */
1266 MOD_ACTION_RETURN, /* ok */
1267 MOD_ACTION_RETURN, /* handled */
1268 MOD_ACTION_RETURN, /* invalid */
1269 MOD_ACTION_RETURN, /* userlock */
1271 MOD_ACTION_RETURN, /* noop */
1272 MOD_ACTION_RETURN /* updated */
1279 MOD_ACTION_RETURN, /* reject */
1280 MOD_ACTION_RETURN, /* fail */
1282 MOD_ACTION_RETURN, /* handled */
1283 MOD_ACTION_RETURN, /* invalid */
1284 MOD_ACTION_RETURN, /* userlock */
1291 MOD_ACTION_RETURN, /* reject */
1293 MOD_ACTION_RETURN, /* ok */
1294 MOD_ACTION_RETURN, /* handled */
1295 MOD_ACTION_RETURN, /* invalid */
1296 MOD_ACTION_RETURN, /* userlock */
1297 MOD_ACTION_RETURN, /* notfound */
1298 MOD_ACTION_RETURN, /* noop */
1299 MOD_ACTION_RETURN /* updated */
1303 MOD_ACTION_RETURN, /* reject */
1305 MOD_ACTION_RETURN, /* ok */
1306 MOD_ACTION_RETURN, /* handled */
1307 MOD_ACTION_RETURN, /* invalid */
1308 MOD_ACTION_RETURN, /* userlock */
1310 MOD_ACTION_RETURN, /* noop */
1311 MOD_ACTION_RETURN /* updated */
1319 static modcallable *do_compile_modupdate(modcallable *parent,
1320 int component, CONF_SECTION *cs,
1324 const char *vp_name;
1326 modcallable *csingle;
1328 VALUE_PAIR *head, **tail;
1330 static const char *attrlist_names[] = {
1331 "request", "reply", "proxy-request", "proxy-reply",
1332 "config", "control",
1333 "coa", "coa-reply", "disconnect", "disconnect-reply",
1337 component = component; /* -Wunused */
1339 if (!cf_section_name2(cs)) {
1340 cf_log_err(cf_sectiontoitem(cs),
1341 "Require list name for 'update'.\n");
1346 if (strncmp(vp_name, "outer.", 6) == 0) {
1350 for (i = 0; attrlist_names[i] != NULL; i++) {
1351 if (strcmp(vp_name, attrlist_names[i]) == 0) {
1358 cf_log_err(cf_sectiontoitem(cs),
1359 "Unknown attribute list \"%s\"",
1368 * Walk through the children of the update section,
1369 * ensuring that they're all known attributes.
1371 for (ci=cf_item_find_next(cs, NULL);
1373 ci=cf_item_find_next(cs, ci)) {
1377 if (cf_item_is_section(ci)) {
1378 cf_log_err(ci, "\"update\" sections cannot have subsections");
1382 if (!cf_item_is_pair(ci)) continue;
1384 cp = cf_itemtopair(ci); /* can't return NULL */
1385 vp = cf_pairtovp(cp);
1388 cf_log_err(ci, "ERROR: %s", fr_strerror());
1392 if ((vp->operator != T_OP_EQ) &&
1393 (vp->operator != T_OP_CMP_EQ) &&
1394 (vp->operator != T_OP_ADD) &&
1395 (vp->operator != T_OP_SUB) &&
1396 (vp->operator != T_OP_LE) &&
1397 (vp->operator != T_OP_GE) &&
1398 (vp->operator != T_OP_CMP_FALSE) &&
1399 (vp->operator != T_OP_SET)) {
1402 cf_log_err(ci, "Invalid operator for attribute");
1407 * A few more sanity checks. The enforcement of
1408 * <= or >= can only happen for integer
1411 if ((vp->operator == T_OP_LE) ||
1412 (vp->operator == T_OP_GE)) {
1413 if ((vp->type != PW_TYPE_BYTE) &&
1414 (vp->type != PW_TYPE_SHORT) &&
1415 (vp->type != PW_TYPE_INTEGER)) {
1418 cf_log_err(ci, "Enforcment of <= or >= is possible only for integer attributes");
1428 cf_log_err(cf_sectiontoitem(cs),
1429 "ERROR: update %s section cannot be empty",
1434 g = rad_malloc(sizeof(*g)); /* never fails */
1435 memset(g, 0, sizeof(*g));
1436 csingle = mod_grouptocallable(g);
1438 csingle->parent = parent;
1439 csingle->next = NULL;
1440 csingle->name = name2;
1441 csingle->type = MOD_UPDATE;
1442 csingle->method = component;
1444 g->grouptype = GROUPTYPE_SIMPLE;
1453 static modcallable *do_compile_modswitch(modcallable *parent,
1454 int component, CONF_SECTION *cs)
1456 modcallable *csingle;
1458 int had_seen_default = FALSE;
1460 component = component; /* -Wunused */
1462 if (!cf_section_name2(cs)) {
1463 cf_log_err(cf_sectiontoitem(cs),
1464 "You must specify a variable to switch over for 'switch'.");
1468 if (!cf_item_find_next(cs, NULL)) {
1469 cf_log_err(cf_sectiontoitem(cs), "'switch' statments cannot be empty.");
1474 * Walk through the children of the switch section,
1475 * ensuring that they're all 'case' statements
1477 for (ci=cf_item_find_next(cs, NULL);
1479 ci=cf_item_find_next(cs, ci)) {
1480 CONF_SECTION *subcs;
1481 const char *name1, *name2;
1483 if (!cf_item_is_section(ci)) {
1484 if (!cf_item_is_pair(ci)) continue;
1486 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1490 subcs = cf_itemtosection(ci); /* can't return NULL */
1491 name1 = cf_section_name1(subcs);
1493 if (strcmp(name1, "case") != 0) {
1494 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1498 name2 = cf_section_name2(subcs);
1499 if (!name2 && !had_seen_default) {
1500 had_seen_default = TRUE;
1504 if (!name2 || (name2[0] == '\0')) {
1505 cf_log_err(ci, "\"case\" sections must have a name");
1510 csingle= do_compile_modgroup(parent, component, cs,
1511 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1512 if (!csingle) return NULL;
1513 csingle->type = MOD_SWITCH;
1518 static modcallable *do_compile_modserver(modcallable *parent,
1519 int component, CONF_ITEM *ci,
1524 modcallable *csingle;
1525 CONF_SECTION *subcs;
1528 subcs = cf_section_sub_find_name2(cs, comp2str[component], NULL);
1530 cf_log_err(ci, "Server %s has no %s section",
1531 server, comp2str[component]);
1535 mr = rad_malloc(sizeof(*mr));
1536 memset(mr, 0, sizeof(*mr));
1538 csingle = mod_reftocallable(mr);
1539 csingle->parent = parent;
1540 csingle->next = NULL;
1541 csingle->name = name;
1542 csingle->type = MOD_REFERENCE;
1543 csingle->method = component;
1545 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1546 sizeof(csingle->actions));
1548 mr->ref_name = strdup(server);
1554 static modcallable *do_compile_modxlat(modcallable *parent,
1555 int component, const char *fmt)
1557 modcallable *csingle;
1560 mx = rad_malloc(sizeof(*mx));
1561 memset(mx, 0, sizeof(*mx));
1563 csingle = mod_xlattocallable(mx);
1564 csingle->parent = parent;
1565 csingle->next = NULL;
1566 csingle->name = "expand";
1567 csingle->type = MOD_XLAT;
1568 csingle->method = component;
1570 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1571 sizeof(csingle->actions));
1573 mx->xlat_name = strdup(fmt);
1574 if (fmt[0] != '%') {
1578 strcpy(mx->xlat_name, fmt + 1);
1579 p = strrchr(mx->xlat_name, '`');
1587 * redundant, etc. can refer to modules or groups, but not much else.
1589 static int all_children_are_modules(CONF_SECTION *cs, const char *name)
1593 for (ci=cf_item_find_next(cs, NULL);
1595 ci=cf_item_find_next(cs, ci)) {
1597 * If we're a redundant, etc. group, then the
1598 * intention is to call modules, rather than
1599 * processing logic. These checks aren't
1600 * *strictly* necessary, but they keep the users
1601 * from doing crazy things.
1603 if (cf_item_is_section(ci)) {
1604 CONF_SECTION *subcs = cf_itemtosection(ci);
1605 const char *name1 = cf_section_name1(subcs);
1607 if ((strcmp(name1, "if") == 0) ||
1608 (strcmp(name1, "else") == 0) ||
1609 (strcmp(name1, "elsif") == 0) ||
1610 (strcmp(name1, "update") == 0) ||
1611 (strcmp(name1, "switch") == 0) ||
1612 (strcmp(name1, "case") == 0)) {
1613 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
1620 if (cf_item_is_pair(ci)) {
1621 CONF_PAIR *cp = cf_itemtopair(ci);
1622 if (cf_pair_value(cp) != NULL) {
1624 "Entry with no value is invalid");
1635 * Compile one entry of a module call.
1637 static modcallable *do_compile_modsingle(modcallable *parent,
1638 int component, CONF_ITEM *ci,
1640 const char **modname)
1645 const char *modrefname;
1647 modcallable *csingle;
1648 module_instance_t *this;
1649 CONF_SECTION *cs, *subcs, *modules;
1651 if (cf_item_is_section(ci)) {
1654 cs = cf_itemtosection(ci);
1655 modrefname = cf_section_name1(cs);
1656 name2 = cf_section_name2(cs);
1657 if (!name2) name2 = "_UnNamedGroup";
1660 * group{}, redundant{}, or append{} may appear
1661 * where a single module instance was expected.
1662 * In that case, we hand it off to
1665 if (strcmp(modrefname, "group") == 0) {
1667 return do_compile_modgroup(parent, component, cs,
1671 } else if (strcmp(modrefname, "redundant") == 0) {
1674 if (!all_children_are_modules(cs, modrefname)) {
1678 return do_compile_modgroup(parent, component, cs,
1679 GROUPTYPE_REDUNDANT,
1682 } else if (strcmp(modrefname, "append") == 0) {
1684 return do_compile_modgroup(parent, component, cs,
1688 } else if (strcmp(modrefname, "load-balance") == 0) {
1691 if (!all_children_are_modules(cs, modrefname)) {
1695 csingle= do_compile_modgroup(parent, component, cs,
1698 if (!csingle) return NULL;
1699 csingle->type = MOD_LOAD_BALANCE;
1702 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1705 if (!all_children_are_modules(cs, modrefname)) {
1709 csingle= do_compile_modgroup(parent, component, cs,
1710 GROUPTYPE_REDUNDANT,
1712 if (!csingle) return NULL;
1713 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1717 } else if (strcmp(modrefname, "if") == 0) {
1718 if (!cf_section_name2(cs)) {
1719 cf_log_err(ci, "'if' without condition.");
1724 csingle= do_compile_modgroup(parent, component, cs,
1727 if (!csingle) return NULL;
1728 csingle->type = MOD_IF;
1730 if (!radius_evaluate_condition(NULL, 0, 0, modname,
1732 modcallable_free(&csingle);
1739 } else if (strcmp(modrefname, "elsif") == 0) {
1741 ((parent->type == MOD_LOAD_BALANCE) ||
1742 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1743 cf_log_err(ci, "'elsif' cannot be used in this section.");
1747 if (!cf_section_name2(cs)) {
1748 cf_log_err(ci, "'elsif' without condition.");
1753 csingle= do_compile_modgroup(parent, component, cs,
1756 if (!csingle) return NULL;
1757 csingle->type = MOD_ELSIF;
1759 if (!radius_evaluate_condition(NULL, 0, 0, modname,
1761 modcallable_free(&csingle);
1768 } else if (strcmp(modrefname, "else") == 0) {
1770 ((parent->type == MOD_LOAD_BALANCE) ||
1771 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1772 cf_log_err(ci, "'else' cannot be used in this section section.");
1776 if (cf_section_name2(cs)) {
1777 cf_log_err(ci, "Cannot have conditions on 'else'.");
1782 csingle= do_compile_modgroup(parent, component, cs,
1785 if (!csingle) return NULL;
1786 csingle->type = MOD_ELSE;
1789 } else if (strcmp(modrefname, "update") == 0) {
1792 csingle = do_compile_modupdate(parent, component, cs,
1794 if (!csingle) return NULL;
1798 } else if (strcmp(modrefname, "switch") == 0) {
1801 csingle = do_compile_modswitch(parent, component, cs);
1802 if (!csingle) return NULL;
1806 } else if (strcmp(modrefname, "case") == 0) {
1812 * FIXME: How to tell that the parent can only
1813 * be a "switch" statement?
1816 cf_log_err(ci, "\"case\" statements may only appear within a \"switch\" section");
1820 csingle= do_compile_modgroup(parent, component, cs,
1823 if (!csingle) return NULL;
1824 csingle->type = MOD_CASE;
1825 csingle->name = cf_section_name2(cs); /* may be NULL */
1828 * Set all of it's codes to return, so that
1829 * when we pick a 'case' statement, we don't
1830 * fall through to processing the next one.
1832 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1833 csingle->actions[i] = MOD_ACTION_RETURN;
1838 } /* else it's something like sql { fail = 1 ...} */
1840 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
1844 * Else it's a module reference, with updated return
1849 CONF_PAIR *cp = cf_itemtopair(ci);
1850 modrefname = cf_pair_attr(cp);
1853 * Actions (ok = 1), etc. are orthoganal to just
1854 * about everything else.
1856 if (cf_pair_value(cp) != NULL) {
1857 cf_log_err(ci, "Entry is not a reference to a module");
1861 if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
1862 (modrefname[0] == '`')) {
1863 return do_compile_modxlat(parent, component,
1868 * See if the module is a virtual one. If so,
1869 * return that, rather than doing anything here.
1872 cs = cf_section_find("instantiate");
1873 if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
1876 (cs = cf_section_find("policy")) != NULL) {
1879 snprintf(buffer, sizeof(buffer), "%s.%s",
1880 modrefname, comp2str[component]);
1883 * Prefer name.section, then name.
1885 subcs = cf_section_sub_find_name2(cs, NULL,
1888 subcs = cf_section_sub_find_name2(cs, NULL,
1894 * Allow policies to over-ride module names.
1895 * i.e. the "sql" policy can do some extra things,
1896 * and then call the "sql" module.
1898 for (loop = cf_item_parent(ci);
1900 loop = cf_item_parent(cf_sectiontoitem(loop))) {
1901 if (loop == subcs) {
1907 DEBUG2(" Module: Loading virtual module %s",
1911 * redundant foo {} is a single.
1913 if (cf_section_name2(subcs)) {
1914 return do_compile_modsingle(parent,
1916 cf_sectiontoitem(subcs),
1921 * foo {} is a group.
1923 return do_compile_modgroup(parent,
1933 * Not a virtual module. It must be a real module.
1935 modules = cf_section_find("modules");
1938 if (modules && cf_section_sub_find_name2(modules, NULL, modrefname)) {
1939 this = find_module_instance(modules, modrefname, 1);
1947 * Maybe it's module.method
1949 p = strrchr(modrefname, '.');
1950 if (p) for (i = RLM_COMPONENT_AUTH;
1951 i < RLM_COMPONENT_COUNT;
1953 if (strcmp(p + 1, comp2str[i]) == 0) {
1956 strlcpy(buffer, modrefname, sizeof(buffer));
1957 buffer[p - modrefname] = '\0';
1960 this = find_module_instance(cf_section_find("modules"), buffer, 1);
1962 !this->entry->module->methods[i]) {
1964 cf_log_err(ci, "Module %s has no such method %s", buffer, comp2str[i]);
1972 if (strncmp(modrefname, "server[", 7) == 0) {
1975 strlcpy(buffer, modrefname + 7, sizeof(buffer));
1976 p = strrchr(buffer, ']');
1977 if (!p || p[1] != '\0' || (p == buffer)) {
1978 cf_log_err(ci, "Invalid server reference in \"%s\".", modrefname);
1983 cs = cf_section_sub_find_name2(NULL, "server", buffer);
1985 cf_log_err(ci, "No such server \"%s\".", buffer);
1989 return do_compile_modserver(parent, component, ci,
1990 modrefname, cs, buffer);
1994 cf_log_err(ci, "Failed to find \"%s\" in the \"modules\" section.", modrefname);
1999 * We know it's all OK, allocate the structures, and fill
2002 single = rad_malloc(sizeof(*single));
2003 memset(single, 0, sizeof(*single));
2004 csingle = mod_singletocallable(single);
2005 csingle->parent = parent;
2006 csingle->next = NULL;
2007 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2008 memcpy(csingle->actions, defaultactions[component][grouptype],
2009 sizeof csingle->actions);
2010 } else { /* inside Auth-Type has different rules */
2011 memcpy(csingle->actions, defaultactions[RLM_COMPONENT_AUTZ][grouptype],
2012 sizeof csingle->actions);
2014 rad_assert(modrefname != NULL);
2015 csingle->name = modrefname;
2016 csingle->type = MOD_SINGLE;
2017 csingle->method = component;
2020 * Singles can override the actions, virtual modules cannot.
2022 * FIXME: We may want to re-visit how to do this...
2023 * maybe a csingle as a ref?
2025 if (cf_item_is_section(ci)) {
2028 cs = cf_itemtosection(ci);
2029 for (csi=cf_item_find_next(cs, NULL);
2031 csi=cf_item_find_next(cs, csi)) {
2033 if (cf_item_is_section(csi)) {
2034 cf_log_err(csi, "Subsection of module instance call not allowed");
2035 modcallable_free(&csingle);
2039 if (!cf_item_is_pair(csi)) continue;
2041 if (!compile_action(csingle, cf_itemtopair(csi))) {
2042 modcallable_free(&csingle);
2049 * Bail out if the module in question does not supply the
2052 if (!this->entry->module->methods[component]) {
2053 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
2054 comp2str[component]);
2055 modcallable_free(&csingle);
2059 single->modinst = this;
2060 *modname = this->entry->module->name;
2064 modcallable *compile_modsingle(modcallable *parent,
2065 int component, CONF_ITEM *ci,
2066 const char **modname)
2068 modcallable *ret = do_compile_modsingle(parent, component, ci,
2071 dump_tree(component, ret);
2077 * Internal compile group code.
2079 static modcallable *do_compile_modgroup(modcallable *parent,
2080 int component, CONF_SECTION *cs,
2081 int grouptype, int parentgrouptype)
2088 g = rad_malloc(sizeof(*g));
2089 memset(g, 0, sizeof(*g));
2090 g->grouptype = grouptype;
2092 c = mod_grouptocallable(g);
2094 c->type = MOD_GROUP;
2096 memset(c->actions, 0, sizeof(c->actions));
2099 * Remember the name for printing, etc.
2101 * FIXME: We may also want to put the names into a
2102 * rbtree, so that groups can reference each other...
2104 c->name = cf_section_name2(cs);
2106 c->name = cf_section_name1(cs);
2107 if (strcmp(c->name, "group") == 0) {
2110 c->type = MOD_POLICY;
2116 * Loop over the children of this group.
2118 for (ci=cf_item_find_next(cs, NULL);
2120 ci=cf_item_find_next(cs, ci)) {
2123 * Sections are references to other groups, or
2124 * to modules with updated return codes.
2126 if (cf_item_is_section(ci)) {
2127 const char *junk = NULL;
2128 modcallable *single;
2129 CONF_SECTION *subcs = cf_itemtosection(ci);
2131 single = do_compile_modsingle(c, component, ci,
2134 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
2135 cf_section_name1(subcs));
2136 modcallable_free(&c);
2139 add_child(g, single);
2141 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
2145 const char *attr, *value;
2146 CONF_PAIR *cp = cf_itemtopair(ci);
2148 attr = cf_pair_attr(cp);
2149 value = cf_pair_value(cp);
2152 * A CONF_PAIR is either a module
2153 * instance with no actions
2157 modcallable *single;
2158 const char *junk = NULL;
2160 single = do_compile_modsingle(c,
2167 "Failed to parse \"%s\" entry.",
2169 modcallable_free(&c);
2172 add_child(g, single);
2175 * Or a module instance with action.
2177 } else if (!compile_action(c, cp)) {
2178 modcallable_free(&c);
2180 } /* else it worked */
2185 * Set the default actions, if they haven't already been
2188 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2189 if (!c->actions[i]) {
2190 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2191 c->actions[i] = defaultactions[component][parentgrouptype][i];
2192 } else { /* inside Auth-Type has different rules */
2193 c->actions[i] = defaultactions[RLM_COMPONENT_AUTZ][parentgrouptype][i];
2199 * FIXME: If there are no children, return NULL?
2201 return mod_grouptocallable(g);
2204 modcallable *compile_modgroup(modcallable *parent,
2205 int component, CONF_SECTION *cs)
2207 modcallable *ret = do_compile_modgroup(parent, component, cs,
2210 dump_tree(component, ret);
2214 void add_to_modcallable(modcallable **parent, modcallable *this,
2215 int component, const char *name)
2219 rad_assert(this != NULL);
2221 if (*parent == NULL) {
2224 g = rad_malloc(sizeof *g);
2225 memset(g, 0, sizeof(*g));
2226 g->grouptype = GROUPTYPE_SIMPLE;
2227 c = mod_grouptocallable(g);
2230 defaultactions[component][GROUPTYPE_SIMPLE],
2231 sizeof(c->actions));
2232 rad_assert(name != NULL);
2234 c->type = MOD_GROUP;
2235 c->method = component;
2238 *parent = mod_grouptocallable(g);
2240 g = mod_callabletogroup(*parent);
2246 void modcallable_free(modcallable **pc)
2248 modcallable *c, *loop, *next;
2250 if (!pc || !*pc) return;
2254 if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
2255 modgroup *g = mod_callabletogroup(c);
2257 if (g->children) for (loop = g->children;
2261 modcallable_free(&loop);