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->force) {
294 myresult = sp->modinst->code;
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,
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;
435 * Interpret the various types of blocks.
437 static int modcall_recurse(REQUEST *request, int component, int depth,
438 modcall_stack_entry_t *entry)
440 int if_taken, was_if;
442 int result, priority;
444 was_if = if_taken = FALSE;
445 result = RLM_MODULE_FAIL;
452 * Nothing more to do. Return the code and priority
453 * which was set by the caller.
458 * We've been asked to stop. Do so.
460 if ((request->master_state == REQUEST_STOP_PROCESSING) ||
462 (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
463 entry->result = RLM_MODULE_FAIL;
464 entry->priority = 9999;
469 * Handle "if" conditions.
471 if (c->type == MOD_IF) {
477 g = mod_callabletogroup(c);
480 RDEBUG2("%.*s? %s %s", depth + 1, modcall_spaces,
481 group_name[c->type], c->name);
483 if (radius_evaluate_condition(request, result,
484 0, &p, TRUE, &condition)) {
485 RDEBUG2("%.*s? %s %s -> %s", depth + 1, modcall_spaces,
487 c->name, condition ? "TRUE" : "FALSE");
493 * Didn't pass. Remember that.
502 * We took the "if". Go recurse into its' children.
510 * "else" if the previous "if" was taken.
511 * "if" if the previous if wasn't taken.
513 if (c->type == MOD_ELSIF) {
514 if (!was_if) goto elsif_error;
517 * Like MOD_ELSE, but allow for a later "else"
520 RDEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
521 depth + 1, modcall_spaces,
522 group_name[c->type], request->number);
529 * Check the "if" condition.
535 * "else" for a preceding "if".
537 if (c->type == MOD_ELSE) {
538 if (!was_if) { /* error */
540 RDEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",
541 depth + 1, modcall_spaces,
542 group_name[c->type], request->number);
547 RDEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
548 depth + 1, modcall_spaces,
549 group_name[c->type], request->number);
556 * We need to process it. Go do that.
564 * We're no longer processing if/else/elsif. Reset the
565 * trackers for those conditions.
570 if (c->type == MOD_SINGLE) {
574 * Process a stand-alone child, and fall through
575 * to dealing with it's parent.
577 sp = mod_callabletosingle(c);
579 result = call_modsingle(c->method, sp, request);
580 RDEBUG2("%.*s[%s] = %s", depth + 1, modcall_spaces, c->name ? c->name : "",
581 fr_int2str(mod_rcode_table, result, "<invalid>"));
582 goto calculate_result;
586 * Update attribute(s)
588 if (c->type == MOD_UPDATE) {
590 modgroup *g = mod_callabletogroup(c);
592 MOD_LOG_OPEN_BRACE("update");
593 rcode = radius_update_attrlist(request, g->cs,
595 if (rcode != RLM_MODULE_UPDATED) {
598 result = RLM_MODULE_NOOP;
600 MOD_LOG_CLOSE_BRACE();
601 goto calculate_result;
605 * Child is a group that has children of it's own.
607 if ((c->type == MOD_GROUP) || (c->type == MOD_POLICY) ||
608 (c->type == MOD_CASE)) {
612 g = mod_callabletogroup(c);
615 * This should really have been caught in the
616 * compiler, and the node never generated. But
617 * doing that requires changing it's API so that
618 * it returns a flag instead of the compiled
622 RDEBUG2("%.*s%s %s { ... } # empty sub-section is ignored",
623 depth + 1, modcall_spaces, group_name[c->type], c->name);
627 MOD_LOG_OPEN_BRACE(group_name[c->type]);
628 modcall_child(request, component,
629 depth + 1, entry, g->children,
631 MOD_LOG_CLOSE_BRACE();
632 goto calculate_result;
635 if (c->type == MOD_SWITCH) {
636 modcallable *this, *found, *null_case;
640 MOD_LOG_OPEN_BRACE("switch");
643 * If there's no %, it refers to an attribute.
644 * Otherwise, expand it.
646 if (!strchr(c->name, '%')) {
647 VALUE_PAIR *vp = NULL;
649 if (radius_get_vp(request, c->name, &vp) && vp) {
650 vp_prints_value(buffer,
657 radius_xlat(buffer, sizeof(buffer),
658 c->name, request, NULL);
662 * Find either the exact matching name, or the
663 * "case {...}" statement.
665 g = mod_callabletogroup(c);
666 null_case = found = NULL;
667 for (this = g->children; this; this = this->next) {
669 if (!null_case) null_case = this;
672 if (strcmp(buffer, this->name) == 0) {
678 if (!found) found = null_case;
680 MOD_LOG_OPEN_BRACE(group_name[c->type]);
681 modcall_child(request, component,
682 depth + 1, entry, found,
684 MOD_LOG_CLOSE_BRACE();
685 goto calculate_result;
688 if ((c->type == MOD_LOAD_BALANCE) ||
689 (c->type == MOD_REDUNDANT_LOAD_BALANCE)) {
691 modcallable *this, *found;
694 MOD_LOG_OPEN_BRACE("load-balance");
696 g = mod_callabletogroup(c);
698 for (this = g->children; this; this = this->next) {
706 if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
711 MOD_LOG_OPEN_BRACE(group_name[c->type]);
713 if (c->type == MOD_LOAD_BALANCE) {
714 modcall_child(request, component,
715 depth + 1, entry, found,
722 * Loop over all children in this
723 * section. If we get FAIL, then
724 * continue. Otherwise, stop.
726 for (i = 0; i < count; i++) {
727 modcall_child(request, component,
728 depth + 1, entry, found,
730 if (found->actions[result] == MOD_ACTION_RETURN) {
736 if (!found) found = g->children;
739 MOD_LOG_CLOSE_BRACE();
740 goto calculate_result;
741 } /* MOD_LOAD_BALANCE */
744 * Reference another virtual server.
746 * This should really be deleted, and replaced with a
747 * more abstracted / functional version.
749 if (c->type == MOD_REFERENCE) {
750 modref *mr = mod_callabletoref(c);
751 char const *server = request->server;
753 if (server == mr->ref_name) {
754 radlog(L_INFO, "WARNING: Suppressing recursive call to server %s", server);
758 request->server = mr->ref_name;
759 RDEBUG("server %s { # nested call", mr->ref_name);
760 result = indexed_modcall(component, 0, request);
761 RDEBUG("} # server %s with nested call", mr->ref_name);
762 request->server = server;
763 goto calculate_result;
764 } /* MOD_REFERENCE */
767 * xlat a string without doing anything else
769 * This should really be deleted, and replaced with a
770 * more abstracted / functional version.
772 if (c->type == MOD_XLAT) {
773 modxlat *mx = mod_callabletoxlat(c);
777 radius_xlat(buffer, sizeof(buffer),
778 mx->xlat_name, request, NULL);
780 RDEBUG("`%s`", mx->xlat_name);
781 radius_exec_program(mx->xlat_name, request,
784 request->packet->vps,
792 * Add new module types here.
797 RDEBUG("(%s, %d) ? (%s, %d)",
798 fr_int2str(mod_rcode_table, result, "<invalid>"),
800 fr_int2str(mod_rcode_table, entry->result, "<invalid>"),
805 * The child's action says return. Do so.
807 if ((c->actions[result] == MOD_ACTION_RETURN) &&
809 entry->result = result;
814 * If "reject", break out of the loop and return
817 if (c->actions[result] == MOD_ACTION_REJECT) {
818 entry->result = RLM_MODULE_REJECT;
823 * The array holds a default priority for this return
824 * code. Grab it in preference to any unset priority.
827 priority = c->actions[result];
831 * We're higher than any previous priority, remember this
832 * return code and priority.
834 if (priority > entry->priority) {
835 entry->result = result;
836 entry->priority = priority;
840 * If we're processing a "case" statement, we return once
841 * it's done, rather than going to the next "case" statement.
843 if (c->type == MOD_CASE) return TRUE;
846 entry->c = entry->c->next;
848 if (entry->c) goto redo;
858 * @brief Call a module, iteratively, with a local stack, rather than
859 * recursively. What did Paul Graham say about Lisp...?
861 int modcall(int component, modcallable *c, REQUEST *request)
863 modcall_stack_entry_t stack[MODCALL_STACK_MAX];
865 if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {
866 return RLM_MODULE_FAIL;
870 * Set up the initial stack frame.
873 stack[0].result = default_component_results[component];
874 stack[0].priority = 0;
877 * Call the main handler.
879 if (!modcall_recurse(request, component, 0, &stack[0])) {
880 return RLM_MODULE_FAIL;
886 return stack[0].result;
890 static const char *action2str(int action)
893 if(action==MOD_ACTION_RETURN)
895 if(action==MOD_ACTION_REJECT)
897 snprintf(buf, sizeof buf, "%d", action);
901 /* If you suspect a bug in the parser, you'll want to use these dump
902 * functions. dump_tree should reproduce a whole tree exactly as it was found
903 * in radiusd.conf, but in long form (all actions explicitly defined) */
904 static void dump_mc(modcallable *c, int indent)
908 if(c->type==MOD_SINGLE) {
909 modsingle *single = mod_callabletosingle(c);
910 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
911 single->modinst->name);
912 } else if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
913 modgroup *g = mod_callabletogroup(c);
915 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
916 group_name[c->type]);
917 for(p = g->children;p;p = p->next)
918 dump_mc(p, indent+1);
919 } /* else ignore it for now */
921 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
922 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
923 fr_int2str(rcode_table, i, "??"),
924 action2str(c->actions[i]));
927 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
930 static void dump_tree(int comp, modcallable *c)
932 RDEBUG("[%s]", comp2str[comp]);
936 #define dump_tree(a, b)
939 /* These are the default actions. For each component, the group{} block
940 * behaves like the code from the old module_*() function. redundant{} and
941 * append{} are based on my guesses of what they will be used for. --Pac. */
943 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
949 MOD_ACTION_RETURN, /* reject */
951 MOD_ACTION_RETURN, /* ok */
952 MOD_ACTION_RETURN, /* handled */
954 MOD_ACTION_RETURN, /* userlock */
955 MOD_ACTION_RETURN, /* notfound */
961 MOD_ACTION_RETURN, /* reject */
963 MOD_ACTION_RETURN, /* ok */
964 MOD_ACTION_RETURN, /* handled */
965 MOD_ACTION_RETURN, /* invalid */
966 MOD_ACTION_RETURN, /* userlock */
967 MOD_ACTION_RETURN, /* notfound */
968 MOD_ACTION_RETURN, /* noop */
969 MOD_ACTION_RETURN /* updated */
973 MOD_ACTION_RETURN, /* reject */
975 MOD_ACTION_RETURN, /* ok */
976 MOD_ACTION_RETURN, /* handled */
977 MOD_ACTION_RETURN, /* invalid */
978 MOD_ACTION_RETURN, /* userlock */
980 MOD_ACTION_RETURN, /* noop */
981 MOD_ACTION_RETURN /* updated */
988 MOD_ACTION_RETURN, /* reject */
989 MOD_ACTION_RETURN, /* fail */
991 MOD_ACTION_RETURN, /* handled */
992 MOD_ACTION_RETURN, /* invalid */
993 MOD_ACTION_RETURN, /* userlock */
1000 MOD_ACTION_RETURN, /* reject */
1002 MOD_ACTION_RETURN, /* ok */
1003 MOD_ACTION_RETURN, /* handled */
1004 MOD_ACTION_RETURN, /* invalid */
1005 MOD_ACTION_RETURN, /* userlock */
1006 MOD_ACTION_RETURN, /* notfound */
1007 MOD_ACTION_RETURN, /* noop */
1008 MOD_ACTION_RETURN /* updated */
1012 MOD_ACTION_RETURN, /* reject */
1014 MOD_ACTION_RETURN, /* ok */
1015 MOD_ACTION_RETURN, /* handled */
1016 MOD_ACTION_RETURN, /* invalid */
1017 MOD_ACTION_RETURN, /* userlock */
1019 MOD_ACTION_RETURN, /* noop */
1020 MOD_ACTION_RETURN /* updated */
1027 MOD_ACTION_RETURN, /* reject */
1028 MOD_ACTION_RETURN, /* fail */
1030 MOD_ACTION_RETURN, /* handled */
1031 MOD_ACTION_RETURN, /* invalid */
1032 MOD_ACTION_RETURN, /* userlock */
1033 MOD_ACTION_RETURN, /* notfound */
1039 MOD_ACTION_RETURN, /* reject */
1041 MOD_ACTION_RETURN, /* ok */
1042 MOD_ACTION_RETURN, /* handled */
1043 MOD_ACTION_RETURN, /* invalid */
1044 MOD_ACTION_RETURN, /* userlock */
1045 MOD_ACTION_RETURN, /* notfound */
1046 MOD_ACTION_RETURN, /* noop */
1047 MOD_ACTION_RETURN /* updated */
1051 MOD_ACTION_RETURN, /* reject */
1053 MOD_ACTION_RETURN, /* ok */
1054 MOD_ACTION_RETURN, /* handled */
1055 MOD_ACTION_RETURN, /* invalid */
1056 MOD_ACTION_RETURN, /* userlock */
1058 MOD_ACTION_RETURN, /* noop */
1059 MOD_ACTION_RETURN /* updated */
1066 MOD_ACTION_RETURN, /* reject */
1067 MOD_ACTION_RETURN, /* fail */
1069 MOD_ACTION_RETURN, /* handled */
1070 MOD_ACTION_RETURN, /* invalid */
1071 MOD_ACTION_RETURN, /* userlock */
1072 MOD_ACTION_RETURN, /* notfound */
1080 MOD_ACTION_RETURN, /* ok */
1081 MOD_ACTION_RETURN, /* handled */
1090 MOD_ACTION_RETURN, /* reject */
1092 MOD_ACTION_RETURN, /* ok */
1093 MOD_ACTION_RETURN, /* handled */
1094 MOD_ACTION_RETURN, /* invalid */
1095 MOD_ACTION_RETURN, /* userlock */
1097 MOD_ACTION_RETURN, /* noop */
1098 MOD_ACTION_RETURN /* updated */
1105 MOD_ACTION_RETURN, /* reject */
1107 MOD_ACTION_RETURN, /* ok */
1108 MOD_ACTION_RETURN, /* handled */
1109 MOD_ACTION_RETURN, /* invalid */
1110 MOD_ACTION_RETURN, /* userlock */
1111 MOD_ACTION_RETURN, /* notfound */
1112 MOD_ACTION_RETURN, /* noop */
1113 MOD_ACTION_RETURN /* updated */
1117 MOD_ACTION_RETURN, /* reject */
1119 MOD_ACTION_RETURN, /* ok */
1120 MOD_ACTION_RETURN, /* handled */
1121 MOD_ACTION_RETURN, /* invalid */
1122 MOD_ACTION_RETURN, /* userlock */
1123 MOD_ACTION_RETURN, /* notfound */
1124 MOD_ACTION_RETURN, /* noop */
1125 MOD_ACTION_RETURN /* updated */
1129 MOD_ACTION_RETURN, /* reject */
1131 MOD_ACTION_RETURN, /* ok */
1132 MOD_ACTION_RETURN, /* handled */
1133 MOD_ACTION_RETURN, /* invalid */
1134 MOD_ACTION_RETURN, /* userlock */
1135 MOD_ACTION_RETURN, /* notfound */
1136 MOD_ACTION_RETURN, /* noop */
1137 MOD_ACTION_RETURN /* updated */
1144 MOD_ACTION_RETURN, /* reject */
1145 MOD_ACTION_RETURN, /* fail */
1147 MOD_ACTION_RETURN, /* handled */
1148 MOD_ACTION_RETURN, /* invalid */
1149 MOD_ACTION_RETURN, /* userlock */
1156 MOD_ACTION_RETURN, /* reject */
1158 MOD_ACTION_RETURN, /* ok */
1159 MOD_ACTION_RETURN, /* handled */
1160 MOD_ACTION_RETURN, /* invalid */
1161 MOD_ACTION_RETURN, /* userlock */
1162 MOD_ACTION_RETURN, /* notfound */
1163 MOD_ACTION_RETURN, /* noop */
1164 MOD_ACTION_RETURN /* updated */
1168 MOD_ACTION_RETURN, /* reject */
1170 MOD_ACTION_RETURN, /* ok */
1171 MOD_ACTION_RETURN, /* handled */
1172 MOD_ACTION_RETURN, /* invalid */
1173 MOD_ACTION_RETURN, /* userlock */
1175 MOD_ACTION_RETURN, /* noop */
1176 MOD_ACTION_RETURN /* updated */
1183 MOD_ACTION_RETURN, /* reject */
1184 MOD_ACTION_RETURN, /* fail */
1186 MOD_ACTION_RETURN, /* handled */
1187 MOD_ACTION_RETURN, /* invalid */
1188 MOD_ACTION_RETURN, /* userlock */
1195 MOD_ACTION_RETURN, /* reject */
1197 MOD_ACTION_RETURN, /* ok */
1198 MOD_ACTION_RETURN, /* handled */
1199 MOD_ACTION_RETURN, /* invalid */
1200 MOD_ACTION_RETURN, /* userlock */
1201 MOD_ACTION_RETURN, /* notfound */
1202 MOD_ACTION_RETURN, /* noop */
1203 MOD_ACTION_RETURN /* updated */
1207 MOD_ACTION_RETURN, /* reject */
1209 MOD_ACTION_RETURN, /* ok */
1210 MOD_ACTION_RETURN, /* handled */
1211 MOD_ACTION_RETURN, /* invalid */
1212 MOD_ACTION_RETURN, /* userlock */
1214 MOD_ACTION_RETURN, /* noop */
1215 MOD_ACTION_RETURN /* updated */
1222 MOD_ACTION_RETURN, /* reject */
1223 MOD_ACTION_RETURN, /* fail */
1225 MOD_ACTION_RETURN, /* handled */
1226 MOD_ACTION_RETURN, /* invalid */
1227 MOD_ACTION_RETURN, /* userlock */
1234 MOD_ACTION_RETURN, /* reject */
1236 MOD_ACTION_RETURN, /* ok */
1237 MOD_ACTION_RETURN, /* handled */
1238 MOD_ACTION_RETURN, /* invalid */
1239 MOD_ACTION_RETURN, /* userlock */
1240 MOD_ACTION_RETURN, /* notfound */
1241 MOD_ACTION_RETURN, /* noop */
1242 MOD_ACTION_RETURN /* updated */
1246 MOD_ACTION_RETURN, /* reject */
1248 MOD_ACTION_RETURN, /* ok */
1249 MOD_ACTION_RETURN, /* handled */
1250 MOD_ACTION_RETURN, /* invalid */
1251 MOD_ACTION_RETURN, /* userlock */
1253 MOD_ACTION_RETURN, /* noop */
1254 MOD_ACTION_RETURN /* updated */
1263 MOD_ACTION_RETURN, /* reject */
1264 MOD_ACTION_RETURN, /* fail */
1266 MOD_ACTION_RETURN, /* handled */
1267 MOD_ACTION_RETURN, /* invalid */
1268 MOD_ACTION_RETURN, /* userlock */
1275 MOD_ACTION_RETURN, /* reject */
1277 MOD_ACTION_RETURN, /* ok */
1278 MOD_ACTION_RETURN, /* handled */
1279 MOD_ACTION_RETURN, /* invalid */
1280 MOD_ACTION_RETURN, /* userlock */
1281 MOD_ACTION_RETURN, /* notfound */
1282 MOD_ACTION_RETURN, /* noop */
1283 MOD_ACTION_RETURN /* updated */
1287 MOD_ACTION_RETURN, /* reject */
1289 MOD_ACTION_RETURN, /* ok */
1290 MOD_ACTION_RETURN, /* handled */
1291 MOD_ACTION_RETURN, /* invalid */
1292 MOD_ACTION_RETURN, /* userlock */
1294 MOD_ACTION_RETURN, /* noop */
1295 MOD_ACTION_RETURN /* updated */
1302 MOD_ACTION_RETURN, /* reject */
1303 MOD_ACTION_RETURN, /* fail */
1305 MOD_ACTION_RETURN, /* handled */
1306 MOD_ACTION_RETURN, /* invalid */
1307 MOD_ACTION_RETURN, /* userlock */
1314 MOD_ACTION_RETURN, /* reject */
1316 MOD_ACTION_RETURN, /* ok */
1317 MOD_ACTION_RETURN, /* handled */
1318 MOD_ACTION_RETURN, /* invalid */
1319 MOD_ACTION_RETURN, /* userlock */
1320 MOD_ACTION_RETURN, /* notfound */
1321 MOD_ACTION_RETURN, /* noop */
1322 MOD_ACTION_RETURN /* updated */
1326 MOD_ACTION_RETURN, /* reject */
1328 MOD_ACTION_RETURN, /* ok */
1329 MOD_ACTION_RETURN, /* handled */
1330 MOD_ACTION_RETURN, /* invalid */
1331 MOD_ACTION_RETURN, /* userlock */
1333 MOD_ACTION_RETURN, /* noop */
1334 MOD_ACTION_RETURN /* updated */
1342 static modcallable *do_compile_modupdate(modcallable *parent,
1343 int component, CONF_SECTION *cs,
1347 const char *vp_name;
1349 modcallable *csingle;
1351 VALUE_PAIR *head, **tail;
1353 static const char *attrlist_names[] = {
1354 "request", "reply", "proxy-request", "proxy-reply",
1355 "config", "control",
1356 "coa", "coa-reply", "disconnect", "disconnect-reply",
1360 component = component; /* -Wunused */
1362 if (!cf_section_name2(cs)) {
1363 cf_log_err(cf_sectiontoitem(cs),
1364 "Require list name for 'update'.\n");
1369 if (strncmp(vp_name, "outer.", 6) == 0) {
1373 for (i = 0; attrlist_names[i] != NULL; i++) {
1374 if (strcmp(vp_name, attrlist_names[i]) == 0) {
1381 cf_log_err(cf_sectiontoitem(cs),
1382 "Unknown attribute list \"%s\"",
1391 * Walk through the children of the update section,
1392 * ensuring that they're all known attributes.
1394 for (ci=cf_item_find_next(cs, NULL);
1396 ci=cf_item_find_next(cs, ci)) {
1400 if (cf_item_is_section(ci)) {
1401 cf_log_err(ci, "\"update\" sections cannot have subsections");
1405 if (!cf_item_is_pair(ci)) continue;
1407 cp = cf_itemtopair(ci); /* can't return NULL */
1408 vp = cf_pairtovp(cp);
1411 cf_log_err(ci, "ERROR: %s", fr_strerror());
1415 if ((vp->operator != T_OP_EQ) &&
1416 (vp->operator != T_OP_CMP_EQ) &&
1417 (vp->operator != T_OP_ADD) &&
1418 (vp->operator != T_OP_SUB) &&
1419 (vp->operator != T_OP_LE) &&
1420 (vp->operator != T_OP_GE) &&
1421 (vp->operator != T_OP_CMP_FALSE) &&
1422 (vp->operator != T_OP_SET)) {
1425 cf_log_err(ci, "Invalid operator for attribute");
1430 * A few more sanity checks. The enforcement of
1431 * <= or >= can only happen for integer
1434 if ((vp->operator == T_OP_LE) ||
1435 (vp->operator == T_OP_GE)) {
1436 if ((vp->type != PW_TYPE_BYTE) &&
1437 (vp->type != PW_TYPE_SHORT) &&
1438 (vp->type != PW_TYPE_INTEGER)) {
1441 cf_log_err(ci, "Enforcment of <= or >= is possible only for integer attributes");
1451 cf_log_err(cf_sectiontoitem(cs),
1452 "ERROR: update %s section cannot be empty",
1457 g = rad_malloc(sizeof(*g)); /* never fails */
1458 memset(g, 0, sizeof(*g));
1459 csingle = mod_grouptocallable(g);
1461 csingle->parent = parent;
1462 csingle->next = NULL;
1463 csingle->name = name2;
1464 csingle->type = MOD_UPDATE;
1465 csingle->method = component;
1467 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1468 sizeof(csingle->actions));
1470 g->grouptype = GROUPTYPE_SIMPLE;
1479 static modcallable *do_compile_modswitch(modcallable *parent,
1480 int component, CONF_SECTION *cs)
1482 modcallable *csingle;
1484 int had_seen_default = FALSE;
1486 component = component; /* -Wunused */
1488 if (!cf_section_name2(cs)) {
1489 cf_log_err(cf_sectiontoitem(cs),
1490 "You must specify a variable to switch over for 'switch'.");
1494 if (!cf_item_find_next(cs, NULL)) {
1495 cf_log_err(cf_sectiontoitem(cs), "'switch' statments cannot be empty.");
1500 * Walk through the children of the switch section,
1501 * ensuring that they're all 'case' statements
1503 for (ci=cf_item_find_next(cs, NULL);
1505 ci=cf_item_find_next(cs, ci)) {
1506 CONF_SECTION *subcs;
1507 const char *name1, *name2;
1509 if (!cf_item_is_section(ci)) {
1510 if (!cf_item_is_pair(ci)) continue;
1512 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1516 subcs = cf_itemtosection(ci); /* can't return NULL */
1517 name1 = cf_section_name1(subcs);
1519 if (strcmp(name1, "case") != 0) {
1520 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1524 name2 = cf_section_name2(subcs);
1525 if (!name2 && !had_seen_default) {
1526 had_seen_default = TRUE;
1530 if (!name2 || (name2[0] == '\0')) {
1531 cf_log_err(ci, "\"case\" sections must have a name");
1536 csingle= do_compile_modgroup(parent, component, cs,
1537 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1538 if (!csingle) return NULL;
1539 csingle->type = MOD_SWITCH;
1544 static modcallable *do_compile_modserver(modcallable *parent,
1545 int component, CONF_ITEM *ci,
1550 modcallable *csingle;
1551 CONF_SECTION *subcs;
1554 subcs = cf_section_sub_find_name2(cs, comp2str[component], NULL);
1556 cf_log_err(ci, "Server %s has no %s section",
1557 server, comp2str[component]);
1561 mr = rad_malloc(sizeof(*mr));
1562 memset(mr, 0, sizeof(*mr));
1564 csingle = mod_reftocallable(mr);
1565 csingle->parent = parent;
1566 csingle->next = NULL;
1567 csingle->name = name;
1568 csingle->type = MOD_REFERENCE;
1569 csingle->method = component;
1571 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1572 sizeof(csingle->actions));
1574 mr->ref_name = strdup(server);
1580 static modcallable *do_compile_modxlat(modcallable *parent,
1581 int component, const char *fmt)
1583 modcallable *csingle;
1586 mx = rad_malloc(sizeof(*mx));
1587 memset(mx, 0, sizeof(*mx));
1589 csingle = mod_xlattocallable(mx);
1590 csingle->parent = parent;
1591 csingle->next = NULL;
1592 csingle->name = "expand";
1593 csingle->type = MOD_XLAT;
1594 csingle->method = component;
1596 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1597 sizeof(csingle->actions));
1599 mx->xlat_name = strdup(fmt);
1600 if (fmt[0] != '%') {
1604 strcpy(mx->xlat_name, fmt + 1);
1605 p = strrchr(mx->xlat_name, '`');
1613 * redundant, etc. can refer to modules or groups, but not much else.
1615 static int all_children_are_modules(CONF_SECTION *cs, const char *name)
1619 for (ci=cf_item_find_next(cs, NULL);
1621 ci=cf_item_find_next(cs, ci)) {
1623 * If we're a redundant, etc. group, then the
1624 * intention is to call modules, rather than
1625 * processing logic. These checks aren't
1626 * *strictly* necessary, but they keep the users
1627 * from doing crazy things.
1629 if (cf_item_is_section(ci)) {
1630 CONF_SECTION *subcs = cf_itemtosection(ci);
1631 const char *name1 = cf_section_name1(subcs);
1633 if ((strcmp(name1, "if") == 0) ||
1634 (strcmp(name1, "else") == 0) ||
1635 (strcmp(name1, "elsif") == 0) ||
1636 (strcmp(name1, "update") == 0) ||
1637 (strcmp(name1, "switch") == 0) ||
1638 (strcmp(name1, "case") == 0)) {
1639 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
1646 if (cf_item_is_pair(ci)) {
1647 CONF_PAIR *cp = cf_itemtopair(ci);
1648 if (cf_pair_value(cp) != NULL) {
1650 "Entry with no value is invalid");
1661 * Compile one entry of a module call.
1663 static modcallable *do_compile_modsingle(modcallable *parent,
1664 int component, CONF_ITEM *ci,
1666 const char **modname)
1671 const char *modrefname;
1673 modcallable *csingle;
1674 module_instance_t *this;
1675 CONF_SECTION *cs, *subcs, *modules;
1677 if (cf_item_is_section(ci)) {
1680 cs = cf_itemtosection(ci);
1681 modrefname = cf_section_name1(cs);
1682 name2 = cf_section_name2(cs);
1683 if (!name2) name2 = "_UnNamedGroup";
1686 * group{}, redundant{}, or append{} may appear
1687 * where a single module instance was expected.
1688 * In that case, we hand it off to
1691 if (strcmp(modrefname, "group") == 0) {
1693 return do_compile_modgroup(parent, component, cs,
1697 } else if (strcmp(modrefname, "redundant") == 0) {
1700 if (!all_children_are_modules(cs, modrefname)) {
1704 return do_compile_modgroup(parent, component, cs,
1705 GROUPTYPE_REDUNDANT,
1708 } else if (strcmp(modrefname, "append") == 0) {
1710 return do_compile_modgroup(parent, component, cs,
1714 } else if (strcmp(modrefname, "load-balance") == 0) {
1717 if (!all_children_are_modules(cs, modrefname)) {
1721 csingle= do_compile_modgroup(parent, component, cs,
1724 if (!csingle) return NULL;
1725 csingle->type = MOD_LOAD_BALANCE;
1728 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1731 if (!all_children_are_modules(cs, modrefname)) {
1735 csingle= do_compile_modgroup(parent, component, cs,
1736 GROUPTYPE_REDUNDANT,
1738 if (!csingle) return NULL;
1739 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1743 } else if (strcmp(modrefname, "if") == 0) {
1744 if (!cf_section_name2(cs)) {
1745 cf_log_err(ci, "'if' without condition.");
1750 csingle= do_compile_modgroup(parent, component, cs,
1753 if (!csingle) return NULL;
1754 csingle->type = MOD_IF;
1756 if (!radius_evaluate_condition(NULL, 0, 0, modname,
1758 modcallable_free(&csingle);
1765 } else if (strcmp(modrefname, "elsif") == 0) {
1767 ((parent->type == MOD_LOAD_BALANCE) ||
1768 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1769 cf_log_err(ci, "'elsif' cannot be used in this section.");
1773 if (!cf_section_name2(cs)) {
1774 cf_log_err(ci, "'elsif' without condition.");
1779 csingle= do_compile_modgroup(parent, component, cs,
1782 if (!csingle) return NULL;
1783 csingle->type = MOD_ELSIF;
1785 if (!radius_evaluate_condition(NULL, 0, 0, modname,
1787 modcallable_free(&csingle);
1794 } else if (strcmp(modrefname, "else") == 0) {
1796 ((parent->type == MOD_LOAD_BALANCE) ||
1797 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1798 cf_log_err(ci, "'else' cannot be used in this section section.");
1802 if (cf_section_name2(cs)) {
1803 cf_log_err(ci, "Cannot have conditions on 'else'.");
1808 csingle= do_compile_modgroup(parent, component, cs,
1811 if (!csingle) return NULL;
1812 csingle->type = MOD_ELSE;
1815 } else if (strcmp(modrefname, "update") == 0) {
1818 csingle = do_compile_modupdate(parent, component, cs,
1820 if (!csingle) return NULL;
1824 } else if (strcmp(modrefname, "switch") == 0) {
1827 csingle = do_compile_modswitch(parent, component, cs);
1828 if (!csingle) return NULL;
1832 } else if (strcmp(modrefname, "case") == 0) {
1838 * FIXME: How to tell that the parent can only
1839 * be a "switch" statement?
1842 cf_log_err(ci, "\"case\" statements may only appear within a \"switch\" section");
1846 csingle= do_compile_modgroup(parent, component, cs,
1849 if (!csingle) return NULL;
1850 csingle->type = MOD_CASE;
1851 csingle->name = cf_section_name2(cs); /* may be NULL */
1854 * Set all of it's codes to return, so that
1855 * when we pick a 'case' statement, we don't
1856 * fall through to processing the next one.
1858 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1859 csingle->actions[i] = MOD_ACTION_RETURN;
1864 } /* else it's something like sql { fail = 1 ...} */
1866 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
1870 * Else it's a module reference, with updated return
1875 CONF_PAIR *cp = cf_itemtopair(ci);
1876 modrefname = cf_pair_attr(cp);
1879 * Actions (ok = 1), etc. are orthoganal to just
1880 * about everything else.
1882 if (cf_pair_value(cp) != NULL) {
1883 cf_log_err(ci, "Entry is not a reference to a module");
1887 if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
1888 (modrefname[0] == '`')) {
1889 return do_compile_modxlat(parent, component,
1894 * See if the module is a virtual one. If so,
1895 * return that, rather than doing anything here.
1898 cs = cf_section_find("instantiate");
1899 if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
1902 (cs = cf_section_find("policy")) != NULL) {
1905 snprintf(buffer, sizeof(buffer), "%s.%s",
1906 modrefname, comp2str[component]);
1909 * Prefer name.section, then name.
1911 subcs = cf_section_sub_find_name2(cs, NULL,
1914 subcs = cf_section_sub_find_name2(cs, NULL,
1920 * Allow policies to over-ride module names.
1921 * i.e. the "sql" policy can do some extra things,
1922 * and then call the "sql" module.
1924 for (loop = cf_item_parent(ci);
1926 loop = cf_item_parent(cf_sectiontoitem(loop))) {
1927 if (loop == subcs) {
1933 DEBUG2(" Module: Loading virtual module %s",
1937 * redundant foo {} is a single.
1939 if (cf_section_name2(subcs)) {
1940 return do_compile_modsingle(parent,
1942 cf_sectiontoitem(subcs),
1947 * foo {} is a group.
1949 return do_compile_modgroup(parent,
1959 * Not a virtual module. It must be a real module.
1961 modules = cf_section_find("modules");
1964 if (modules && cf_section_sub_find_name2(modules, NULL, modrefname)) {
1965 this = find_module_instance(modules, modrefname, 1);
1973 * Maybe it's module.method
1975 p = strrchr(modrefname, '.');
1976 if (p) for (i = RLM_COMPONENT_AUTH;
1977 i < RLM_COMPONENT_COUNT;
1979 if (strcmp(p + 1, comp2str[i]) == 0) {
1982 strlcpy(buffer, modrefname, sizeof(buffer));
1983 buffer[p - modrefname] = '\0';
1986 this = find_module_instance(cf_section_find("modules"), buffer, 1);
1988 !this->entry->module->methods[i]) {
1990 cf_log_err(ci, "Module %s has no such method %s", buffer, comp2str[i]);
1998 if (strncmp(modrefname, "server[", 7) == 0) {
2001 strlcpy(buffer, modrefname + 7, sizeof(buffer));
2002 p = strrchr(buffer, ']');
2003 if (!p || p[1] != '\0' || (p == buffer)) {
2004 cf_log_err(ci, "Invalid server reference in \"%s\".", modrefname);
2009 cs = cf_section_sub_find_name2(NULL, "server", buffer);
2011 cf_log_err(ci, "No such server \"%s\".", buffer);
2015 return do_compile_modserver(parent, component, ci,
2016 modrefname, cs, buffer);
2020 cf_log_err(ci, "Failed to find \"%s\" in the \"modules\" section.", modrefname);
2025 * We know it's all OK, allocate the structures, and fill
2028 single = rad_malloc(sizeof(*single));
2029 memset(single, 0, sizeof(*single));
2030 csingle = mod_singletocallable(single);
2031 csingle->parent = parent;
2032 csingle->next = NULL;
2033 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2034 memcpy(csingle->actions, defaultactions[component][grouptype],
2035 sizeof csingle->actions);
2036 } else { /* inside Auth-Type has different rules */
2037 memcpy(csingle->actions, defaultactions[RLM_COMPONENT_AUTZ][grouptype],
2038 sizeof csingle->actions);
2040 rad_assert(modrefname != NULL);
2041 csingle->name = modrefname;
2042 csingle->type = MOD_SINGLE;
2043 csingle->method = component;
2046 * Singles can override the actions, virtual modules cannot.
2048 * FIXME: We may want to re-visit how to do this...
2049 * maybe a csingle as a ref?
2051 if (cf_item_is_section(ci)) {
2054 cs = cf_itemtosection(ci);
2055 for (csi=cf_item_find_next(cs, NULL);
2057 csi=cf_item_find_next(cs, csi)) {
2059 if (cf_item_is_section(csi)) {
2060 cf_log_err(csi, "Subsection of module instance call not allowed");
2061 modcallable_free(&csingle);
2065 if (!cf_item_is_pair(csi)) continue;
2067 if (!compile_action(csingle, cf_itemtopair(csi))) {
2068 modcallable_free(&csingle);
2075 * Bail out if the module in question does not supply the
2078 if (!this->entry->module->methods[component]) {
2079 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
2080 comp2str[component]);
2081 modcallable_free(&csingle);
2085 single->modinst = this;
2086 *modname = this->entry->module->name;
2090 modcallable *compile_modsingle(modcallable *parent,
2091 int component, CONF_ITEM *ci,
2092 const char **modname)
2094 modcallable *ret = do_compile_modsingle(parent, component, ci,
2097 dump_tree(component, ret);
2103 * Internal compile group code.
2105 static modcallable *do_compile_modgroup(modcallable *parent,
2106 int component, CONF_SECTION *cs,
2107 int grouptype, int parentgrouptype)
2114 g = rad_malloc(sizeof(*g));
2115 memset(g, 0, sizeof(*g));
2116 g->grouptype = grouptype;
2118 c = mod_grouptocallable(g);
2120 c->type = MOD_GROUP;
2122 memset(c->actions, 0, sizeof(c->actions));
2125 * Remember the name for printing, etc.
2127 * FIXME: We may also want to put the names into a
2128 * rbtree, so that groups can reference each other...
2130 c->name = cf_section_name2(cs);
2132 c->name = cf_section_name1(cs);
2133 if (strcmp(c->name, "group") == 0) {
2136 c->type = MOD_POLICY;
2142 * Loop over the children of this group.
2144 for (ci=cf_item_find_next(cs, NULL);
2146 ci=cf_item_find_next(cs, ci)) {
2149 * Sections are references to other groups, or
2150 * to modules with updated return codes.
2152 if (cf_item_is_section(ci)) {
2153 const char *junk = NULL;
2154 modcallable *single;
2155 CONF_SECTION *subcs = cf_itemtosection(ci);
2157 single = do_compile_modsingle(c, component, ci,
2160 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
2161 cf_section_name1(subcs));
2162 modcallable_free(&c);
2165 add_child(g, single);
2167 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
2171 const char *attr, *value;
2172 CONF_PAIR *cp = cf_itemtopair(ci);
2174 attr = cf_pair_attr(cp);
2175 value = cf_pair_value(cp);
2178 * A CONF_PAIR is either a module
2179 * instance with no actions
2183 modcallable *single;
2184 const char *junk = NULL;
2186 single = do_compile_modsingle(c,
2193 "Failed to parse \"%s\" entry.",
2195 modcallable_free(&c);
2198 add_child(g, single);
2201 * Or a module instance with action.
2203 } else if (!compile_action(c, cp)) {
2204 modcallable_free(&c);
2206 } /* else it worked */
2211 * Set the default actions, if they haven't already been
2214 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2215 if (!c->actions[i]) {
2216 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2217 c->actions[i] = defaultactions[component][parentgrouptype][i];
2218 } else { /* inside Auth-Type has different rules */
2219 c->actions[i] = defaultactions[RLM_COMPONENT_AUTZ][parentgrouptype][i];
2225 * FIXME: If there are no children, return NULL?
2227 return mod_grouptocallable(g);
2230 modcallable *compile_modgroup(modcallable *parent,
2231 int component, CONF_SECTION *cs)
2233 modcallable *ret = do_compile_modgroup(parent, component, cs,
2236 dump_tree(component, ret);
2240 void add_to_modcallable(modcallable **parent, modcallable *this,
2241 int component, const char *name)
2245 rad_assert(this != NULL);
2247 if (*parent == NULL) {
2250 g = rad_malloc(sizeof *g);
2251 memset(g, 0, sizeof(*g));
2252 g->grouptype = GROUPTYPE_SIMPLE;
2253 c = mod_grouptocallable(g);
2256 defaultactions[component][GROUPTYPE_SIMPLE],
2257 sizeof(c->actions));
2258 rad_assert(name != NULL);
2260 c->type = MOD_GROUP;
2261 c->method = component;
2264 *parent = mod_grouptocallable(g);
2266 g = mod_callabletogroup(*parent);
2272 void modcallable_free(modcallable **pc)
2274 modcallable *c, *loop, *next;
2276 if (!pc || !*pc) return;
2280 if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
2281 modgroup *g = mod_callabletogroup(c);
2283 if (g->children) for (loop = g->children;
2287 modcallable_free(&loop);