/* * Allow single attribute values to be retrieved from the dhcp. */ static ssize_t dhcp_options_xlat(UNUSED void *instance, REQUEST *request, char const *fmt, char **out, size_t freespace) { vp_cursor_t cursor, src_cursor; vp_tmpl_t src; VALUE_PAIR *vp, *head = NULL; int decoded = 0; ssize_t slen; while (isspace((int) *fmt)) fmt++; slen = tmpl_from_attr_str(&src, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false); if (slen <= 0) { REMARKER(fmt, slen, fr_strerror()); error: return -1; } if (src.type != TMPL_TYPE_ATTR) { REDEBUG("dhcp_options cannot operate on a %s", fr_int2str(tmpl_names, src.type, "<INVALID>")); goto error; } if (src.tmpl_da->type != PW_TYPE_OCTETS) { REDEBUG("dhcp_options got a %s attribute needed octets", fr_int2str(dict_attr_types, src.tmpl_da->type, "<INVALID>")); goto error; } for (vp = tmpl_cursor_init(NULL, &src_cursor, request, &src); vp; vp = tmpl_cursor_next(&src_cursor, &src)) { /* * @fixme: we should pass in a cursor, then decoding multiple * source attributes can be made atomic. */ if ((fr_dhcp_decode_options(request->packet, &head, vp->vp_octets, vp->vp_length) < 0) || (!head)) { RWDEBUG("DHCP option decoding failed: %s", fr_strerror()); goto error; } for (vp = fr_cursor_init(&cursor, &head); vp; vp = fr_cursor_next(&cursor)) { rdebug_pair(L_DBG_LVL_2, request, vp, "dhcp_options: "); decoded++; } fr_pair_list_move(request->packet, &(request->packet->vps), &head); /* Free any unmoved pairs */ fr_pair_list_free(&head); } snprintf(*out, freespace, "%i", decoded); return strlen(*out); }
/* * Common code called by everything below. */ static rlm_rcode_t file_common(rlm_files_t const *inst, REQUEST *request, char const *filename, rbtree_t *tree, RADIUS_PACKET *request_packet, RADIUS_PACKET *reply_packet) { char const *name; VALUE_PAIR *check_tmp = NULL; VALUE_PAIR *reply_tmp = NULL; PAIR_LIST const *user_pl, *default_pl; bool found = false; 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 = xlat_eval(buffer, sizeof(buffer), request, inst->key, NULL, NULL); if (len < 0) { return RLM_MODULE_FAIL; } name = len ? buffer : "NONE"; } if (!tree) return RLM_MODULE_NOOP; my_pl.name = name; user_pl = rbtree_finddata(tree, &my_pl); my_pl.name = "DEFAULT"; default_pl = rbtree_finddata(tree, &my_pl); /* * Find the entry for the user. */ while (user_pl || default_pl) { fr_cursor_t cursor; VALUE_PAIR *vp; PAIR_LIST const *pl; /* * Figure out which entry to match on. */ if (!default_pl && user_pl) { pl = user_pl; user_pl = user_pl->next; } else if (!user_pl && default_pl) { pl = default_pl; default_pl = default_pl->next; } else if (user_pl->order < default_pl->order) { pl = user_pl; user_pl = user_pl->next; } else { pl = default_pl; default_pl = default_pl->next; } MEM(fr_pair_list_copy(request, &check_tmp, pl->check) >= 0); for (vp = fr_cursor_init(&cursor, &check_tmp); vp; vp = fr_cursor_next(&cursor)) { if (xlat_eval_pair(request, vp) < 0) { RWARN("Failed parsing expanded value for check item, skipping entry: %s", fr_strerror()); fr_pair_list_free(&check_tmp); continue; } } if (paircmp(request, request_packet->vps, check_tmp, &reply_packet->vps) == 0) { RDEBUG2("Found match \"%s\" one line %d of %s", pl->name, pl->lineno, filename); found = true; /* ctx may be reply or proxy */ MEM(fr_pair_list_copy(reply_packet, &reply_tmp, pl->reply) >= 0); radius_pairmove(request, &reply_packet->vps, reply_tmp, true); fr_pair_list_move(&request->control, &check_tmp); reply_tmp = NULL; /* radius_pairmove() frees input attributes */ fr_pair_list_free(&check_tmp); /* * Fallthrough? */ if (!fall_through(pl->reply)) break; } } /* * Remove server internal parameters. */ fr_pair_delete_by_da(&reply_packet->vps, attr_fall_through); /* * See if we succeeded. */ if (!found) return RLM_MODULE_NOOP; /* on to the next module */ return RLM_MODULE_OK; }