/* * First, look for Exec-Program && Exec-Program-Wait. * * Then, call exec_dispatch. */ static rlm_rcode_t 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, TAG_ANY); if (vp) { exec_wait = 0; } else if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT, 0, TAG_ANY)) != 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) { RDEBUG2("%s", module_failure_msg(request, "rlm_exec (%s): " "Login incorrect (external " "check failed)", inst->xlat_name)); 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("%s", module_failure_msg(request, "rlm_exec (%s): " "Login incorrect (external " "check said so)", inst->xlat_name)); return RLM_MODULE_REJECT; } return RLM_MODULE_OK; }
/** Process the exit code returned by one of the exec functions * * @param request Current request. * @param answer Output string from exec call. * @param len length of data in answer. * @param status code returned by exec call. * @return One of the RLM_MODULE_* values. */ static rlm_rcode_t rlm_exec_status2rcode(REQUEST *request, char *answer, size_t len, int status) { if (status < 0) { return RLM_MODULE_FAIL; } /* * Exec'd programs are meant to return exit statuses that correspond * to the standard RLM_MODULE_* + 1. * * This frees up 0, for success where it'd normally be reject. */ if (status == 0) { RDEBUG("Program executed successfully"); return RLM_MODULE_OK; } if (status > RLM_MODULE_NUMCODES) { REDEBUG("Program returned invalid code (greater than max rcode) (%i > %i): %s", status, RLM_MODULE_NUMCODES, answer); goto fail; return RLM_MODULE_FAIL; } status--; /* Lets hope no one ever re-enumerates RLM_MODULE_* */ if (status == RLM_MODULE_FAIL) { fail: if (len > 0) { char *p = &answer[len - 1]; /* * Trim off trailing returns */ while((p > answer) && ((*p == '\r') || (*p == '\n'))) { *p-- = '\0'; } module_failure_msg(request, "%s", answer); } return RLM_MODULE_FAIL; } return status; }
/* * Dispatch an exec method */ static rlm_rcode_t exec_dispatch(void *instance, REQUEST *request) { rlm_exec_t *inst = (rlm_exec_t *) instance; int result; VALUE_PAIR **input_pairs, **output_pairs; VALUE_PAIR *answer = NULL; char msg[1024]; size_t len; /* * We need a program to execute. */ if (!inst->program) { radlog(L_ERR, "rlm_exec (%s): We require a program to execute", inst->xlat_name); return RLM_MODULE_FAIL; } /* * 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; } /* * It points to the attribute list, but the attribute * list is empty. */ 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. * * FIXME: if inst->program starts with %{, then * do an xlat ourselves. This will allow us to do * program = %{Exec-Program}, which this module * xlat's into it's string value, and then the * exec program function xlat's it's string value * into something else. */ result = radius_exec_program(inst->program, request, inst->wait, msg, sizeof(msg), *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; } /* * Move the answer over to the output pairs. * * If we're not waiting, then there are no output pairs. */ 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; } /* * Write any exec output to module failure message */ if (*msg) { /* Trim off returns and newlines */ len = strlen(msg); if (msg[len - 1] == '\n' || msg[len - 1] == '\r') { msg[len - 1] = '\0'; } module_failure_msg(request, "rlm_exec (%s): %s", inst->xlat_name, msg); } return result-1; }