X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Frlm_exec%2Frlm_exec.c;h=bf6252138377ba116b1513627b260ce4103e9af3;hb=9960563934a7da222528a1d82224aecc207c8aa8;hp=e100add7f5ceb8665503f2821341a9211712da1f;hpb=cbebc163d490ea8422ecadd9e2fde5450ed5a308;p=freeradius.git diff --git a/src/modules/rlm_exec/rlm_exec.c b/src/modules/rlm_exec/rlm_exec.c index e100add..bf62521 100644 --- a/src/modules/rlm_exec/rlm_exec.c +++ b/src/modules/rlm_exec/rlm_exec.c @@ -1,5 +1,5 @@ /* - * rlm_exe.c + * rlm_exec.c * * Version: $Id$ * @@ -15,34 +15,31 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * - * Copyright 2002 The FreeRADIUS server project + * Copyright 2002,2006 The FreeRADIUS server project * Copyright 2002 Alan DeKok */ -#include "autoconf.h" -#include "libradius.h" +#include +RCSID("$Id$") -#include -#include -#include - -#include "radiusd.h" -#include "modules.h" -#include "conffile.h" - -static const char rcsid[] = "$Id$"; +#include +#include /* * Define a structure for our module configuration. */ typedef struct rlm_exec_t { char *xlat_name; + int bare; int wait; char *program; char *input; char *output; + char *packet_type; + unsigned int packet_code; + int shell_escape; } rlm_exec_t; /* @@ -54,14 +51,17 @@ typedef struct rlm_exec_t { * to the strdup'd string into 'config.string'. This gets around * buffer over-flows. */ -static CONF_PARSER module_config[] = { +static const CONF_PARSER module_config[] = { { "wait", PW_TYPE_BOOLEAN, offsetof(rlm_exec_t,wait), NULL, "yes" }, { "program", PW_TYPE_STRING_PTR, offsetof(rlm_exec_t,program), NULL, NULL }, { "input_pairs", PW_TYPE_STRING_PTR, - offsetof(rlm_exec_t,input), NULL, NULL }, + offsetof(rlm_exec_t,input), NULL, "request" }, { "output_pairs", PW_TYPE_STRING_PTR, offsetof(rlm_exec_t,output), NULL, NULL }, + { "packet_type", PW_TYPE_STRING_PTR, + offsetof(rlm_exec_t,packet_type), NULL, NULL }, + { "shell_escape", PW_TYPE_BOOLEAN, offsetof(rlm_exec_t,shell_escape), NULL, "yes" }, { NULL, -1, 0, NULL, NULL } /* end the list */ }; @@ -88,6 +88,7 @@ static VALUE_PAIR **decode_string(REQUEST *request, const char *string) return &request->reply->vps; } +#ifdef WITH_PROXY if (strcmp(string, "proxy-request") == 0) { if (!request->proxy) return NULL; @@ -99,25 +100,31 @@ static VALUE_PAIR **decode_string(REQUEST *request, const char *string) return &request->proxy_reply->vps; } +#endif if (strcmp(string, "config") == 0) { return &request->config_items; } + if (strcmp(string, "none") == 0) { + return NULL; + } + return NULL; } /* * Do xlat of strings. - */ -static int exec_xlat(void *instance, REQUEST *request, - char *fmt, char *out, int outlen, - RADIUS_ESCAPE_STRING func) + */ +static size_t exec_xlat(void *instance, REQUEST *request, + char *fmt, char *out, size_t outlen, + UNUSED RADIUS_ESCAPE_STRING func) { int result; rlm_exec_t *inst = instance; VALUE_PAIR **input_pairs; + char *p; input_pairs = decode_string(request, inst->input); if (!input_pairs) { @@ -130,15 +137,19 @@ static int exec_xlat(void *instance, REQUEST *request, /* * FIXME: Do xlat of program name? */ - DEBUG2("rlm_exec (%s): Executing %s", inst->xlat_name, fmt); + RDEBUG2("Executing %s", fmt); result = radius_exec_program(fmt, request, inst->wait, - out, outlen, *input_pairs, NULL); - DEBUG2("rlm_exec (%s): result %d", inst->xlat_name, result); + out, outlen, *input_pairs, NULL, inst->shell_escape); + RDEBUG2("result %d", result); if (result != 0) { out[0] = '\0'; return 0; } + for (p = out; *p != '\0'; p++) { + if (*p < ' ') *p = ' '; + } + return strlen(out); } @@ -155,13 +166,6 @@ static int exec_detach(void *instance) free(inst->xlat_name); } - /* - * Free the strings. - */ - if (inst->program) free(inst->program); - if (inst->input) free(inst->input); - if (inst->output) free(inst->output); - free(inst); return 0; } @@ -180,15 +184,17 @@ static int exec_detach(void *instance) static int exec_instantiate(CONF_SECTION *conf, void **instance) { rlm_exec_t *inst; - char *xlat_name; - + const char *xlat_name; + /* * Set up a storage area for instance data */ - + inst = rad_malloc(sizeof(rlm_exec_t)); + if (!inst) + return -1; memset(inst, 0, sizeof(rlm_exec_t)); - + /* * If the configuration parameters can't be parsed, then * fail. @@ -198,7 +204,7 @@ static int exec_instantiate(CONF_SECTION *conf, void **instance) exec_detach(inst); return -1; } - + /* * No input pairs defined. Why are we executing a program? */ @@ -219,16 +225,35 @@ static int exec_instantiate(CONF_SECTION *conf, void **instance) return -1; } + /* + * Get the packet type on which to execute + */ + if (!inst->packet_type) { + inst->packet_code = 0; + } else { + DICT_VALUE *dval; + + dval = dict_valbyname(PW_PACKET_TYPE, 0, inst->packet_type); + if (!dval) { + radlog(L_ERR, "rlm_exec: Unknown packet type %s: See list of VALUEs for Packet-Type in share/dictionary", inst->packet_type); + exec_detach(inst); + return -1; + } + inst->packet_code = dval->value; + } + xlat_name = cf_section_name2(conf); - if (xlat_name == NULL) + if (xlat_name == NULL) { xlat_name = cf_section_name1(conf); - if (xlat_name){ + inst->bare = 1; + } + if (xlat_name){ inst->xlat_name = strdup(xlat_name); - xlat_register(xlat_name, exec_xlat, inst); - } + xlat_register(xlat_name, exec_xlat, inst); + } *instance = inst; - + return 0; } @@ -253,20 +278,43 @@ static int exec_dispatch(void *instance, REQUEST *request) } /* + * See if we're supposed to execute it now. + */ + if (!((inst->packet_code == 0) || + (request->packet->code == inst->packet_code) || + (request->reply->code == inst->packet_code) +#ifdef WITH_PROXY + || (request->proxy && + (request->proxy->code == inst->packet_code)) || + (request->proxy_reply && + (request->proxy_reply->code == inst->packet_code)) +#endif + )) { + RDEBUG2("Packet type is not %s. Not executing.", + inst->packet_type); + return RLM_MODULE_NOOP; + } + + /* * Decide what input/output the program takes. */ input_pairs = decode_string(request, inst->input); output_pairs = decode_string(request, inst->output); + if (!input_pairs) { + RDEBUG2("WARNING: Possible parse error in %s", + inst->input); + return RLM_MODULE_NOOP; + } + /* - * We need a place to store the returned VP's + * It points to the attribute list, but the attribute + * list is empty. */ - if (!output_pairs) { - radlog(L_ERR, "rlm_exec (%s): Nowhere to place output", - inst->xlat_name); - return RLM_MODULE_FAIL; + if (!*input_pairs) { + RDEBUG2("WARNING! Input pairs are empty. No attributes will be passed to the script"); } - + /* * This function does it's own xlat of the input program * to execute. @@ -280,8 +328,8 @@ static int exec_dispatch(void *instance, REQUEST *request) */ result = radius_exec_program(inst->program, request, inst->wait, NULL, 0, - *input_pairs, &answer); - if (result != 0) { + *input_pairs, &answer, inst->shell_escape); + if (result < 0) { radlog(L_ERR, "rlm_exec (%s): External script failed", inst->xlat_name); return RLM_MODULE_FAIL; @@ -289,14 +337,122 @@ static int exec_dispatch(void *instance, REQUEST *request) /* * Move the answer over to the output pairs. + * + * If we're not waiting, then there are no output pairs. */ - pairmove(output_pairs, &answer); + if (output_pairs) pairmove(output_pairs, &answer); pairfree(&answer); + if (result == 0) { + return RLM_MODULE_OK; + } + if (result > RLM_MODULE_NUMCODES) { + return RLM_MODULE_FAIL; + } + return result-1; +} + + +/* + * First, look for Exec-Program && Exec-Program-Wait. + * + * Then, call exec_dispatch. + */ +static int exec_postauth(void *instance, REQUEST *request) +{ + int result; + int exec_wait = 0; + VALUE_PAIR *vp, *tmp; + rlm_exec_t *inst = (rlm_exec_t *) instance; + + vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM, 0); + if (vp) { + exec_wait = 0; + + } else if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT, 0)) != NULL) { + exec_wait = 1; + } + if (!vp) { + if (!inst->program) return RLM_MODULE_NOOP; + + return exec_dispatch(instance, request); + } + + tmp = NULL; + result = radius_exec_program(vp->vp_strvalue, request, exec_wait, + NULL, 0, request->packet->vps, &tmp, + inst->shell_escape); + + /* + * Always add the value-pairs to the reply. + */ + pairmove(&request->reply->vps, &tmp); + pairfree(&tmp); + + if (result < 0) { + /* + * Error. radius_exec_program() returns -1 on + * fork/exec errors. + */ + tmp = pairmake("Reply-Message", "Access denied (external check failed)", T_OP_SET); + pairadd(&request->reply->vps, tmp); + + RDEBUG2("Login incorrect (external check failed)"); + + request->reply->code = PW_AUTHENTICATION_REJECT; + return RLM_MODULE_REJECT; + } + if (result > 0) { + /* + * Reject. radius_exec_program() returns >0 + * if the exec'ed program had a non-zero + * exit status. + */ + request->reply->code = PW_AUTHENTICATION_REJECT; + RDEBUG2("Login incorrect (external check said so)"); + return RLM_MODULE_REJECT; + } + return RLM_MODULE_OK; } +/* + * First, look for Exec-Program && Exec-Program-Wait. + * + * Then, call exec_dispatch. + */ +static int exec_accounting(void *instance, REQUEST *request) +{ + int result; + int exec_wait = 0; + VALUE_PAIR *vp; + rlm_exec_t *inst = (rlm_exec_t *) instance; + + /* + * The "bare" exec module takes care of handling + * Exec-Program and Exec-Program-Wait. + */ + if (!inst->bare) return exec_dispatch(instance, request); + + vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM, 0); + if (vp) { + exec_wait = 0; + + } else if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT, 0)) != NULL) { + exec_wait = 1; + } + if (!vp) return RLM_MODULE_NOOP; + + result = radius_exec_program(vp->vp_strvalue, request, exec_wait, + NULL, 0, request->packet->vps, NULL, + inst->shell_escape); + if (result != 0) { + return RLM_MODULE_REJECT; + } + + return RLM_MODULE_OK; +} /* * The module name should be the only globally exported symbol. @@ -308,20 +464,23 @@ static int exec_dispatch(void *instance, REQUEST *request) * is single-threaded. */ module_t rlm_exec = { + RLM_MODULE_INIT, "exec", /* Name */ - RLM_TYPE_THREAD_SAFE, /* type */ - NULL, /* initialization */ + RLM_TYPE_CHECK_CONFIG_SAFE, /* type */ exec_instantiate, /* instantiation */ + exec_detach, /* detach */ { exec_dispatch, /* authentication */ exec_dispatch, /* authorization */ exec_dispatch, /* pre-accounting */ - exec_dispatch, /* accounting */ + exec_accounting, /* accounting */ NULL, /* check simul */ exec_dispatch, /* pre-proxy */ exec_dispatch, /* post-proxy */ - exec_dispatch /* post-auth */ + exec_postauth /* post-auth */ +#ifdef WITH_COA + , exec_dispatch, + exec_dispatch +#endif }, - exec_detach, /* detach */ - NULL, /* destroy */ };