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
32 /* mutually-recursive static functions need a prototype up front */
33 static modcallable *do_compile_modgroup(int, CONF_SECTION *, const char *,
36 /* Actions may be a positive integer (the highest one returned in the group
37 * will be returned), or the keyword "return", represented here by
38 * MOD_ACTION_RETURN, to cause an immediate return. */
39 #define MOD_ACTION_RETURN (-1)
41 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
42 * explanation of what they are all about, see ../../doc/README.failover */
44 struct modcallable *next;
45 int actions[RLM_MODULE_NUMCODES];
47 enum { MOD_SINGLE, MOD_GROUP } type;
52 modcallable *children;
57 module_instance_t *modinst;
60 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
61 * so we often want to go back and forth between them. */
62 static modsingle *mod_callabletosingle(modcallable *p)
64 assert(p->type==MOD_SINGLE);
65 return (modsingle *)p;
67 static modgroup *mod_callabletogroup(modcallable *p)
69 assert(p->type==MOD_GROUP);
72 static modcallable *mod_singletocallable(modsingle *p)
74 return (modcallable *)p;
76 static modcallable *mod_grouptocallable(modgroup *p)
78 return (modcallable *)p;
81 /* modgroups are grown by adding a modcallable to the end */
82 static void add_child(modgroup *g, modcallable *c)
84 modcallable **head = &g->children;
85 modcallable *node = *head;
86 modcallable **last = head;
93 assert(c->next == NULL);
97 /* Here's where we recognize all of our keywords: first the rcodes, then the
99 static int str2rcode(const char *s, const char *filename, int lineno)
101 if(!strcasecmp(s, "reject"))
102 return RLM_MODULE_REJECT;
103 else if(!strcasecmp(s, "fail"))
104 return RLM_MODULE_FAIL;
105 else if(!strcasecmp(s, "ok"))
106 return RLM_MODULE_OK;
107 else if(!strcasecmp(s, "handled"))
108 return RLM_MODULE_HANDLED;
109 else if(!strcasecmp(s, "invalid"))
110 return RLM_MODULE_INVALID;
111 else if(!strcasecmp(s, "userlock"))
112 return RLM_MODULE_USERLOCK;
113 else if(!strcasecmp(s, "notfound"))
114 return RLM_MODULE_NOTFOUND;
115 else if(!strcasecmp(s, "noop"))
116 return RLM_MODULE_NOOP;
117 else if(!strcasecmp(s, "updated"))
118 return RLM_MODULE_UPDATED;
121 "%s[%d] Unknown module rcode '%s'.\n",
122 filename, lineno, s);
127 static const char *rcode2str[] = {
139 static int str2action(const char *s, const char *filename, int lineno)
141 if(!strcasecmp(s, "return"))
142 return MOD_ACTION_RETURN;
143 else if(strspn(s, "0123456789")==strlen(s))
147 "%s[%d] Unknown action '%s'.\n",
148 filename, lineno, s);
153 static const char *action2str(int action)
156 if(action==MOD_ACTION_RETURN)
158 snprintf(buf, sizeof buf, "%d", action);
162 /* Some short names for debugging output */
163 static const char *comp2str[] = {
173 * Lock the mutex for the module
175 static void safe_lock(module_instance_t *instance)
178 pthread_mutex_lock(instance->mutex);
182 * Unlock the mutex for the module
184 static void safe_unlock(module_instance_t *instance)
187 pthread_mutex_unlock(instance->mutex);
191 * No threads: these functions become NULL's.
193 #define safe_lock(foo)
194 #define safe_unlock(foo)
197 static int call_modsingle(int component, modsingle *sp, REQUEST *request,
200 int myresult = default_result;
202 safe_lock(sp->modinst);
203 myresult = sp->modinst->entry->module->methods[component](
204 sp->modinst->insthandle, request);
205 safe_unlock(sp->modinst);
210 static int call_modgroup(int component, modgroup *g, REQUEST *request,
213 int myresult = default_result;
217 /* Assign the lowest possible preference to the default return code */
220 /* Loop over the children */
221 for(p = g->children; p; p = p->next) {
222 int r = RLM_MODULE_FAIL;
224 /* Call this child by recursing into modcall */
225 r = modcall(component, p, request);
227 DEBUG2("modcall[%s]: action for %s is %s",
228 comp2str[component], rcode2str[r],
229 action2str(p->actions[r]));
231 /* Find an action to go with the child's result. If "return",
232 * break out of the loop so the rest of the children in the
233 * list will be skipped. */
234 if(p->actions[r] == MOD_ACTION_RETURN) {
239 /* Otherwise, the action is a number, the preference level of
240 * this return code. If no higher preference has been seen
241 * yet, remember this one. */
242 if(p->actions[r] >= myresultpref) {
244 myresultpref = p->actions[r];
251 int modcall(int component, modcallable *c, REQUEST *request)
255 /* Choose a default return value appropriate for the component */
257 case RLM_COMPONENT_AUTZ: myresult = RLM_MODULE_NOTFOUND;break;
258 case RLM_COMPONENT_AUTH: myresult = RLM_MODULE_REJECT; break;
259 case RLM_COMPONENT_PREACCT: myresult = RLM_MODULE_NOOP; break;
260 case RLM_COMPONENT_ACCT: myresult = RLM_MODULE_NOOP; break;
261 case RLM_COMPONENT_SESS: myresult = RLM_MODULE_FAIL; break;
262 default: myresult = RLM_MODULE_FAIL;
266 DEBUG2("modcall[%s]: Null object returns %s",
267 comp2str[component], rcode2str[myresult]);
271 if(c->type==MOD_GROUP) {
272 modgroup *g = mod_callabletogroup(c);
274 DEBUG2("modcall[%s]: Entering group at line %d",
275 comp2str[component], c->lineno);
277 myresult = call_modgroup(component, g, request, myresult);
279 DEBUG2("modcall[%s]: Group at line %d returns %s",
280 comp2str[component], c->lineno, rcode2str[myresult]);
282 modsingle *sp = mod_callabletosingle(c);
284 myresult = call_modsingle(component, sp, request, myresult);
286 DEBUG2("modcall[%s]: Module at line %d returns %s",
287 comp2str[component], c->lineno, rcode2str[myresult]);
293 /* If you suspect a bug in the parser, you'll want to use these dump
294 * functions. dump_tree should reproduce a whole tree exactly as it was found
295 * in radiusd.conf, but in long form (all actions explicitly defined) */
296 static void dump_mc(modcallable *c, int indent)
300 if(c->type==MOD_SINGLE) {
301 modsingle *single = mod_callabletosingle(c);
302 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
303 single->modinst->name);
305 modgroup *g = mod_callabletogroup(c);
307 DEBUG("%.*sgroup {", indent, "\t\t\t\t\t\t\t\t\t\t\t");
308 for(p = g->children;p;p = p->next)
309 dump_mc(p, indent+1);
312 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
313 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
314 rcode2str[i], action2str(c->actions[i]));
317 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
320 static void dump_tree(int comp, modcallable *c)
322 DEBUG("[%s]", comp2str[comp]);
326 #define GROUPTYPE_SIMPLEGROUP 0
327 #define GROUPTYPE_REDUNDANT 1
328 #define GROUPTYPE_APPEND 2
329 #define GROUPTYPE_COUNT 3
331 /* These are the default actions. For each component, the group{} block
332 * behaves like the code from the old module_*() function. redundant{} and
333 * append{} are based on my guesses of what they will be used for. --Pac. */
335 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
341 MOD_ACTION_RETURN, /* reject */
343 MOD_ACTION_RETURN, /* ok */
344 MOD_ACTION_RETURN, /* handled */
346 MOD_ACTION_RETURN, /* userlock */
347 MOD_ACTION_RETURN, /* notfound */
353 MOD_ACTION_RETURN, /* reject */
355 MOD_ACTION_RETURN, /* ok */
356 MOD_ACTION_RETURN, /* handled */
357 MOD_ACTION_RETURN, /* invalid */
358 MOD_ACTION_RETURN, /* userlock */
359 MOD_ACTION_RETURN, /* notfound */
360 MOD_ACTION_RETURN, /* noop */
361 MOD_ACTION_RETURN /* updated */
365 MOD_ACTION_RETURN, /* reject */
367 MOD_ACTION_RETURN, /* ok */
368 MOD_ACTION_RETURN, /* handled */
369 MOD_ACTION_RETURN, /* invalid */
370 MOD_ACTION_RETURN, /* userlock */
372 MOD_ACTION_RETURN, /* noop */
373 MOD_ACTION_RETURN /* updated */
380 MOD_ACTION_RETURN, /* reject */
381 MOD_ACTION_RETURN, /* fail */
383 MOD_ACTION_RETURN, /* handled */
384 MOD_ACTION_RETURN, /* invalid */
385 MOD_ACTION_RETURN, /* userlock */
392 MOD_ACTION_RETURN, /* reject */
394 MOD_ACTION_RETURN, /* ok */
395 MOD_ACTION_RETURN, /* handled */
396 MOD_ACTION_RETURN, /* invalid */
397 MOD_ACTION_RETURN, /* userlock */
398 MOD_ACTION_RETURN, /* notfound */
399 MOD_ACTION_RETURN, /* noop */
400 MOD_ACTION_RETURN /* updated */
404 MOD_ACTION_RETURN, /* reject */
406 MOD_ACTION_RETURN, /* ok */
407 MOD_ACTION_RETURN, /* handled */
408 MOD_ACTION_RETURN, /* invalid */
409 MOD_ACTION_RETURN, /* userlock */
411 MOD_ACTION_RETURN, /* noop */
412 MOD_ACTION_RETURN /* updated */
419 MOD_ACTION_RETURN, /* reject */
420 MOD_ACTION_RETURN, /* fail */
422 MOD_ACTION_RETURN, /* handled */
423 MOD_ACTION_RETURN, /* invalid */
424 MOD_ACTION_RETURN, /* userlock */
425 MOD_ACTION_RETURN, /* notfound */
431 MOD_ACTION_RETURN, /* reject */
433 MOD_ACTION_RETURN, /* ok */
434 MOD_ACTION_RETURN, /* handled */
435 MOD_ACTION_RETURN, /* invalid */
436 MOD_ACTION_RETURN, /* userlock */
437 MOD_ACTION_RETURN, /* notfound */
438 MOD_ACTION_RETURN, /* noop */
439 MOD_ACTION_RETURN /* updated */
443 MOD_ACTION_RETURN, /* reject */
445 MOD_ACTION_RETURN, /* ok */
446 MOD_ACTION_RETURN, /* handled */
447 MOD_ACTION_RETURN, /* invalid */
448 MOD_ACTION_RETURN, /* userlock */
450 MOD_ACTION_RETURN, /* noop */
451 MOD_ACTION_RETURN /* updated */
458 MOD_ACTION_RETURN, /* reject */
459 MOD_ACTION_RETURN, /* fail */
461 MOD_ACTION_RETURN, /* handled */
462 MOD_ACTION_RETURN, /* invalid */
463 MOD_ACTION_RETURN, /* userlock */
464 MOD_ACTION_RETURN, /* notfound */
473 MOD_ACTION_RETURN, /* handled */
482 MOD_ACTION_RETURN, /* reject */
484 MOD_ACTION_RETURN, /* ok */
485 MOD_ACTION_RETURN, /* handled */
486 MOD_ACTION_RETURN, /* invalid */
487 MOD_ACTION_RETURN, /* userlock */
489 MOD_ACTION_RETURN, /* noop */
490 MOD_ACTION_RETURN /* updated */
497 MOD_ACTION_RETURN, /* reject */
499 MOD_ACTION_RETURN, /* ok */
500 MOD_ACTION_RETURN, /* handled */
501 MOD_ACTION_RETURN, /* invalid */
502 MOD_ACTION_RETURN, /* userlock */
503 MOD_ACTION_RETURN, /* notfound */
504 MOD_ACTION_RETURN, /* noop */
505 MOD_ACTION_RETURN /* updated */
509 MOD_ACTION_RETURN, /* reject */
511 MOD_ACTION_RETURN, /* ok */
512 MOD_ACTION_RETURN, /* handled */
513 MOD_ACTION_RETURN, /* invalid */
514 MOD_ACTION_RETURN, /* userlock */
515 MOD_ACTION_RETURN, /* notfound */
516 MOD_ACTION_RETURN, /* noop */
517 MOD_ACTION_RETURN /* updated */
521 MOD_ACTION_RETURN, /* reject */
523 MOD_ACTION_RETURN, /* ok */
524 MOD_ACTION_RETURN, /* handled */
525 MOD_ACTION_RETURN, /* invalid */
526 MOD_ACTION_RETURN, /* userlock */
527 MOD_ACTION_RETURN, /* notfound */
528 MOD_ACTION_RETURN, /* noop */
529 MOD_ACTION_RETURN /* updated */
534 /* Bail out if the module in question does not supply the wanted component */
535 static void sanity_check(int component, module_instance_t *inst, int lineno,
536 const char *filename)
538 if (!inst->entry->module->methods[component]) {
540 "%s[%d] Module %s does not contain a method for '%s'",
541 filename, lineno, inst->entry->module->name,
542 component_names[component]);
547 /* Parse a CONF_SECTION containing only result=action pairs */
548 static void override_actions(modcallable *c, CONF_SECTION *cs,
549 const char *filename)
553 const char *attr, *value;
554 int lineno, rcode, action;
556 for(ci=cf_item_find_next(cs, NULL); ci; ci=cf_item_find_next(cs, ci)) {
557 if(cf_item_is_section(ci)) {
559 "%s[%d] Subsection of module instance call "
560 "not allowed\n", filename,
561 cf_section_lineno(cf_itemtosection(ci)));
564 cp = cf_itemtopair(ci);
565 attr = cf_pair_attr(cp);
566 value = cf_pair_value(cp);
567 lineno = cf_pair_lineno(cp);
568 rcode = str2rcode(attr, filename, lineno);
569 action = str2action(value, filename, lineno);
570 c->actions[rcode] = action;
574 static modcallable *do_compile_modsingle(int component, CONF_ITEM *ci,
575 const char *filename, int grouptype,
576 const char **modname)
579 const char *modrefname;
581 modcallable *csingle;
582 module_instance_t *this;
584 if(cf_item_is_section(ci)) {
585 CONF_SECTION *cs = cf_itemtosection(ci);
587 lineno = cf_section_lineno(cs);
588 modrefname = cf_section_name1(cs);
590 /* group{}, redundant{}, or append{} may appear where a
591 * single module instance was expected - in that case, we
592 * hand it off to compile_modgroup */
593 if(!strcmp(modrefname, "group")) {
594 *modname = "UnnamedGroup";
595 return do_compile_modgroup(component, cs, filename,
596 GROUPTYPE_SIMPLEGROUP, grouptype);
597 } else if(!strcmp(modrefname, "redundant")) {
598 *modname = "UnnamedGroup";
599 return do_compile_modgroup(component, cs, filename,
600 GROUPTYPE_REDUNDANT, grouptype);
601 } else if(!strcmp(modrefname, "append")) {
602 *modname = "UnnamedGroup";
603 return do_compile_modgroup(component, cs, filename,
604 GROUPTYPE_APPEND, grouptype);
607 CONF_PAIR *cp = cf_itemtopair(ci);
608 lineno = cf_pair_lineno(cp);
609 modrefname = cf_pair_attr(cp);
612 single = rad_malloc(sizeof *single);
613 csingle = mod_singletocallable(single);
614 csingle->next = NULL;
615 memcpy(csingle->actions,
616 defaultactions[component][grouptype],
617 sizeof csingle->actions);
618 csingle->lineno = lineno;
619 csingle->type = MOD_SINGLE;
621 if(cf_item_is_section(ci)) {
622 /* override default actions with what's in the CONF_SECTION */
623 override_actions(csingle, cf_itemtosection(ci), filename);
626 this = find_module_instance(modrefname);
631 sanity_check(component, this, csingle->lineno, filename);
633 single->modinst = this;
634 *modname = this->entry->module->name;
638 modcallable *compile_modsingle(int component, CONF_ITEM *ci,
639 const char *filename, const char **modname)
641 modcallable *ret = do_compile_modsingle(component, ci, filename,
642 GROUPTYPE_SIMPLEGROUP,
644 /*dump_tree(component, ret);*/
648 static modcallable *do_compile_modgroup(int component, CONF_SECTION *cs,
649 const char *filename, int grouptype,
656 g = rad_malloc(sizeof *g);
658 c = mod_grouptocallable(g);
660 memcpy(c->actions, defaultactions[component][parentgrouptype],
662 c->lineno = cf_section_lineno(cs);
666 for(ci=cf_item_find_next(cs, NULL); ci; ci=cf_item_find_next(cs, ci)) {
667 if(cf_item_is_section(ci)) {
670 single = do_compile_modsingle(component, ci, filename,
672 add_child(g, single);
674 const char *attr, *value;
675 CONF_PAIR *cp = cf_itemtopair(ci);
678 attr = cf_pair_attr(cp);
679 value = cf_pair_value(cp);
680 lineno = cf_pair_lineno(cp);
682 /* A CONF_PAIR is either a module instance with no
683 * actions specified... */
688 single = do_compile_modsingle(component,
689 cf_pairtoitem(cp), filename,
691 add_child(g, single);
693 /* ...or an action to be applied to this
696 rcode = str2rcode(attr, filename, lineno);
697 action = str2action(value, filename, lineno);
699 c->actions[rcode] = action;
703 return mod_grouptocallable(g);
706 modcallable *compile_modgroup(int component, CONF_SECTION *cs,
707 const char *filename)
709 modcallable *ret = do_compile_modgroup(component, cs, filename,
710 GROUPTYPE_SIMPLEGROUP,
711 GROUPTYPE_SIMPLEGROUP);
712 /*dump_tree(component, ret);*/
716 void add_to_modcallable(modcallable **parent, modcallable *this,
717 int component, int lineno)
724 g = rad_malloc(sizeof *g);
725 c = mod_grouptocallable(g);
728 defaultactions[component][GROUPTYPE_SIMPLEGROUP],
734 *parent = mod_grouptocallable(g);
736 g = mod_callabletogroup(*parent);
742 void modcallable_free(modcallable **pc)
744 modcallable *c, *loop, *next;
746 if(c->type==MOD_GROUP) {
747 for(loop=mod_callabletogroup(c)->children ; loop ; loop=next) {
749 modcallable_free(&loop);