📄 modcall.c
字号:
/* * modcall.c * * Version: $Id: modcall.c,v 1.22.2.1 2005/02/09 18:19:00 aland Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright 2000 The FreeRADIUS server project */#include <stdlib.h>#include <string.h>#include <stdarg.h>#include "radiusd.h"#include "rad_assert.h"#include "conffile.h"#include "modpriv.h"#include "modules.h"#include "modcall.h"/* mutually-recursive static functions need a prototype up front */static modcallable *do_compile_modgroup(int, CONF_SECTION *, const char *, int, int);/* Actions may be a positive integer (the highest one returned in the group * will be returned), or the keyword "return", represented here by * MOD_ACTION_RETURN, to cause an immediate return. * There's also the keyword "reject", represented here by MOD_ACTION_REJECT * to cause an immediate reject. */#define MOD_ACTION_RETURN (-1)#define MOD_ACTION_REJECT (-2)/* Here are our basic types: modcallable, modgroup, and modsingle. For an * explanation of what they are all about, see ../../doc/README.failover */struct modcallable { struct modcallable *next; int actions[RLM_MODULE_NUMCODES]; const char *name; enum { MOD_SINGLE, MOD_GROUP } type;};typedef struct { modcallable mc; modcallable *children;} modgroup;typedef struct { modcallable mc; module_instance_t *modinst;} modsingle;/* Simple conversions: modsingle and modgroup are subclasses of modcallable, * so we often want to go back and forth between them. */static modsingle *mod_callabletosingle(modcallable *p){ rad_assert(p->type==MOD_SINGLE); return (modsingle *)p;}static modgroup *mod_callabletogroup(modcallable *p){ rad_assert(p->type==MOD_GROUP); return (modgroup *)p;}static modcallable *mod_singletocallable(modsingle *p){ return (modcallable *)p;}static modcallable *mod_grouptocallable(modgroup *p){ return (modcallable *)p;}/* modgroups are grown by adding a modcallable to the end */static void add_child(modgroup *g, modcallable *c){ modcallable **head = &g->children; modcallable *node = *head; modcallable **last = head; while (node) { last = &node->next; node = node->next; } rad_assert(c->next == NULL); *last = c;}/* Here's where we recognize all of our keywords: first the rcodes, then the * actions */static LRAD_NAME_NUMBER rcode_table[] = { { "reject", RLM_MODULE_REJECT }, { "fail", RLM_MODULE_FAIL }, { "ok", RLM_MODULE_OK }, { "handled", RLM_MODULE_HANDLED }, { "invalid", RLM_MODULE_INVALID }, { "userlock", RLM_MODULE_USERLOCK }, { "notfound", RLM_MODULE_NOTFOUND }, { "noop", RLM_MODULE_NOOP }, { "updated", RLM_MODULE_UPDATED }, { NULL, 0 }};static int str2rcode(const char *s, const char *filename, int lineno){ int rcode; rcode = lrad_str2int(rcode_table, s, -1); if (rcode < 0) { radlog(L_ERR|L_CONS, "%s[%d] Unknown module rcode '%s'.\n", filename, lineno, s); exit(1); } return rcode;}static int str2action(const char *s, const char *filename, int lineno){ if(!strcasecmp(s, "return")) return MOD_ACTION_RETURN; else if(!strcasecmp(s, "reject")) return MOD_ACTION_REJECT; else if (strspn(s, "0123456789")==strlen(s)) { int rcode = atoi(s); /* * Don't allow priority zero, for future use. */ if (rcode == 0) { radlog(L_ERR|L_CONS, "%s[%d] Invalid action '%s'.\n", filename, lineno, s); exit(1); } return rcode; } else { radlog(L_ERR|L_CONS, "%s[%d] Unknown action '%s'.\n", filename, lineno, s); exit(1); } return -1;}#if 0static const char *action2str(int action){ static char buf[32]; if(action==MOD_ACTION_RETURN) return "return"; if(action==MOD_ACTION_REJECT) return "reject"; snprintf(buf, sizeof buf, "%d", action); return buf;}#endif/* Some short names for debugging output */static const char *comp2str[] = { "authenticate", "authorize", "preacct", "accounting", "session", "pre-proxy", "post-proxy", "post-auth"};#ifdef HAVE_PTHREAD_H/* * Lock the mutex for the module */static void safe_lock(module_instance_t *instance){ if (instance->mutex) pthread_mutex_lock(instance->mutex);}/* * Unlock the mutex for the module */static void safe_unlock(module_instance_t *instance){ if (instance->mutex) pthread_mutex_unlock(instance->mutex);}#else/* * No threads: these functions become NULL's. */#define safe_lock(foo)#define safe_unlock(foo)#endifstatic int call_modsingle(int component, modsingle *sp, REQUEST *request, int default_result){ int myresult = default_result; DEBUG3(" modsingle[%s]: calling %s (%s) for request %d", comp2str[component], sp->modinst->name, sp->modinst->entry->name, request->number); safe_lock(sp->modinst); myresult = sp->modinst->entry->module->methods[component]( sp->modinst->insthandle, request); safe_unlock(sp->modinst); DEBUG3(" modsingle[%s]: returned from %s (%s) for request %d", comp2str[component], sp->modinst->name, sp->modinst->entry->name, request->number); return myresult;}static int call_modgroup(int component, modgroup *g, REQUEST *request, int default_result){ int myresult = default_result; int myresultpref; modcallable *p; /* * Catch people who have issues. */ if (!g->children) { DEBUG2(" WARNING! Asked to process empty group. Returning %s.", lrad_int2str(rcode_table, myresult, "??")); return default_result; } /* Assign the lowest possible preference to the default return code */ myresultpref = 0; /* Loop over the children */ for(p = g->children; p; p = p->next) { int r = RLM_MODULE_FAIL; /* Call this child by recursing into modcall */ r = modcall(component, p, request);#if 0 DEBUG2("%s: action for %s is %s", comp2str[component], lrad_int2str(rcode_table, r, "??"), action2str(p->actions[r]));#endif /* Find an action to go with the child's result. If "return", * break out of the loop so the rest of the children in the * list will be skipped. */ if(p->actions[r] == MOD_ACTION_RETURN) { myresult = r; break; } /* If "reject" break out of the loop and return reject */ if (p->actions[r] == MOD_ACTION_REJECT) { myresult = RLM_MODULE_REJECT; break; } /* Otherwise, the action is a number, the preference level of * this return code. If no higher preference has been seen * yet, remember this one. */ if(p->actions[r] >= myresultpref) { myresult = r; myresultpref = p->actions[r]; } } return myresult;}int modcall(int component, modcallable *c, REQUEST *request){ int myresult; /* Choose a default return value appropriate for the component */ switch(component) { case RLM_COMPONENT_AUTZ: myresult = RLM_MODULE_NOTFOUND; break; case RLM_COMPONENT_AUTH: myresult = RLM_MODULE_REJECT; break; case RLM_COMPONENT_PREACCT: myresult = RLM_MODULE_NOOP; break; case RLM_COMPONENT_ACCT: myresult = RLM_MODULE_NOOP; break; case RLM_COMPONENT_SESS: myresult = RLM_MODULE_FAIL; break; case RLM_COMPONENT_PRE_PROXY: myresult = RLM_MODULE_NOOP; break; case RLM_COMPONENT_POST_PROXY: myresult = RLM_MODULE_NOOP; break; case RLM_COMPONENT_POST_AUTH: myresult = RLM_MODULE_NOOP; break; default: myresult = RLM_MODULE_FAIL; break; } if(c == NULL) { DEBUG2("modcall[%s]: NULL object returns %s for request %d", comp2str[component], lrad_int2str(rcode_table, myresult, "??"), request->number); return myresult; } if(c->type==MOD_GROUP) { modgroup *g = mod_callabletogroup(c); DEBUG2("modcall: entering group %s for request %d", c->name, request->number); myresult = call_modgroup(component, g, request, myresult); DEBUG2("modcall: group %s returns %s for request %d", c->name, lrad_int2str(rcode_table, myresult, "??"), request->number); } else { modsingle *sp = mod_callabletosingle(c); myresult = call_modsingle(component, sp, request, myresult); DEBUG2(" modcall[%s]: module \"%s\" returns %s for request %d", comp2str[component], c->name, lrad_int2str(rcode_table, myresult, "??"), request->number); } return myresult;}#if 0/* If you suspect a bug in the parser, you'll want to use these dump * functions. dump_tree should reproduce a whole tree exactly as it was found * in radiusd.conf, but in long form (all actions explicitly defined) */static void dump_mc(modcallable *c, int indent){ int i; if(c->type==MOD_SINGLE) { modsingle *single = mod_callabletosingle(c); DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t", single->modinst->name); } else { modgroup *g = mod_callabletogroup(c); modcallable *p; DEBUG("%.*sgroup {", indent, "\t\t\t\t\t\t\t\t\t\t\t"); for(p = g->children;p;p = p->next) dump_mc(p, indent+1); } for(i = 0; i<RLM_MODULE_NUMCODES; ++i) { DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t", lrad_int2str(rcode_table, i, "??"), action2str(c->actions[i])); } DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");}static void dump_tree(int comp, modcallable *c){ DEBUG("[%s]", comp2str[comp]); dump_mc(c, 0);}#elsestatic void dump_tree(int comp UNUSED, modcallable *c UNUSED){ return;}#endif#define GROUPTYPE_SIMPLEGROUP 0#define GROUPTYPE_REDUNDANT 1#define GROUPTYPE_APPEND 2#define GROUPTYPE_COUNT 3/* These are the default actions. For each component, the group{} block * behaves like the code from the old module_*() function. redundant{} and * append{} are based on my guesses of what they will be used for. --Pac. */static intdefaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] ={ /* authenticate */ { /* group */ { MOD_ACTION_RETURN, /* reject */ 1, /* fail */ MOD_ACTION_RETURN, /* ok */ MOD_ACTION_RETURN, /* handled */ 1, /* invalid */ MOD_ACTION_RETURN, /* userlock */ MOD_ACTION_RETURN, /* notfound */ 1, /* noop */ 1 /* updated */ }, /* redundant */ { MOD_ACTION_RETURN, /* reject */ 1, /* fail */ MOD_ACTION_RETURN, /* ok */ MOD_ACTION_RETURN, /* handled */ MOD_ACTION_RETURN, /* invalid */ MOD_ACTION_RETURN, /* userlock */ MOD_ACTION_RETURN, /* notfound */ MOD_ACTION_RETURN, /* noop */ MOD_ACTION_RETURN /* updated */ }, /* append */ { MOD_ACTION_RETURN, /* reject */ 1, /* fail */ MOD_ACTION_RETURN, /* ok */ MOD_ACTION_RETURN, /* handled */ MOD_ACTION_RETURN, /* invalid */ MOD_ACTION_RETURN, /* userlock */ 2, /* notfound */ MOD_ACTION_RETURN, /* noop */ MOD_ACTION_RETURN /* updated */ } }, /* authorize */ { /* group */ { MOD_ACTION_RETURN, /* reject */ MOD_ACTION_RETURN, /* fail */ 3, /* ok */ MOD_ACTION_RETURN, /* handled */ MOD_ACTION_RETURN, /* invalid */ MOD_ACTION_RETURN, /* userlock */ 1, /* notfound */ 2, /* noop */ 4 /* updated */ }, /* redundant */ { MOD_ACTION_RETURN, /* reject */ 1, /* fail */ MOD_ACTION_RETURN, /* ok */ MOD_ACTION_RETURN, /* handled */ MOD_ACTION_RETURN, /* invalid */ MOD_ACTION_RETURN, /* userlock */ MOD_ACTION_RETURN, /* notfound */ MOD_ACTION_RETURN, /* noop */ MOD_ACTION_RETURN /* updated */ }, /* append */ {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -