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 The FreeRADIUS server project
22 #include <freeradius-devel/autoconf.h>
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/rad_assert.h>
29 #include <freeradius-devel/conffile.h>
30 #include <freeradius-devel/modpriv.h>
31 #include <freeradius-devel/modules.h>
32 #include <freeradius-devel/modcall.h>
34 /* mutually-recursive static functions need a prototype up front */
35 static modcallable *do_compile_modgroup(modcallable *,
36 int, CONF_SECTION *, const char *,
39 /* Actions may be a positive integer (the highest one returned in the group
40 * will be returned), or the keyword "return", represented here by
41 * MOD_ACTION_RETURN, to cause an immediate return.
42 * There's also the keyword "reject", represented here by MOD_ACTION_REJECT
43 * to cause an immediate reject. */
44 #define MOD_ACTION_RETURN (-1)
45 #define MOD_ACTION_REJECT (-2)
47 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
48 * explanation of what they are all about, see ../../doc/README.failover */
51 struct modcallable *next;
53 int actions[RLM_MODULE_NUMCODES];
54 enum { MOD_SINGLE, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE } type;
57 #define GROUPTYPE_SIMPLE 0
58 #define GROUPTYPE_REDUNDANT 1
59 #define GROUPTYPE_APPEND 2
60 #define GROUPTYPE_COUNT 3
63 modcallable mc; /* self */
64 int grouptype; /* after mc */
65 modcallable *children;
70 module_instance_t *modinst;
74 static const LRAD_NAME_NUMBER grouptype_table[] = {
75 { "", GROUPTYPE_SIMPLE },
76 { "redundant ", GROUPTYPE_REDUNDANT },
77 { "append ", GROUPTYPE_APPEND },
81 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
82 * so we often want to go back and forth between them. */
83 static modsingle *mod_callabletosingle(modcallable *p)
85 rad_assert(p->type==MOD_SINGLE);
86 return (modsingle *)p;
88 static modgroup *mod_callabletogroup(modcallable *p)
90 rad_assert((p->type==MOD_GROUP) ||
91 (p->type==MOD_LOAD_BALANCE) ||
92 (p->type==MOD_REDUNDANT_LOAD_BALANCE));
95 static modcallable *mod_singletocallable(modsingle *p)
97 return (modcallable *)p;
99 static modcallable *mod_grouptocallable(modgroup *p)
101 return (modcallable *)p;
104 /* modgroups are grown by adding a modcallable to the end */
105 static void add_child(modgroup *g, modcallable *c)
107 modcallable **head = &g->children;
108 modcallable *node = *head;
109 modcallable **last = head;
118 rad_assert(c->next == NULL);
120 c->parent = mod_grouptocallable(g);
123 /* Here's where we recognize all of our keywords: first the rcodes, then the
125 static const LRAD_NAME_NUMBER rcode_table[] = {
126 { "reject", RLM_MODULE_REJECT },
127 { "fail", RLM_MODULE_FAIL },
128 { "ok", RLM_MODULE_OK },
129 { "handled", RLM_MODULE_HANDLED },
130 { "invalid", RLM_MODULE_INVALID },
131 { "userlock", RLM_MODULE_USERLOCK },
132 { "notfound", RLM_MODULE_NOTFOUND },
133 { "noop", RLM_MODULE_NOOP },
134 { "updated", RLM_MODULE_UPDATED },
140 * Compile action && rcode for later use.
142 static int compile_action(modcallable *c, const char *attr, const char *value,
143 const char *filename, int lineno)
147 if (!strcasecmp(value, "return"))
148 action = MOD_ACTION_RETURN;
150 else if (!strcasecmp(value, "reject"))
151 action = MOD_ACTION_REJECT;
153 else if (strspn(value, "0123456789")==strlen(value)) {
154 action = atoi(value);
157 * Don't allow priority zero, for future use.
159 if (action == 0) return 0;
162 "%s[%d] Unknown action '%s'.\n",
163 filename, lineno, value);
167 if (strcasecmp(attr, "default") != 0) {
170 rcode = lrad_str2int(rcode_table, attr, -1);
173 "%s[%d] Unknown module rcode '%s'.\n",
174 filename, lineno, attr);
177 c->actions[rcode] = action;
179 } else { /* set all unset values to the default */
182 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
183 if (!c->actions[i]) c->actions[i] = action;
191 static const char *action2str(int action)
194 if(action==MOD_ACTION_RETURN)
196 if(action==MOD_ACTION_REJECT)
198 snprintf(buf, sizeof buf, "%d", action);
203 /* Some short names for debugging output */
204 static const char * const comp2str[] = {
215 #ifdef HAVE_PTHREAD_H
217 * Lock the mutex for the module
219 static void safe_lock(module_instance_t *instance)
222 pthread_mutex_lock(instance->mutex);
226 * Unlock the mutex for the module
228 static void safe_unlock(module_instance_t *instance)
231 pthread_mutex_unlock(instance->mutex);
235 * No threads: these functions become NULL's.
237 #define safe_lock(foo)
238 #define safe_unlock(foo)
241 static int call_modsingle(int component, modsingle *sp, REQUEST *request,
244 int myresult = default_result;
246 DEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
247 comp2str[component], sp->modinst->name,
248 sp->modinst->entry->name, request->number);
249 safe_lock(sp->modinst);
252 * For logging unresponsive children.
254 request->module = sp->modinst->name;
255 request->component = comp2str[component];
257 myresult = sp->modinst->entry->module->methods[component](
258 sp->modinst->insthandle, request);
260 request->module = NULL;
261 safe_unlock(sp->modinst);
262 DEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
263 comp2str[component], sp->modinst->name,
264 sp->modinst->entry->name, request->number);
270 static int default_component_results[RLM_COMPONENT_COUNT] = {
271 RLM_MODULE_REJECT, /* AUTH */
272 RLM_MODULE_NOTFOUND, /* AUTZ */
273 RLM_MODULE_NOOP, /* PREACCT */
274 RLM_MODULE_NOOP, /* ACCT */
275 RLM_MODULE_FAIL, /* SESS */
276 RLM_MODULE_NOOP, /* PRE_PROXY */
277 RLM_MODULE_NOOP, /* POST_PROXY */
278 RLM_MODULE_NOOP /* POST_AUTH */
281 static const char *group_name[] = {
284 "load-balance group",
285 "redundant-load-balance group"
288 #define MODCALL_STACK_MAX (8)
291 * Don't call the modules recursively. Instead, do them
292 * iteratively, and manage the call stack ourselves.
294 typedef struct modcall_stack {
297 int priority[MODCALL_STACK_MAX];
298 int result[MODCALL_STACK_MAX];
299 modcallable *children[MODCALL_STACK_MAX];
300 modcallable *start[MODCALL_STACK_MAX];
304 int modcall(int component, modcallable *c, REQUEST *request)
308 modcallable *parent, *child;
312 if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {
313 return RLM_MODULE_FAIL;
317 return default_component_results[component];
320 stack.priority[0] = 0;
321 stack.children[0] = c;
322 myresult = stack.result[0] = default_component_results[component];
326 * A module has taken too long to process the request,
327 * and we've been told to stop processing it.
329 if (request->options & RAD_REQUEST_OPTION_STOP_NOW) {
330 myresult = RLM_MODULE_FAIL;
334 child = stack.children[stack.pointer];
335 parent = child->parent;
338 * Child is a group that has children of it's own.
340 if (child && (child->type != MOD_SINGLE)) {
343 modgroup *g = mod_callabletogroup(child);
348 * Catastrophic error. This SHOULD have
349 * been caught when we were reading in the
354 if (stack.pointer >= MODCALL_STACK_MAX) {
355 radlog(L_ERR, "Internal sanity check failed: module stack is too deep");
359 stack.priority[stack.pointer] = 0;
360 stack.result[stack.pointer] = default_component_results[component];
361 switch (child->type) {
363 stack.children[stack.pointer] = g->children;
367 * See the "camel book" for why
370 * If (rand(0..n) < 1), pick the
371 * current realm. We add a scale
372 * factor of 65536, to avoid
375 case MOD_LOAD_BALANCE:
376 case MOD_REDUNDANT_LOAD_BALANCE:
378 for(p = g->children; p; p = p->next) {
387 if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
391 stack.children[stack.pointer] = q;
395 exit(1); /* internal sanity check failure */
400 stack.start[stack.pointer] = stack.children[stack.pointer];
402 DEBUG2("modcall: entering %s %s for request %d",
403 group_name[child->type],
404 child->name, request->number);
407 * Catch the special case of a NULL group.
409 if (!stack.children[stack.pointer]) {
411 * Print message for NULL group
413 DEBUG2("modcall[%s]: NULL object returns %s for request %d",
415 lrad_int2str(rcode_table,
416 stack.result[stack.pointer],
422 continue; /* child MAY be a group! */
426 * Process a stand-alone child, and fall through
427 * to dealing with it's parent.
429 if (child && (child->type == MOD_SINGLE)) {
430 modsingle *sp = mod_callabletosingle(child);
432 myresult = call_modsingle(component, sp, request,
433 default_component_results[component]);
434 stack.result[stack.pointer] = myresult;
438 * We roll back up the stack at this point.
442 * No parent, we must be done.
445 rad_assert(stack.pointer == 0);
446 myresult = stack.result[0];
450 rad_assert(child != NULL);
453 * Go to the "next" child, whatever that is.
455 switch (parent->type) {
457 stack.children[stack.pointer] = child->next;
460 case MOD_LOAD_BALANCE:
461 stack.children[stack.pointer] = NULL;
464 case MOD_REDUNDANT_LOAD_BALANCE:
466 stack.children[stack.pointer] = child->next;
468 modgroup *g = mod_callabletogroup(parent);
470 stack.children[stack.pointer] = g->children;
472 if (stack.children[stack.pointer] == stack.start[stack.pointer]) {
473 stack.children[stack.pointer] = NULL;
481 * The child's action says return. Do so.
483 if (child->actions[myresult] == MOD_ACTION_RETURN) {
484 stack.children[stack.pointer] = NULL;
487 /* If "reject", break out of the loop and return reject */
488 if (child->actions[myresult] == MOD_ACTION_REJECT) {
489 stack.children[stack.pointer] = NULL;
490 stack.result[stack.pointer] = RLM_MODULE_REJECT;
494 * No child, we're done this group.
496 if (!stack.children[stack.pointer]) {
498 rad_assert(stack.pointer > 0);
499 myresult = stack.result[stack.pointer];
502 DEBUG2("modcall: %s %s returns %s for request %d",
503 group_name[parent->type], parent->name,
504 lrad_int2str(rcode_table, myresult, "??"),
507 if (stack.pointer == 0) break;
512 child = stack.children[stack.pointer];
513 parent = child->parent;
518 * Otherwise, the action is a number, the
519 * preference level of this return code. If no
520 * higher preference has been seen yet, remember
522 if (child->actions[myresult] >= stack.priority[stack.pointer]) {
523 stack.result[stack.pointer] = myresult;
524 stack.priority[stack.pointer] = child->actions[myresult];
526 } /* loop until done */
533 /* If you suspect a bug in the parser, you'll want to use these dump
534 * functions. dump_tree should reproduce a whole tree exactly as it was found
535 * in radiusd.conf, but in long form (all actions explicitly defined) */
536 static void dump_mc(modcallable *c, int indent)
540 if(c->type==MOD_SINGLE) {
541 modsingle *single = mod_callabletosingle(c);
542 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
543 single->modinst->name);
545 modgroup *g = mod_callabletogroup(c);
547 DEBUG("%.*sgroup {", indent, "\t\t\t\t\t\t\t\t\t\t\t");
548 for(p = g->children;p;p = p->next)
549 dump_mc(p, indent+1);
552 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
553 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
554 lrad_int2str(rcode_table, i, "??"),
555 action2str(c->actions[i]));
558 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
561 static void dump_tree(int comp, modcallable *c)
563 DEBUG("[%s]", comp2str[comp]);
567 static void dump_tree(int comp UNUSED, modcallable *c UNUSED)
573 /* These are the default actions. For each component, the group{} block
574 * behaves like the code from the old module_*() function. redundant{} and
575 * append{} are based on my guesses of what they will be used for. --Pac. */
577 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
583 MOD_ACTION_RETURN, /* reject */
585 MOD_ACTION_RETURN, /* ok */
586 MOD_ACTION_RETURN, /* handled */
588 MOD_ACTION_RETURN, /* userlock */
589 MOD_ACTION_RETURN, /* notfound */
595 MOD_ACTION_RETURN, /* reject */
597 MOD_ACTION_RETURN, /* ok */
598 MOD_ACTION_RETURN, /* handled */
599 MOD_ACTION_RETURN, /* invalid */
600 MOD_ACTION_RETURN, /* userlock */
601 MOD_ACTION_RETURN, /* notfound */
602 MOD_ACTION_RETURN, /* noop */
603 MOD_ACTION_RETURN /* updated */
607 MOD_ACTION_RETURN, /* reject */
609 MOD_ACTION_RETURN, /* ok */
610 MOD_ACTION_RETURN, /* handled */
611 MOD_ACTION_RETURN, /* invalid */
612 MOD_ACTION_RETURN, /* userlock */
614 MOD_ACTION_RETURN, /* noop */
615 MOD_ACTION_RETURN /* updated */
622 MOD_ACTION_RETURN, /* reject */
623 MOD_ACTION_RETURN, /* fail */
625 MOD_ACTION_RETURN, /* handled */
626 MOD_ACTION_RETURN, /* invalid */
627 MOD_ACTION_RETURN, /* userlock */
634 MOD_ACTION_RETURN, /* reject */
636 MOD_ACTION_RETURN, /* ok */
637 MOD_ACTION_RETURN, /* handled */
638 MOD_ACTION_RETURN, /* invalid */
639 MOD_ACTION_RETURN, /* userlock */
640 MOD_ACTION_RETURN, /* notfound */
641 MOD_ACTION_RETURN, /* noop */
642 MOD_ACTION_RETURN /* updated */
646 MOD_ACTION_RETURN, /* reject */
648 MOD_ACTION_RETURN, /* ok */
649 MOD_ACTION_RETURN, /* handled */
650 MOD_ACTION_RETURN, /* invalid */
651 MOD_ACTION_RETURN, /* userlock */
653 MOD_ACTION_RETURN, /* noop */
654 MOD_ACTION_RETURN /* updated */
661 MOD_ACTION_RETURN, /* reject */
662 MOD_ACTION_RETURN, /* fail */
664 MOD_ACTION_RETURN, /* handled */
665 MOD_ACTION_RETURN, /* invalid */
666 MOD_ACTION_RETURN, /* userlock */
667 MOD_ACTION_RETURN, /* notfound */
673 MOD_ACTION_RETURN, /* reject */
675 MOD_ACTION_RETURN, /* ok */
676 MOD_ACTION_RETURN, /* handled */
677 MOD_ACTION_RETURN, /* invalid */
678 MOD_ACTION_RETURN, /* userlock */
679 MOD_ACTION_RETURN, /* notfound */
680 MOD_ACTION_RETURN, /* noop */
681 MOD_ACTION_RETURN /* updated */
685 MOD_ACTION_RETURN, /* reject */
687 MOD_ACTION_RETURN, /* ok */
688 MOD_ACTION_RETURN, /* handled */
689 MOD_ACTION_RETURN, /* invalid */
690 MOD_ACTION_RETURN, /* userlock */
692 MOD_ACTION_RETURN, /* noop */
693 MOD_ACTION_RETURN /* updated */
700 MOD_ACTION_RETURN, /* reject */
701 MOD_ACTION_RETURN, /* fail */
703 MOD_ACTION_RETURN, /* handled */
704 MOD_ACTION_RETURN, /* invalid */
705 MOD_ACTION_RETURN, /* userlock */
706 MOD_ACTION_RETURN, /* notfound */
714 MOD_ACTION_RETURN, /* ok */
715 MOD_ACTION_RETURN, /* handled */
724 MOD_ACTION_RETURN, /* reject */
726 MOD_ACTION_RETURN, /* ok */
727 MOD_ACTION_RETURN, /* handled */
728 MOD_ACTION_RETURN, /* invalid */
729 MOD_ACTION_RETURN, /* userlock */
731 MOD_ACTION_RETURN, /* noop */
732 MOD_ACTION_RETURN /* updated */
739 MOD_ACTION_RETURN, /* reject */
741 MOD_ACTION_RETURN, /* ok */
742 MOD_ACTION_RETURN, /* handled */
743 MOD_ACTION_RETURN, /* invalid */
744 MOD_ACTION_RETURN, /* userlock */
745 MOD_ACTION_RETURN, /* notfound */
746 MOD_ACTION_RETURN, /* noop */
747 MOD_ACTION_RETURN /* updated */
751 MOD_ACTION_RETURN, /* reject */
753 MOD_ACTION_RETURN, /* ok */
754 MOD_ACTION_RETURN, /* handled */
755 MOD_ACTION_RETURN, /* invalid */
756 MOD_ACTION_RETURN, /* userlock */
757 MOD_ACTION_RETURN, /* notfound */
758 MOD_ACTION_RETURN, /* noop */
759 MOD_ACTION_RETURN /* updated */
763 MOD_ACTION_RETURN, /* reject */
765 MOD_ACTION_RETURN, /* ok */
766 MOD_ACTION_RETURN, /* handled */
767 MOD_ACTION_RETURN, /* invalid */
768 MOD_ACTION_RETURN, /* userlock */
769 MOD_ACTION_RETURN, /* notfound */
770 MOD_ACTION_RETURN, /* noop */
771 MOD_ACTION_RETURN /* updated */
778 MOD_ACTION_RETURN, /* reject */
779 MOD_ACTION_RETURN, /* fail */
781 MOD_ACTION_RETURN, /* handled */
782 MOD_ACTION_RETURN, /* invalid */
783 MOD_ACTION_RETURN, /* userlock */
790 MOD_ACTION_RETURN, /* reject */
792 MOD_ACTION_RETURN, /* ok */
793 MOD_ACTION_RETURN, /* handled */
794 MOD_ACTION_RETURN, /* invalid */
795 MOD_ACTION_RETURN, /* userlock */
796 MOD_ACTION_RETURN, /* notfound */
797 MOD_ACTION_RETURN, /* noop */
798 MOD_ACTION_RETURN /* updated */
802 MOD_ACTION_RETURN, /* reject */
804 MOD_ACTION_RETURN, /* ok */
805 MOD_ACTION_RETURN, /* handled */
806 MOD_ACTION_RETURN, /* invalid */
807 MOD_ACTION_RETURN, /* userlock */
809 MOD_ACTION_RETURN, /* noop */
810 MOD_ACTION_RETURN /* updated */
817 MOD_ACTION_RETURN, /* reject */
818 MOD_ACTION_RETURN, /* fail */
820 MOD_ACTION_RETURN, /* handled */
821 MOD_ACTION_RETURN, /* invalid */
822 MOD_ACTION_RETURN, /* userlock */
829 MOD_ACTION_RETURN, /* reject */
831 MOD_ACTION_RETURN, /* ok */
832 MOD_ACTION_RETURN, /* handled */
833 MOD_ACTION_RETURN, /* invalid */
834 MOD_ACTION_RETURN, /* userlock */
835 MOD_ACTION_RETURN, /* notfound */
836 MOD_ACTION_RETURN, /* noop */
837 MOD_ACTION_RETURN /* updated */
841 MOD_ACTION_RETURN, /* reject */
843 MOD_ACTION_RETURN, /* ok */
844 MOD_ACTION_RETURN, /* handled */
845 MOD_ACTION_RETURN, /* invalid */
846 MOD_ACTION_RETURN, /* userlock */
848 MOD_ACTION_RETURN, /* noop */
849 MOD_ACTION_RETURN /* updated */
856 MOD_ACTION_RETURN, /* reject */
857 MOD_ACTION_RETURN, /* fail */
859 MOD_ACTION_RETURN, /* handled */
860 MOD_ACTION_RETURN, /* invalid */
861 MOD_ACTION_RETURN, /* userlock */
868 MOD_ACTION_RETURN, /* reject */
870 MOD_ACTION_RETURN, /* ok */
871 MOD_ACTION_RETURN, /* handled */
872 MOD_ACTION_RETURN, /* invalid */
873 MOD_ACTION_RETURN, /* userlock */
874 MOD_ACTION_RETURN, /* notfound */
875 MOD_ACTION_RETURN, /* noop */
876 MOD_ACTION_RETURN /* updated */
880 MOD_ACTION_RETURN, /* reject */
882 MOD_ACTION_RETURN, /* ok */
883 MOD_ACTION_RETURN, /* handled */
884 MOD_ACTION_RETURN, /* invalid */
885 MOD_ACTION_RETURN, /* userlock */
887 MOD_ACTION_RETURN, /* noop */
888 MOD_ACTION_RETURN /* updated */
895 * Compile one entry of a module call.
897 static modcallable *do_compile_modsingle(modcallable *parent,
898 int component, CONF_ITEM *ci,
899 const char *filename, int grouptype,
900 const char **modname)
903 const char *modrefname;
905 modcallable *csingle;
906 module_instance_t *this;
908 if (cf_item_is_section(ci)) {
909 CONF_SECTION *cs = cf_itemtosection(ci);
910 const char *name2 = cf_section_name2(cs);
912 lineno = cf_section_lineno(cs);
913 modrefname = cf_section_name1(cs);
914 if (!name2) name2 = "_UnNamedGroup";
917 * group{}, redundant{}, or append{} may appear
918 * where a single module instance was expected.
919 * In that case, we hand it off to
922 if (strcmp(modrefname, "group") == 0) {
924 return do_compile_modgroup(parent, component, cs,
928 } else if (strcmp(modrefname, "redundant") == 0) {
930 return do_compile_modgroup(parent, component, cs,
934 } else if (strcmp(modrefname, "append") == 0) {
936 return do_compile_modgroup(parent, component, cs,
940 } else if (strcmp(modrefname, "load-balance") == 0) {
942 csingle= do_compile_modgroup(parent, component, cs,
946 if (!csingle) return NULL;
947 csingle->type = MOD_LOAD_BALANCE;
949 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
951 csingle= do_compile_modgroup(parent, component, cs,
955 if (!csingle) return NULL;
956 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
960 * Else it's a module reference, with updated return
964 CONF_PAIR *cp = cf_itemtopair(ci);
965 lineno = cf_pair_lineno(cp);
966 modrefname = cf_pair_attr(cp);
970 * See if the module is a virtual one. If so, return that,
971 * rather than doing anything here.
973 this = find_module_instance(cf_section_find("modules"), modrefname);
975 CONF_SECTION *cs, *subcs;
978 * Then, look for it in the "instantiate" section.
980 if (((subcs = cf_section_find(NULL)) != NULL) &&
981 ((cs = cf_section_sub_find_name2(subcs, "instantiate", NULL)) != NULL)) {
982 subcs = cf_section_sub_find_name2(cs, NULL, modrefname);
985 * As it's sole configuration, the
986 * virtual module takes a section which
989 return do_compile_modsingle(parent,
991 cf_sectiontoitem(subcs),
1000 radlog(L_ERR|L_CONS, "%s[%d] Failed to find module \"%s\".", filename,
1001 lineno, modrefname);
1006 * We know it's all OK, allocate the structures, and fill
1009 single = rad_malloc(sizeof(*single));
1010 memset(single, 0, sizeof(*single));
1011 csingle = mod_singletocallable(single);
1012 csingle->parent = parent;
1013 csingle->next = NULL;
1014 memcpy(csingle->actions, defaultactions[component][grouptype],
1015 sizeof csingle->actions);
1016 rad_assert(modrefname != NULL);
1017 csingle->name = modrefname;
1018 csingle->type = MOD_SINGLE;
1021 * Singles can override the actions, virtual modules cannot.
1023 * FIXME: We may want to re-visit how to do this...
1024 * maybe a csingle as a ref?
1026 if (cf_item_is_section(ci)) {
1027 CONF_SECTION *cs = cf_itemtosection(ci);
1029 const char *attr, *value;
1031 for (ci=cf_item_find_next(cs, NULL);
1033 ci=cf_item_find_next(cs, ci)) {
1035 if (cf_item_is_section(ci)) {
1036 radlog(L_ERR|L_CONS,
1037 "%s[%d] Subsection of module instance call "
1038 "not allowed\n", filename,
1039 cf_section_lineno(cf_itemtosection(ci)));
1040 modcallable_free(&csingle);
1044 cp = cf_itemtopair(ci);
1045 attr = cf_pair_attr(cp);
1046 value = cf_pair_value(cp);
1047 lineno = cf_pair_lineno(cp);
1049 if (!compile_action(csingle, attr, value, filename,
1051 modcallable_free(&csingle);
1058 * Bail out if the module in question does not supply the
1061 if (!this->entry->module->methods[component]) {
1062 radlog(L_ERR|L_CONS,
1063 "%s[%d]: \"%s\" modules aren't allowed in '%s' sections -- they have no such method.",
1064 filename, lineno, this->entry->module->name,
1065 comp2str[component]);
1066 modcallable_free(&csingle);
1070 single->modinst = this;
1071 *modname = this->entry->module->name;
1075 modcallable *compile_modsingle(modcallable *parent,
1076 int component, CONF_ITEM *ci,
1077 const char *filename, const char **modname)
1079 modcallable *ret = do_compile_modsingle(parent, component, ci,
1083 dump_tree(component, ret);
1089 * Internal compile group code.
1091 static modcallable *do_compile_modgroup(modcallable *parent,
1092 int component, CONF_SECTION *cs,
1093 const char *filename, int grouptype,
1094 int parentgrouptype)
1101 g = rad_malloc(sizeof(*g));
1102 memset(g, 0, sizeof(*g));
1103 g->grouptype = grouptype;
1105 c = mod_grouptocallable(g);
1108 memset(c->actions, 0, sizeof(c->actions));
1111 * Remember the name for printing, etc.
1113 * FIXME: We may also want to put the names into a
1114 * rbtree, so that groups can reference each other...
1116 c->name = cf_section_name2(cs);
1117 if (!c->name) c->name = "";
1118 c->type = MOD_GROUP;
1122 * Loop over the children of this group.
1124 for (ci=cf_item_find_next(cs, NULL);
1126 ci=cf_item_find_next(cs, ci)) {
1129 * Sections are references to other groups, or
1130 * to modules with updated return codes.
1132 if (cf_item_is_section(ci)) {
1133 const char *junk = NULL;
1134 modcallable *single;
1136 CONF_SECTION *subcs = cf_itemtosection(ci);
1138 lineno = cf_section_lineno(subcs);
1140 single = do_compile_modsingle(c, component, ci,
1144 radlog(L_ERR|L_CONS,
1145 "%s[%d] Failed to parse \"%s\" subsection.\n",
1147 cf_section_name1(subcs));
1148 modcallable_free(&c);
1151 add_child(g, single);
1154 const char *attr, *value;
1155 CONF_PAIR *cp = cf_itemtopair(ci);
1158 attr = cf_pair_attr(cp);
1159 value = cf_pair_value(cp);
1160 lineno = cf_pair_lineno(cp);
1163 * A CONF_PAIR is either a module
1164 * instance with no actions
1167 if (value[0] == 0) {
1168 modcallable *single;
1169 const char *junk = NULL;
1171 single = do_compile_modsingle(c,
1178 radlog(L_ERR|L_CONS,
1179 "%s[%d] Failed to parse \"%s\" entry.\n",
1180 filename, lineno, attr);
1181 modcallable_free(&c);
1184 add_child(g, single);
1187 * Or a module instance with action.
1189 } else if (!compile_action(c, attr, value, filename,
1191 modcallable_free(&c);
1193 } /* else it worked */
1198 * Set the default actions, if they haven't already been
1201 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1202 if (!c->actions[i]) {
1203 c->actions[i] = defaultactions[component][parentgrouptype][i];
1208 * FIXME: If there are no children, return NULL?
1210 return mod_grouptocallable(g);
1213 modcallable *compile_modgroup(modcallable *parent,
1214 int component, CONF_SECTION *cs,
1215 const char *filename)
1217 modcallable *ret = do_compile_modgroup(parent, component, cs, filename,
1220 dump_tree(component, ret);
1224 void add_to_modcallable(modcallable **parent, modcallable *this,
1225 int component, const char *name)
1229 rad_assert(this != NULL);
1231 if (*parent == NULL) {
1234 g = rad_malloc(sizeof *g);
1235 memset(g, 0, sizeof(*g));
1236 g->grouptype = GROUPTYPE_SIMPLE;
1237 c = mod_grouptocallable(g);
1240 defaultactions[component][GROUPTYPE_SIMPLE],
1241 sizeof(c->actions));
1242 rad_assert(name != NULL);
1244 c->type = MOD_GROUP;
1247 *parent = mod_grouptocallable(g);
1249 g = mod_callabletogroup(*parent);
1255 void modcallable_free(modcallable **pc)
1257 modcallable *c, *loop, *next;
1259 if(c->type==MOD_GROUP) {
1260 for(loop = mod_callabletogroup(c)->children;
1264 modcallable_free(&loop);