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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2000 The FreeRADIUS server project
27 #include "rad_assert.h"
33 /* mutually-recursive static functions need a prototype up front */
34 static modcallable *do_compile_modgroup(int, CONF_SECTION *, const char *,
37 /* Actions may be a positive integer (the highest one returned in the group
38 * will be returned), or the keyword "return", represented here by
39 * MOD_ACTION_RETURN, to cause an immediate return. */
40 #define MOD_ACTION_RETURN (-1)
42 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
43 * explanation of what they are all about, see ../../doc/README.failover */
45 struct modcallable *next;
46 int actions[RLM_MODULE_NUMCODES];
48 enum { MOD_SINGLE, MOD_GROUP } type;
53 modcallable *children;
58 module_instance_t *modinst;
61 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
62 * so we often want to go back and forth between them. */
63 static modsingle *mod_callabletosingle(modcallable *p)
65 rad_assert(p->type==MOD_SINGLE);
66 return (modsingle *)p;
68 static modgroup *mod_callabletogroup(modcallable *p)
70 rad_assert(p->type==MOD_GROUP);
73 static modcallable *mod_singletocallable(modsingle *p)
75 return (modcallable *)p;
77 static modcallable *mod_grouptocallable(modgroup *p)
79 return (modcallable *)p;
82 /* modgroups are grown by adding a modcallable to the end */
83 static void add_child(modgroup *g, modcallable *c)
85 modcallable **head = &g->children;
86 modcallable *node = *head;
87 modcallable **last = head;
94 rad_assert(c->next == NULL);
98 /* Here's where we recognize all of our keywords: first the rcodes, then the
100 static LRAD_NAME_NUMBER rcode_table[] = {
101 { "reject", RLM_MODULE_REJECT },
102 { "fail", RLM_MODULE_FAIL },
103 { "ok", RLM_MODULE_OK },
104 { "handled", RLM_MODULE_HANDLED },
105 { "invalid", RLM_MODULE_INVALID },
106 { "userlock", RLM_MODULE_USERLOCK },
107 { "notfound", RLM_MODULE_NOTFOUND },
108 { "noop", RLM_MODULE_NOOP },
109 { "updated", RLM_MODULE_UPDATED },
113 static int str2rcode(const char *s, const char *filename, int lineno)
117 rcode = lrad_str2int(rcode_table, s, -1);
120 "%s[%d] Unknown module rcode '%s'.\n",
121 filename, lineno, s);
128 static int str2action(const char *s, const char *filename, int lineno)
130 if(!strcasecmp(s, "return"))
131 return MOD_ACTION_RETURN;
132 else if (strspn(s, "0123456789")==strlen(s)) {
136 * Don't allow priority zero, for future use.
140 "%s[%d] Invalid action '%s'.\n",
141 filename, lineno, s);
147 "%s[%d] Unknown action '%s'.\n",
148 filename, lineno, s);
155 static const char *action2str(int action)
158 if(action==MOD_ACTION_RETURN)
160 snprintf(buf, sizeof buf, "%d", action);
165 /* Some short names for debugging output */
166 static const char *comp2str[] = {
177 #ifdef HAVE_PTHREAD_H
179 * Lock the mutex for the module
181 static void safe_lock(module_instance_t *instance)
184 pthread_mutex_lock(instance->mutex);
188 * Unlock the mutex for the module
190 static void safe_unlock(module_instance_t *instance)
193 pthread_mutex_unlock(instance->mutex);
197 * No threads: these functions become NULL's.
199 #define safe_lock(foo)
200 #define safe_unlock(foo)
203 static int call_modsingle(int component, modsingle *sp, REQUEST *request,
206 int myresult = default_result;
208 DEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
209 comp2str[component], sp->modinst->name,
210 sp->modinst->entry->name, request->number);
211 safe_lock(sp->modinst);
212 myresult = sp->modinst->entry->module->methods[component](
213 sp->modinst->insthandle, request);
214 safe_unlock(sp->modinst);
215 DEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
216 comp2str[component], sp->modinst->name,
217 sp->modinst->entry->name, request->number);
222 static int call_modgroup(int component, modgroup *g, REQUEST *request,
225 int myresult = default_result;
229 /* Assign the lowest possible preference to the default return code */
232 /* Loop over the children */
233 for(p = g->children; p; p = p->next) {
234 int r = RLM_MODULE_FAIL;
236 /* Call this child by recursing into modcall */
237 r = modcall(component, p, request);
240 DEBUG2("%s: action for %s is %s",
241 comp2str[component], lrad_int2str(rcode_table, r, "??"),
242 action2str(p->actions[r]));
245 /* Find an action to go with the child's result. If "return",
246 * break out of the loop so the rest of the children in the
247 * list will be skipped. */
248 if(p->actions[r] == MOD_ACTION_RETURN) {
253 /* Otherwise, the action is a number, the preference level of
254 * this return code. If no higher preference has been seen
255 * yet, remember this one. */
256 if(p->actions[r] >= myresultpref) {
258 myresultpref = p->actions[r];
265 int modcall(int component, modcallable *c, REQUEST *request)
269 /* Choose a default return value appropriate for the component */
271 case RLM_COMPONENT_AUTZ:
272 myresult = RLM_MODULE_NOTFOUND;
274 case RLM_COMPONENT_AUTH:
275 myresult = RLM_MODULE_REJECT;
277 case RLM_COMPONENT_PREACCT:
278 myresult = RLM_MODULE_NOOP;
280 case RLM_COMPONENT_ACCT:
281 myresult = RLM_MODULE_NOOP;
283 case RLM_COMPONENT_SESS:
284 myresult = RLM_MODULE_FAIL;
286 case RLM_COMPONENT_PRE_PROXY:
287 myresult = RLM_MODULE_NOOP;
289 case RLM_COMPONENT_POST_PROXY:
290 myresult = RLM_MODULE_NOOP;
292 case RLM_COMPONENT_POST_AUTH:
293 myresult = RLM_MODULE_NOOP;
296 myresult = RLM_MODULE_FAIL;
301 DEBUG2("modcall[%s]: NULL object returns %s for request %d",
303 lrad_int2str(rcode_table, myresult, "??"),
308 if(c->type==MOD_GROUP) {
309 modgroup *g = mod_callabletogroup(c);
311 DEBUG2("modcall: entering group %s for request %d",
312 c->name, request->number);
314 myresult = call_modgroup(component, g, request, myresult);
316 DEBUG2("modcall: group %s returns %s for request %d",
318 lrad_int2str(rcode_table, myresult, "??"),
321 modsingle *sp = mod_callabletosingle(c);
323 myresult = call_modsingle(component, sp, request, myresult);
325 DEBUG2(" modcall[%s]: module \"%s\" returns %s for request %d",
326 comp2str[component], c->name,
327 lrad_int2str(rcode_table, myresult, "??"),
335 /* If you suspect a bug in the parser, you'll want to use these dump
336 * functions. dump_tree should reproduce a whole tree exactly as it was found
337 * in radiusd.conf, but in long form (all actions explicitly defined) */
338 static void dump_mc(modcallable *c, int indent)
342 if(c->type==MOD_SINGLE) {
343 modsingle *single = mod_callabletosingle(c);
344 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
345 single->modinst->name);
347 modgroup *g = mod_callabletogroup(c);
349 DEBUG("%.*sgroup {", indent, "\t\t\t\t\t\t\t\t\t\t\t");
350 for(p = g->children;p;p = p->next)
351 dump_mc(p, indent+1);
354 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
355 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
356 lrad_int2str(rcode_table, i, "??"),
357 action2str(c->actions[i]));
360 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
363 static void dump_tree(int comp, modcallable *c)
365 DEBUG("[%s]", comp2str[comp]);
369 static void dump_tree(int comp UNUSED, modcallable *c UNUSED)
375 #define GROUPTYPE_SIMPLEGROUP 0
376 #define GROUPTYPE_REDUNDANT 1
377 #define GROUPTYPE_APPEND 2
378 #define GROUPTYPE_COUNT 3
380 /* These are the default actions. For each component, the group{} block
381 * behaves like the code from the old module_*() function. redundant{} and
382 * append{} are based on my guesses of what they will be used for. --Pac. */
384 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
390 MOD_ACTION_RETURN, /* reject */
392 MOD_ACTION_RETURN, /* ok */
393 MOD_ACTION_RETURN, /* handled */
395 MOD_ACTION_RETURN, /* userlock */
396 MOD_ACTION_RETURN, /* notfound */
402 MOD_ACTION_RETURN, /* reject */
404 MOD_ACTION_RETURN, /* ok */
405 MOD_ACTION_RETURN, /* handled */
406 MOD_ACTION_RETURN, /* invalid */
407 MOD_ACTION_RETURN, /* userlock */
408 MOD_ACTION_RETURN, /* notfound */
409 MOD_ACTION_RETURN, /* noop */
410 MOD_ACTION_RETURN /* updated */
414 MOD_ACTION_RETURN, /* reject */
416 MOD_ACTION_RETURN, /* ok */
417 MOD_ACTION_RETURN, /* handled */
418 MOD_ACTION_RETURN, /* invalid */
419 MOD_ACTION_RETURN, /* userlock */
421 MOD_ACTION_RETURN, /* noop */
422 MOD_ACTION_RETURN /* updated */
429 MOD_ACTION_RETURN, /* reject */
430 MOD_ACTION_RETURN, /* fail */
432 MOD_ACTION_RETURN, /* handled */
433 MOD_ACTION_RETURN, /* invalid */
434 MOD_ACTION_RETURN, /* userlock */
441 MOD_ACTION_RETURN, /* reject */
443 MOD_ACTION_RETURN, /* ok */
444 MOD_ACTION_RETURN, /* handled */
445 MOD_ACTION_RETURN, /* invalid */
446 MOD_ACTION_RETURN, /* userlock */
447 MOD_ACTION_RETURN, /* notfound */
448 MOD_ACTION_RETURN, /* noop */
449 MOD_ACTION_RETURN /* updated */
453 MOD_ACTION_RETURN, /* reject */
455 MOD_ACTION_RETURN, /* ok */
456 MOD_ACTION_RETURN, /* handled */
457 MOD_ACTION_RETURN, /* invalid */
458 MOD_ACTION_RETURN, /* userlock */
460 MOD_ACTION_RETURN, /* noop */
461 MOD_ACTION_RETURN /* updated */
468 MOD_ACTION_RETURN, /* reject */
469 MOD_ACTION_RETURN, /* fail */
471 MOD_ACTION_RETURN, /* handled */
472 MOD_ACTION_RETURN, /* invalid */
473 MOD_ACTION_RETURN, /* userlock */
474 MOD_ACTION_RETURN, /* notfound */
480 MOD_ACTION_RETURN, /* reject */
482 MOD_ACTION_RETURN, /* ok */
483 MOD_ACTION_RETURN, /* handled */
484 MOD_ACTION_RETURN, /* invalid */
485 MOD_ACTION_RETURN, /* userlock */
486 MOD_ACTION_RETURN, /* notfound */
487 MOD_ACTION_RETURN, /* noop */
488 MOD_ACTION_RETURN /* updated */
492 MOD_ACTION_RETURN, /* reject */
494 MOD_ACTION_RETURN, /* ok */
495 MOD_ACTION_RETURN, /* handled */
496 MOD_ACTION_RETURN, /* invalid */
497 MOD_ACTION_RETURN, /* userlock */
499 MOD_ACTION_RETURN, /* noop */
500 MOD_ACTION_RETURN /* updated */
507 MOD_ACTION_RETURN, /* reject */
508 MOD_ACTION_RETURN, /* fail */
510 MOD_ACTION_RETURN, /* handled */
511 MOD_ACTION_RETURN, /* invalid */
512 MOD_ACTION_RETURN, /* userlock */
513 MOD_ACTION_RETURN, /* notfound */
522 MOD_ACTION_RETURN, /* handled */
531 MOD_ACTION_RETURN, /* reject */
533 MOD_ACTION_RETURN, /* ok */
534 MOD_ACTION_RETURN, /* handled */
535 MOD_ACTION_RETURN, /* invalid */
536 MOD_ACTION_RETURN, /* userlock */
538 MOD_ACTION_RETURN, /* noop */
539 MOD_ACTION_RETURN /* updated */
546 MOD_ACTION_RETURN, /* reject */
548 MOD_ACTION_RETURN, /* ok */
549 MOD_ACTION_RETURN, /* handled */
550 MOD_ACTION_RETURN, /* invalid */
551 MOD_ACTION_RETURN, /* userlock */
552 MOD_ACTION_RETURN, /* notfound */
553 MOD_ACTION_RETURN, /* noop */
554 MOD_ACTION_RETURN /* updated */
558 MOD_ACTION_RETURN, /* reject */
560 MOD_ACTION_RETURN, /* ok */
561 MOD_ACTION_RETURN, /* handled */
562 MOD_ACTION_RETURN, /* invalid */
563 MOD_ACTION_RETURN, /* userlock */
564 MOD_ACTION_RETURN, /* notfound */
565 MOD_ACTION_RETURN, /* noop */
566 MOD_ACTION_RETURN /* updated */
570 MOD_ACTION_RETURN, /* reject */
572 MOD_ACTION_RETURN, /* ok */
573 MOD_ACTION_RETURN, /* handled */
574 MOD_ACTION_RETURN, /* invalid */
575 MOD_ACTION_RETURN, /* userlock */
576 MOD_ACTION_RETURN, /* notfound */
577 MOD_ACTION_RETURN, /* noop */
578 MOD_ACTION_RETURN /* updated */
585 MOD_ACTION_RETURN, /* reject */
586 MOD_ACTION_RETURN, /* fail */
588 MOD_ACTION_RETURN, /* handled */
589 MOD_ACTION_RETURN, /* invalid */
590 MOD_ACTION_RETURN, /* userlock */
597 MOD_ACTION_RETURN, /* reject */
599 MOD_ACTION_RETURN, /* ok */
600 MOD_ACTION_RETURN, /* handled */
601 MOD_ACTION_RETURN, /* invalid */
602 MOD_ACTION_RETURN, /* userlock */
603 MOD_ACTION_RETURN, /* notfound */
604 MOD_ACTION_RETURN, /* noop */
605 MOD_ACTION_RETURN /* updated */
609 MOD_ACTION_RETURN, /* reject */
611 MOD_ACTION_RETURN, /* ok */
612 MOD_ACTION_RETURN, /* handled */
613 MOD_ACTION_RETURN, /* invalid */
614 MOD_ACTION_RETURN, /* userlock */
616 MOD_ACTION_RETURN, /* noop */
617 MOD_ACTION_RETURN /* updated */
624 MOD_ACTION_RETURN, /* reject */
625 MOD_ACTION_RETURN, /* fail */
627 MOD_ACTION_RETURN, /* handled */
628 MOD_ACTION_RETURN, /* invalid */
629 MOD_ACTION_RETURN, /* userlock */
636 MOD_ACTION_RETURN, /* reject */
638 MOD_ACTION_RETURN, /* ok */
639 MOD_ACTION_RETURN, /* handled */
640 MOD_ACTION_RETURN, /* invalid */
641 MOD_ACTION_RETURN, /* userlock */
642 MOD_ACTION_RETURN, /* notfound */
643 MOD_ACTION_RETURN, /* noop */
644 MOD_ACTION_RETURN /* updated */
648 MOD_ACTION_RETURN, /* reject */
650 MOD_ACTION_RETURN, /* ok */
651 MOD_ACTION_RETURN, /* handled */
652 MOD_ACTION_RETURN, /* invalid */
653 MOD_ACTION_RETURN, /* userlock */
655 MOD_ACTION_RETURN, /* noop */
656 MOD_ACTION_RETURN /* updated */
663 MOD_ACTION_RETURN, /* reject */
664 MOD_ACTION_RETURN, /* fail */
666 MOD_ACTION_RETURN, /* handled */
667 MOD_ACTION_RETURN, /* invalid */
668 MOD_ACTION_RETURN, /* userlock */
675 MOD_ACTION_RETURN, /* reject */
677 MOD_ACTION_RETURN, /* ok */
678 MOD_ACTION_RETURN, /* handled */
679 MOD_ACTION_RETURN, /* invalid */
680 MOD_ACTION_RETURN, /* userlock */
681 MOD_ACTION_RETURN, /* notfound */
682 MOD_ACTION_RETURN, /* noop */
683 MOD_ACTION_RETURN /* updated */
687 MOD_ACTION_RETURN, /* reject */
689 MOD_ACTION_RETURN, /* ok */
690 MOD_ACTION_RETURN, /* handled */
691 MOD_ACTION_RETURN, /* invalid */
692 MOD_ACTION_RETURN, /* userlock */
694 MOD_ACTION_RETURN, /* noop */
695 MOD_ACTION_RETURN /* updated */
700 /* Bail out if the module in question does not supply the wanted component */
701 static void sanity_check(int component, module_instance_t *inst,
702 const char *filename)
704 if (!inst->entry->module->methods[component]) {
706 "%s: \"%s\" modules aren't allowed in '%s' sections -- they have no such method.",
707 filename, inst->entry->module->name,
708 component_names[component]);
713 /* Parse a CONF_SECTION containing only result=action pairs */
714 static void override_actions(modcallable *c, CONF_SECTION *cs,
715 const char *filename)
719 const char *attr, *value;
720 int lineno, rcode, action;
722 for(ci=cf_item_find_next(cs, NULL); ci != NULL; ci=cf_item_find_next(cs, ci)) {
723 if(cf_item_is_section(ci)) {
725 "%s[%d] Subsection of module instance call "
726 "not allowed\n", filename,
727 cf_section_lineno(cf_itemtosection(ci)));
730 cp = cf_itemtopair(ci);
731 attr = cf_pair_attr(cp);
732 value = cf_pair_value(cp);
733 lineno = cf_pair_lineno(cp);
734 rcode = str2rcode(attr, filename, lineno);
735 action = str2action(value, filename, lineno);
736 c->actions[rcode] = action;
740 static modcallable *do_compile_modsingle(int component, CONF_ITEM *ci,
741 const char *filename, int grouptype,
742 const char **modname)
745 const char *modrefname;
747 modcallable *csingle;
748 module_instance_t *this;
750 if (cf_item_is_section(ci)) {
751 CONF_SECTION *cs = cf_itemtosection(ci);
753 lineno = cf_section_lineno(cs);
754 modrefname = cf_section_name1(cs);
756 /* group{}, redundant{}, or append{} may appear where a
757 * single module instance was expected - in that case, we
758 * hand it off to compile_modgroup */
759 if (strcmp(modrefname, "group") == 0) {
760 *modname = "UnnamedGroup";
761 return do_compile_modgroup(component, cs, filename,
762 GROUPTYPE_SIMPLEGROUP, grouptype);
763 } else if (strcmp(modrefname, "redundant") == 0) {
764 *modname = "UnnamedGroup";
765 return do_compile_modgroup(component, cs, filename,
766 GROUPTYPE_REDUNDANT, grouptype);
767 } else if (strcmp(modrefname, "append") == 0) {
768 *modname = "UnnamedGroup";
769 return do_compile_modgroup(component, cs, filename,
770 GROUPTYPE_APPEND, grouptype);
773 CONF_PAIR *cp = cf_itemtopair(ci);
774 lineno = cf_pair_lineno(cp);
775 modrefname = cf_pair_attr(cp);
778 single = rad_malloc(sizeof(*single));
779 csingle = mod_singletocallable(single);
780 csingle->next = NULL;
781 memcpy(csingle->actions,
782 defaultactions[component][grouptype],
783 sizeof csingle->actions);
784 rad_assert(modrefname != NULL);
785 csingle->name = modrefname;
786 csingle->type = MOD_SINGLE;
788 if (cf_item_is_section(ci)) {
789 /* override default actions with what's in the CONF_SECTION */
790 override_actions(csingle, cf_itemtosection(ci), filename);
793 this = find_module_instance(modrefname);
798 sanity_check(component, this, filename);
800 single->modinst = this;
801 *modname = this->entry->module->name;
805 modcallable *compile_modsingle(int component, CONF_ITEM *ci,
806 const char *filename, const char **modname)
808 modcallable *ret = do_compile_modsingle(component, ci, filename,
809 GROUPTYPE_SIMPLEGROUP,
811 dump_tree(component, ret);
815 static modcallable *do_compile_modgroup(int component, CONF_SECTION *cs,
816 const char *filename, int grouptype,
823 g = rad_malloc(sizeof *g);
825 c = mod_grouptocallable(g);
827 memcpy(c->actions, defaultactions[component][parentgrouptype],
829 c->name = cf_section_name1(cs);
830 rad_assert(c->name != NULL);
834 for (ci=cf_item_find_next(cs, NULL); ci != NULL; ci=cf_item_find_next(cs, ci)) {
835 if(cf_item_is_section(ci)) {
838 single = do_compile_modsingle(component, ci, filename,
840 add_child(g, single);
842 const char *attr, *value;
843 CONF_PAIR *cp = cf_itemtopair(ci);
846 attr = cf_pair_attr(cp);
847 value = cf_pair_value(cp);
848 lineno = cf_pair_lineno(cp);
850 /* A CONF_PAIR is either a module instance with no
851 * actions specified... */
856 single = do_compile_modsingle(component,
857 cf_pairtoitem(cp), filename,
859 add_child(g, single);
861 /* ...or an action to be applied to this
864 rcode = str2rcode(attr, filename, lineno);
865 action = str2action(value, filename, lineno);
867 c->actions[rcode] = action;
871 return mod_grouptocallable(g);
874 modcallable *compile_modgroup(int component, CONF_SECTION *cs,
875 const char *filename)
877 modcallable *ret = do_compile_modgroup(component, cs, filename,
878 GROUPTYPE_SIMPLEGROUP,
879 GROUPTYPE_SIMPLEGROUP);
880 dump_tree(component, ret);
884 void add_to_modcallable(modcallable **parent, modcallable *this,
885 int component, char *name)
889 if (*parent == NULL) {
892 g = rad_malloc(sizeof *g);
893 c = mod_grouptocallable(g);
896 defaultactions[component][GROUPTYPE_SIMPLEGROUP],
898 rad_assert(name != NULL);
903 *parent = mod_grouptocallable(g);
905 g = mod_callabletogroup(*parent);
911 void modcallable_free(modcallable **pc)
913 modcallable *c, *loop, *next;
915 if(c->type==MOD_GROUP) {
916 for(loop=mod_callabletogroup(c)->children ; loop ; loop=next) {
918 modcallable_free(&loop);