/* * Merge a cached entry into a REQUEST. */ static void cache_merge(rlm_cache_t *inst, REQUEST *request, rlm_cache_entry_t *c) { VALUE_PAIR *vp; rad_assert(request != NULL); rad_assert(c != NULL); if (c->control) { vp = paircopy(c->control); pairmove(&request->config_items, &vp); pairfree(&vp); } if (c->request && request->packet) { vp = paircopy(c->request); pairmove(&request->packet->vps, &vp); pairfree(&vp); } if (c->reply && request->reply) { vp = paircopy(c->reply); pairmove(&request->reply->vps, &vp); pairfree(&vp); } if (inst->stats) { vp = paircreate(PW_CACHE_ENTRY_HITS, 0, PW_TYPE_INTEGER); rad_assert(vp != NULL); vp->vp_integer = c->hits; pairadd(&request->packet->vps, vp); } }
/* * Merge a cached entry into a REQUEST. */ static void cache_merge(rlm_cache_t *inst, REQUEST *request, rlm_cache_entry_t *c) { VALUE_PAIR *vp; rad_assert(request != NULL); rad_assert(c != NULL); vp = pairfind(request->config_items, inst->cache_merge->attr, inst->cache_merge->vendor, TAG_ANY); if (vp && (vp->vp_integer == 0)) { RDEBUG2("Told not to merge entry into request"); return; } if (c->control) { RDEBUG2("Merging cached control list:"); rdebug_pair_list(2, request, c->control); vp = paircopy(c->control); pairmove(&request->config_items, &vp); pairfree(&vp); } if (c->request && request->packet) { RDEBUG2("Merging cached request list:"); rdebug_pair_list(2, request, c->request); vp = paircopy(c->request); pairmove(&request->packet->vps, &vp); pairfree(&vp); } if (c->reply && request->reply) { RDEBUG2("Merging cached reply list:"); rdebug_pair_list(2, request, c->reply); vp = paircopy(c->reply); pairmove(&request->reply->vps, &vp); pairfree(&vp); } if (inst->stats) { vp = pairalloc(inst->cache_entry_hits); rad_assert(vp != NULL); vp->vp_integer = c->hits; pairadd(&request->packet->vps, vp); } }
/* * Set the SQL user name. * * We don't call the escape function here. The resulting string * will be escaped later in the queries xlat so we don't need to * escape it twice. (it will make things wrong if we have an * escape candidate character in the username) */ int sql_set_user(rlm_sql_t *inst, REQUEST *request, char const *username) { char *expanded = NULL; VALUE_PAIR *vp = NULL; char const *sqluser; ssize_t len; if (username != NULL) { sqluser = username; } else if (inst->config->query_user[0] != '\0') { sqluser = inst->config->query_user; } else { return 0; } len = radius_axlat(&expanded, request, sqluser, NULL, NULL); if (len < 0) { return -1; } vp = pairalloc(request->packet, inst->sql_user); if (!vp) { talloc_free(expanded); return -1; } pairstrsteal(vp, expanded); RDEBUG2("SQL-User-Name set to '%s'", vp->vp_strvalue); vp->op = T_OP_SET; pairmove(request, &request->packet->vps, &vp); /* needs to be pair move else op is not respected */ return 0; }
/* * 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 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; }
/* * First, look for Exec-Program && Exec-Program-Wait. * * Then, call exec_dispatch. */ static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request) { rlm_exec_t *inst = (rlm_exec_t *) instance; rlm_rcode_t rcode; int status; char out[1024]; bool we_wait = false; VALUE_PAIR *vp, *tmp; vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM, 0, TAG_ANY); if (vp) { we_wait = false; } else if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT, 0, TAG_ANY)) != NULL) { we_wait = true; } if (!vp) { if (!inst->program) { return RLM_MODULE_NOOP; } rcode = exec_dispatch(instance, request); goto finish; } tmp = NULL; status = radius_exec_program(request, vp->vp_strvalue, we_wait, inst->shell_escape, out, sizeof(out), inst->timeout, request->packet->vps, &tmp); rcode = rlm_exec_status2rcode(request, out, strlen(out), status); /* * Always add the value-pairs to the reply. */ pairmove(request->reply, &request->reply->vps, &tmp); pairfree(&tmp); finish: switch (rcode) { case RLM_MODULE_FAIL: case RLM_MODULE_INVALID: case RLM_MODULE_REJECT: request->reply->code = PW_CODE_AUTHENTICATION_REJECT; break; default: break; } return rcode; }
/** Convert a valuepair string to VALUE_PAIR and insert it into a list * * Takes a valuepair string with list and request qualifiers, converts it into a VALUE_PAIR * and inserts it into the appropriate list. * * @param request Current request. * @param raw string to parse. * @param request_def to use if attribute isn't qualified. * @param list_def to use if attribute isn't qualified. * @return 0 on success, -1 on error. */ int radius_str2vp(REQUEST *request, char const *raw, request_refs_t request_def, pair_lists_t list_def) { char const *p; size_t len; request_refs_t req; pair_lists_t list; VALUE_PAIR *vp = NULL; VALUE_PAIR **vps; p = raw; req = radius_request_name(&p, request_def); len = p - raw; if (req == REQUEST_UNKNOWN) { REDEBUG("Invalid request qualifier \"%.*s\"", (int) len, raw); return -1; } raw += len; list = radius_list_name(&p, list_def); if (list == PAIR_LIST_UNKNOWN) { len = p - raw; REDEBUG("Invalid list qualifier \"%.*s\"", (int) len, raw); return -1; } raw += len; if (radius_request(&request, req) < 0) { return -1; } vps = radius_list(request, list); if (!vps) { return -1; } if (userparse(request, raw, &vp) == T_OP_INVALID) { return -1; } pairmove(request, vps, &vp); return 0; }
/* * Allow single attribute values to be retrieved from the dhcp. */ static size_t dhcp_options_xlat(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace) { vp_cursor_t cursor; VALUE_PAIR *vp, *head = NULL; int decoded = 0; while (isspace((int) *fmt)) fmt++; if ((radius_get_vp(request, fmt, &vp) < 0) || !vp) { *out = '\0'; return 0; } if ((fr_dhcp_decode_options(request->packet, vp->vp_octets, vp->length, &head) < 0) || (!head)) { RWDEBUG("DHCP option decoding failed"); goto fail; } for (vp = paircursor(&cursor, &head); vp; vp = pairnext(&cursor)) { decoded++; } pairmove(request->packet, &(request->packet->vps), &head); /* Free any unmoved pairs */ pairfree(&head); fail: snprintf(out, freespace, "%i", decoded); return strlen(out); }
static int remotedb_answer_builder(REQUEST *request, const char *password, const char *vlan) { VALUE_PAIR *pair; radlog(L_DBG, "Building answer : password = %s, vlan = %s\n", password, vlan); pair = pairmake("NT-Password", password, T_OP_SET); pairmove(&request->config_items, &pair); pairfree(&pair); pair = pairmake("Tunnel-Private-Group-Id", vlan, T_OP_SET); pairadd(&request->reply->vps, pair); pair = pairmake("Tunnel-Medium-Type", "6", T_OP_SET); pairadd(&request->reply->vps, pair); pair = pairmake("Tunnel-Type", "13", T_OP_SET); pairadd(&request->reply->vps, pair); return RLM_MODULE_OK; }
/* * Allow single attribute values to be retrieved from the dhcp. */ static size_t dhcp_options_xlat(UNUSED void *instance, REQUEST *request, const char *fmt, char *out, size_t freespace) { VALUE_PAIR *vp, *head = NULL, *next; int decoded = 0; while (isspace((int) *fmt)) fmt++; if ((radius_get_vp(request, fmt, &vp) < 0) || !vp) { *out = '\0'; return 0; } if ((fr_dhcp_decode_options(vp->vp_octets, vp->length, &head) < 0) || (head == NULL)) { RDEBUG("WARNING: DHCP option decoding failed"); goto fail; } next = head; do { next = next->next; decoded++; } while (next); pairmove(&(request->packet->vps), &head); /* Free any unmoved pairs */ pairfree(&head); fail: snprintf(out, freespace, "%i", decoded); return strlen(out); }
static int mongo_authorize(void *instance, REQUEST *request) { if (request->username == NULL) return RLM_MODULE_NOOP; rlm_mongo_t *data = (rlm_mongo_t *) instance; char password[MONGO_STRING_LENGTH] = ""; char mac[MONGO_STRING_LENGTH] = ""; if (strcmp(data->mac_field, "") != 0) { char mac_temp[MONGO_STRING_LENGTH] = ""; radius_xlat(mac_temp, MONGO_STRING_LENGTH, "%{Calling-Station-Id}", request, NULL); format_mac(mac_temp, mac); } if (!find_radius_options(data, request->username->vp_strvalue, mac, password)) { return RLM_MODULE_REJECT; } RDEBUG("Authorisation request by username -> \"%s\"\n", request->username->vp_strvalue); RDEBUG("Password found in MongoDB -> \"%s\"\n\n", password); VALUE_PAIR *vp; /* quiet the compiler */ instance = instance; request = request; vp = pairmake("Cleartext-Password", password, T_OP_SET); if (!vp) return RLM_MODULE_FAIL; pairmove(&request->config_items, &vp); pairfree(&vp); return RLM_MODULE_OK; }
/* * Dispatch an exec method */ static int exec_dispatch(void *instance, REQUEST *request) { int result; VALUE_PAIR **input_pairs, **output_pairs; VALUE_PAIR *answer = NULL; rlm_exec_t *inst = (rlm_exec_t *) instance; /* * 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, NULL, 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; } /* * 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; } return result-1; }
/* * Dispatch an exec method */ static rlm_rcode_t exec_dispatch(void *instance, REQUEST *request) { rlm_exec_t *inst = (rlm_exec_t *)instance; rlm_rcode_t rcode; int status; VALUE_PAIR **input_pairs = NULL, **output_pairs = NULL; VALUE_PAIR *answer = NULL; char out[1024]; /* * We need a program to execute. */ if (!inst->program) { ERROR("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. */ if (inst->input) { input_pairs = radius_list(request, inst->input_list); if (!input_pairs) { return RLM_MODULE_INVALID; } } if (inst->output) { output_pairs = radius_list(request, inst->output_list); if (!output_pairs) { return RLM_MODULE_INVALID; } } /* * This function does it's own xlat of the input program * to execute. */ status = radius_exec_program(request, inst->program, inst->wait, inst->shell_escape, out, sizeof(out), inst->timeout, inst->input ? *input_pairs : NULL, inst->output ? &answer : NULL); rcode = rlm_exec_status2rcode(request, out, strlen(out), status); /* * Move the answer over to the output pairs. * * If we're not waiting, then there are no output pairs. */ if (inst->output) { pairmove(request, output_pairs, &answer); } pairfree(&answer); return rcode; }
/* * Call the function_name inside the module * Store all vps in hashes %RAD_CHECK %RAD_REPLY %RAD_REQUEST * */ static int rlmperl_call(void *instance, REQUEST *request, char *function_name) { PERL_INST *inst = instance; VALUE_PAIR *vp; int exitstatus=0, count; STRLEN n_a; HV *rad_reply_hv; HV *rad_check_hv; HV *rad_request_hv; HV *rad_request_proxy_hv; HV *rad_request_proxy_reply_hv; #ifdef USE_ITHREADS POOL_HANDLE *handle; if ((handle = pool_pop(instance)) == NULL) { return RLM_MODULE_FAIL; } radlog(L_DBG,"found interpetator at address 0x%lx",(unsigned long) handle->clone); { dTHXa(handle->clone); PERL_SET_CONTEXT(handle->clone); } #else PERL_SET_CONTEXT(inst->perl); radlog(L_DBG,"Using perl at 0x%lx",(unsigned long) inst->perl); #endif { dSP; ENTER; SAVETMPS; /* * Radius has told us to call this function, but none * is defined. */ if (!function_name) { return RLM_MODULE_FAIL; } rad_reply_hv = get_hv("RAD_REPLY",1); rad_check_hv = get_hv("RAD_CHECK",1); rad_request_hv = get_hv("RAD_REQUEST",1); rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1); rad_request_proxy_reply_hv = get_hv("RAD_REQUEST_PROXY_REPLY",1); perl_store_vps(request->reply->vps, rad_reply_hv); perl_store_vps(request->config_items, rad_check_hv); perl_store_vps(request->packet->vps, rad_request_hv); if (request->proxy != NULL) { perl_store_vps(request->proxy->vps, rad_request_proxy_hv); } else { hv_undef(rad_request_proxy_hv); } if (request->proxy_reply !=NULL) { perl_store_vps(request->proxy_reply->vps, rad_request_proxy_reply_hv); } else { hv_undef(rad_request_proxy_reply_hv); } vp = NULL; PUSHMARK(SP); /* * This way %RAD_xx can be pushed onto stack as sub parameters. * XPUSHs( newRV_noinc((SV *)rad_request_hv) ); * XPUSHs( newRV_noinc((SV *)rad_reply_hv) ); * XPUSHs( newRV_noinc((SV *)rad_check_hv) ); * PUTBACK; */ count = call_pv(function_name, G_SCALAR | G_EVAL | G_NOARGS); SPAGAIN; if (SvTRUE(ERRSV)) { radlog(L_ERR, "rlm_perl: perl_embed:: module = %s , func = %s exit status= %s\n", inst->module, function_name, SvPV(ERRSV,n_a)); POPs; } if (count == 1) { exitstatus = POPi; if (exitstatus >= 100 || exitstatus < 0) { exitstatus = RLM_MODULE_FAIL; } } PUTBACK; FREETMPS; LEAVE; if ((get_hv_content(rad_reply_hv, &vp)) > 0 ) { pairmove(&request->reply->vps, &vp); pairfree(&vp); } if ((get_hv_content(rad_check_hv, &vp)) > 0 ) { pairmove(&request->config_items, &vp); pairfree(&vp); } if ((get_hv_content(rad_request_proxy_reply_hv, &vp)) > 0 && request->proxy_reply != NULL) { pairfree(&request->proxy_reply->vps); pairmove(&request->proxy_reply->vps, &vp); pairfree(&vp); } } #ifdef USE_ITHREADS pool_release(handle,instance); radlog(L_DBG,"Unreserve perl at address 0x%lx", (unsigned long) handle->clone); #endif return exitstatus; }
/* * Evaluate a 'packet .= {attrs}' statement */ static int evaluate_attr_list(policy_state_t *state, const policy_item_t *item) { const policy_attributes_t *this; VALUE_PAIR **vps = NULL; VALUE_PAIR *vp, *head, **tail; const policy_item_t *attr; policy_lex_t this_how; this = (const policy_attributes_t *) item; switch (this->where) { case POLICY_RESERVED_CONTROL: vps = &(state->request->config_items); break; case POLICY_RESERVED_REQUEST: vps = &(state->request->packet->vps); break; case POLICY_RESERVED_REPLY: vps = &(state->request->reply->vps); break; #ifdef WITH_PROXY case POLICY_RESERVED_PROXY_REQUEST: if (!state->request->proxy) return 0; /* FIXME: print error */ vps = &(state->request->proxy->vps); break; case POLICY_RESERVED_PROXY_REPLY: if (!state->request->proxy_reply) return 0; /* FIXME: print error */ vps = &(state->request->proxy_reply->vps); break; #endif default: return 0; } head = NULL; tail = &head; for (attr = this->attributes; attr != NULL; attr = attr->next) { if (attr->type != POLICY_TYPE_ASSIGNMENT) { fprintf(stderr, "bad assignment in attribute list at line %d\n", attr->lineno); pairfree(&head); return 0; } vp = assign2vp(state->request, (const policy_assignment_t *) attr); if (!vp) { fprintf(stderr, "Failed to allocate VP\n"); pairfree(&head); return 0; } *tail = vp; tail = &(vp->next); } this_how = this->how; retry_how: switch (this_how) { case POLICY_LEX_SET_EQUALS: /* dangerous: removes all previous things! */ pairfree(vps); *vps = head; break; case POLICY_LEX_AFTER_TAIL_ASSIGN: pairmove(vps, &head); pairfree(&head); break; case POLICY_LEX_ASSIGN: /* 'union' */ pairmove(vps, &head); pairfree(&head); break; case POLICY_LEX_BEFORE_HEAD_ASSIGN: pairmove(&head, vps); pairfree(vps); *vps = head; break; case POLICY_LEX_AFTER_TAIL_EQUALS: case POLICY_LEX_CONCAT_EQUALS: pairadd(vps, head); break; case POLICY_LEX_BEFORE_HEAD_EQUALS: pairadd(&head, *vps); *vps = head; break; case POLICY_LEX_BEFORE_WHERE_EQUALS: case POLICY_LEX_AFTER_WHERE_EQUALS: case POLICY_LEX_BEFORE_WHERE_ASSIGN: case POLICY_LEX_AFTER_WHERE_ASSIGN: /* find location*/ { VALUE_PAIR *vpprev = NULL, *vpnext = NULL, *lvp; for(lvp = *vps; lvp; vpprev = lvp, lvp = lvp->next) { vpnext = lvp->next; lvp->next = NULL; if (evaluate_condition(state, this->where_loc)) break; lvp->next = vpnext; } if (lvp) { switch(this_how) { case POLICY_LEX_BEFORE_WHERE_EQUALS: case POLICY_LEX_BEFORE_WHERE_ASSIGN: if (vpprev) { lvp->next = vpnext; vpnext = lvp; vpprev->next = NULL; lvp = vpprev; } default: /* always reached */ break; } switch(this_how) { case POLICY_LEX_BEFORE_WHERE_EQUALS: if (vpprev) pairadd(&lvp, head); else *vps = lvp = head; break; case POLICY_LEX_AFTER_WHERE_EQUALS: pairadd(&lvp, head); break; case POLICY_LEX_BEFORE_WHERE_ASSIGN: if (vpprev) { pairmove(&lvp, &head); pairfree(&head); } else *vps = lvp = head; break; case POLICY_LEX_AFTER_WHERE_ASSIGN: pairmove(&lvp, &head); pairfree(&head); break; default:/*never reached*/ break; } for( ; lvp && lvp->next; lvp = lvp->next); if (lvp) lvp->next = vpnext; break; } switch(this_how) { case POLICY_LEX_BEFORE_WHERE_EQUALS: this_how = POLICY_LEX_BEFORE_HEAD_EQUALS; break; case POLICY_LEX_AFTER_WHERE_EQUALS: this_how = POLICY_LEX_AFTER_TAIL_EQUALS; break; case POLICY_LEX_BEFORE_WHERE_ASSIGN: this_how = POLICY_LEX_BEFORE_HEAD_ASSIGN; break; case POLICY_LEX_AFTER_WHERE_ASSIGN: this_how = POLICY_LEX_AFTER_TAIL_ASSIGN; break; default: /*never reached*/ break; } goto retry_how; } /* FALL-THROUGH */ default: fprintf(stderr, "HUH?\n"); pairfree(&head); return 0; } state->rcode = RLM_MODULE_UPDATED; /* we did stuff */ return 1; }
/* * Common code called by everything below. */ static rlm_rcode_t file_common(rlm_files_t *inst, REQUEST *request, char const *filename, fr_hash_table_t *ht, VALUE_PAIR *request_pairs, VALUE_PAIR **reply_pairs) { char const *name, *match; VALUE_PAIR *check_tmp; VALUE_PAIR *reply_tmp; const PAIR_LIST *user_pl, *default_pl; int found = 0; PAIR_LIST my_pl; char buffer[256]; if (!inst->key) { VALUE_PAIR *namepair; namepair = request->username; name = namepair ? namepair->vp_strvalue : "NONE"; } else { int len; len = radius_xlat(buffer, sizeof(buffer), request, inst->key, NULL, NULL); if (len < 0) { return RLM_MODULE_FAIL; } name = len ? buffer : "NONE"; } if (!ht) return RLM_MODULE_NOOP; my_pl.name = name; user_pl = fr_hash_table_finddata(ht, &my_pl); my_pl.name = "DEFAULT"; default_pl = fr_hash_table_finddata(ht, &my_pl); /* * Find the entry for the user. */ while (user_pl || default_pl) { const PAIR_LIST *pl; if (!default_pl && user_pl) { pl = user_pl; match = name; user_pl = user_pl->next; } else if (!user_pl && default_pl) { pl = default_pl; match = "DEFAULT"; default_pl = default_pl->next; } else if (user_pl->order < default_pl->order) { pl = user_pl; match = name; user_pl = user_pl->next; } else { pl = default_pl; match = "DEFAULT"; default_pl = default_pl->next; } if (paircompare(request, request_pairs, pl->check, reply_pairs) == 0) { RDEBUG2("%s: Matched entry %s at line %d", filename, match, pl->lineno); found = 1; check_tmp = paircopy(request, pl->check); /* ctx may be reply or proxy */ reply_tmp = paircopy(request, pl->reply); radius_xlat_move(request, reply_pairs, &reply_tmp); pairmove(request, &request->config_items, &check_tmp); pairfree(&reply_tmp); pairfree(&check_tmp); /* * Fallthrough? */ if (!fallthrough(pl->reply)) break; } } /* * Remove server internal parameters. */ pairdelete(reply_pairs, PW_FALL_THROUGH, 0, TAG_ANY); /* * See if we succeeded. */ if (!found) return RLM_MODULE_NOOP; /* on to the next module */ return RLM_MODULE_OK; }
/** Convert value_pair_map_t to VALUE_PAIR(s) and add them to a REQUEST. * * Takes a single value_pair_map_t, resolves request and list identifiers * to pointers in the current request, then attempts to retrieve module * specific value(s) using callback, and adds the resulting values to the * correct request/list. * * @param request The current request. * @param map specifying destination attribute and location and src identifier. * @param func to retrieve module specific values and convert them to * VALUE_PAIRS. * @param ctx to be passed to func. * @param src name to be used in debugging if different from map value. * @return -1 if the operation failed, -2 in the source attribute wasn't valid, 0 on success. */ int radius_map2request(REQUEST *request, value_pair_map_t const *map, UNUSED char const *src, radius_tmpl_getvalue_t func, void *ctx) { int rcode, num; VALUE_PAIR **list, *vp, *head = NULL; REQUEST *context; TALLOC_CTX *parent; vp_cursor_t cursor; /* * Sanity check inputs. We can have a list or attribute * as a destination. */ if ((map->dst->type != VPT_TYPE_LIST) && (map->dst->type != VPT_TYPE_ATTR)) { REDEBUG("Invalid mapping destination"); return -2; } context = request; if (radius_request(&context, map->dst->request) < 0) { REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name); return -2; } /* * If there's no CoA packet and we're updating it, * auto-allocate it. */ if (((map->dst->list == PAIR_LIST_COA) || (map->dst->list == PAIR_LIST_DM)) && !request->coa) { request_alloc_coa(context); if (map->dst->list == PAIR_LIST_COA) { context->coa->proxy->code = PW_CODE_COA_REQUEST; } else { context->coa->proxy->code = PW_CODE_DISCONNECT_REQUEST; } } list = radius_list(context, map->dst->list); if (!list) { REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name); return -2; } parent = radius_list_ctx(context, map->dst->list); /* * The callback should either return -1 to signify operations error, -2 when it can't find the * attribute or list being referenced, or 0 to signify success. * It may return "sucess", but still have no VPs to work with. */ rcode = func(&head, request, map, ctx); if (rcode < 0) { rad_assert(!head); return rcode; } if (!head) return 0; /* * Reparent the VP */ for (vp = fr_cursor_init(&cursor, &head); vp; vp = fr_cursor_next(&cursor)) { VERIFY_VP(vp); if (debug_flag) debug_map(request, map, vp); (void) talloc_steal(parent, vp); } /* * List to list copies. */ if (map->dst->type == VPT_TYPE_LIST) { switch (map->op) { case T_OP_CMP_FALSE: rad_assert(head == NULL); pairfree(list); if (map->dst->list == PAIR_LIST_REQUEST) { context->username = NULL; context->password = NULL; } break; case T_OP_SET: if (map->src->type == VPT_TYPE_LIST) { pairfree(list); *list = head; } else { case T_OP_EQ: rad_assert(map->src->type == VPT_TYPE_EXEC); pairmove(parent, list, &head); pairfree(&head); } if (map->dst->list == PAIR_LIST_REQUEST) { context->username = pairfind(head, PW_USER_NAME, 0, TAG_ANY); context->password = pairfind(head, PW_USER_PASSWORD, 0, TAG_ANY); } break; case T_OP_ADD: pairadd(list, head); break; default: pairfree(&head); return -1; } return 0; } /* * We now should have only one destination attribute, and * only one source attribute. */ rad_assert(head->next == NULL); /* * Find the destination attribute. We leave with either * the cursor and vp pointing to the attribute, or vp is * NULL. */ num = map->dst->num; for (vp = fr_cursor_init(&cursor, list); vp != NULL; vp = fr_cursor_next(&cursor)) { VERIFY_VP(vp); if ((vp->da == map->dst->da) && (!vp->da->flags.has_tag || (map->dst->tag == TAG_ANY) || (vp->tag == map->dst->tag))) { if (num == 0) break; num--; } } /* * Figure out what to do with the source attribute. */ switch (map->op) { case T_OP_CMP_FALSE: /* remove matching attributes */ pairfree(&head); if (!vp) return 0; /* * Wildcard: delete all of the matching ones, * based on tag. */ if (!map->dst->num) { pairdelete(list, map->dst->da->attr, map->dst->da->vendor, map->dst->tag); vp = NULL; } else { /* * We've found the Nth one. Delete it, and only * it. */ vp = fr_cursor_remove(&cursor); } /* * Check that the User-Name and User-Password * caches point to the correct attribute. */ fixup: if (map->dst->list == PAIR_LIST_REQUEST) { context->username = pairfind(*list, PW_USER_NAME, 0, TAG_ANY); context->password = pairfind(*list, PW_USER_PASSWORD, 0, TAG_ANY); } pairfree(&vp); return 0; case T_OP_EQ: /* set only if not already set */ if (vp) { pairfree(&head); return 0; } fr_cursor_insert(&cursor, head); goto fixup; case T_OP_SET: /* over-write if existing, or else add */ if (vp) vp = fr_cursor_remove(&cursor); fr_cursor_insert(&cursor, head); goto fixup; case T_OP_ADD: /* append no matter what */ vp = NULL; pairadd(list, head); goto fixup; case T_OP_SUB: /* delete if it matches */ head->op = T_OP_CMP_EQ; rcode = radius_compare_vps(NULL, head, vp); pairfree(&head); if (rcode == 0) { vp = fr_cursor_remove(&cursor); goto fixup; } return 0; default: /* filtering operators */ /* * If the VP doesn't exist, the filters will add * it with the given value. */ if (!vp) { fr_cursor_insert(&cursor, head); goto fixup; } break; } /* * The LHS exists. We need to limit it's value based on * the operator, and the value of the RHS. */ head->op = map->op; rcode = radius_compare_vps(NULL, head, vp); head->op = T_OP_SET; switch (map->op) { case T_OP_CMP_EQ: if (rcode == 0) { leave: pairfree(&head); break; } replace: vp = fr_cursor_remove(&cursor); fr_cursor_insert(&cursor, head); goto fixup; case T_OP_LE: if (rcode <= 0) goto leave; goto replace; case T_OP_GE: if (rcode >= 0) goto leave; goto replace; default: pairfree(&head); return -1; } return 0; }