/** Copy matching pairs * * Copy pairs of a matching attribute number, vendor number and tag from the * the input list to a new list, and returns the head of this list. * * @param[in] ctx for talloc * @param[in] from whence to copy VALUE_PAIRs. * @param[in] attr to match, if 0 input list will not be filtered by attr. * @param[in] vendor to match. * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs. * @return the head of the new VALUE_PAIR list or NULL on error. */ VALUE_PAIR *paircopy_by_num(TALLOC_CTX *ctx, VALUE_PAIR *from, unsigned int attr, unsigned int vendor, int8_t tag) { vp_cursor_t src, dst; VALUE_PAIR *out = NULL, *vp; fr_cursor_init(&dst, &out); for (vp = fr_cursor_init(&src, &from); vp; vp = fr_cursor_next(&src)) { VERIFY_VP(vp); if ((vp->da->attr != attr) || (vp->da->vendor != vendor)) { continue; } if (vp->da->flags.has_tag && !TAG_EQ(tag, vp->tag)) { continue; } vp = paircopyvp(ctx, vp); if (!vp) { pairfree(&out); return NULL; } fr_cursor_insert(&dst, vp); } return out; }
/** Uses paircmp to verify all VALUE_PAIRs in list match the filter defined by check * * @note will sort both filter and list in place. * * @param failed pointer to an array to write the pointers of the filter/list attributes that didn't match. * May be NULL. * @param filter attributes to check list against. * @param list attributes, probably a request or reply */ bool pairvalidate(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *list) { vp_cursor_t filter_cursor; vp_cursor_t list_cursor; VALUE_PAIR *check, *match; if (!filter && !list) { return true; } /* * This allows us to verify the sets of validate and reply are equal * i.e. we have a validate rule which matches every reply attribute. * * @todo this should be removed one we have sets and lists */ pairsort(&filter, attrtagcmp); pairsort(&list, attrtagcmp); check = fr_cursor_init(&filter_cursor, &filter); match = fr_cursor_init(&list_cursor, &list); while (match || check) { /* * Lists are of different lengths */ if (!match || !check) goto mismatch; /* * The lists are sorted, so if the first * attributes aren't of the same type, then we're * done. */ if (!ATTRIBUTE_EQ(check, match)) goto mismatch; /* * They're of the same type, but don't have the * same values. This is a problem. * * Note that the RFCs say that for attributes of * the same type, order is important. */ if (paircmp(check, match) != 1) goto mismatch; check = fr_cursor_next(&filter_cursor); match = fr_cursor_next(&list_cursor); } return true; mismatch: if (failed) { failed[0] = check; failed[1] = match; } return false; }
/** Check group membership attributes to see if a user is a member. * * @param[in] inst rlm_ldap configuration. * @param[in] request Current request. * @param[in] check vp containing the group value (name or dn). * * @return One of the RLM_MODULE_* values. */ rlm_rcode_t rlm_ldap_check_cached(ldap_instance_t const *inst, REQUEST *request, VALUE_PAIR *check) { VALUE_PAIR *vp; int ret; vp_cursor_t cursor; fr_cursor_init(&cursor, &request->config_items); /* * We return RLM_MODULE_INVALID here as an indication * the caller should try a dynamic group lookup instead. */ vp = fr_cursor_next_by_num(&cursor, inst->cache_da->attr, inst->cache_da->vendor, TAG_ANY); if (!vp) return RLM_MODULE_INVALID; fr_cursor_first(&cursor); while ((vp = fr_cursor_next_by_num(&cursor, inst->cache_da->attr, inst->cache_da->vendor, TAG_ANY))) { ret = paircmp_op(T_OP_CMP_EQ, vp, check); if (ret == 1) { RDEBUG2("User found. Matched cached membership"); return RLM_MODULE_OK; } if (ret < -1) { return RLM_MODULE_FAIL; } } RDEBUG2("Cached membership not found"); return RLM_MODULE_NOTFOUND; }
/** Add a child * * @param[in] parent to add child to. * @param[in] child to add. */ void _cf_item_add(CONF_ITEM *parent, CONF_ITEM *child) { fr_cursor_t to_merge; CONF_ITEM *ci; rad_assert(parent != child); if (!parent || !child) return; /* * New child, add child trees. */ if (!parent->ident1) parent->ident1 = rbtree_create(parent, _cf_ident1_cmp, NULL, RBTREE_FLAG_NONE); if (!parent->ident2) parent->ident2 = rbtree_create(parent, _cf_ident2_cmp, NULL, RBTREE_FLAG_NONE); fr_cursor_init(&to_merge, &child); for (ci = fr_cursor_head(&to_merge); ci; ci = fr_cursor_next(&to_merge)) { rbtree_insert(parent->ident1, ci); rbtree_insert(parent->ident2, ci); /* NULL ident2 is still a value */ fr_cursor_append(&parent->cursor, ci); /* Append to the list of children */ } }
/* * Don't even ask what this is doing... */ static void alvarion_vsa_hack(VALUE_PAIR *vp) { int number = 1; vp_cursor_t cursor; for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) { DICT_ATTR const *da; if (vp->da->vendor != 12394) { continue; } if (vp->da->type != PW_TYPE_STRING) { continue; } da = dict_attrbyvalue(number, 12394); if (!da) { continue; } vp->da = da; number++; } }
static ssize_t dhcp_xlat(UNUSED void *instance, REQUEST *request, char const *fmt, char **out, size_t freespace) { vp_cursor_t cursor; VALUE_PAIR *vp; uint8_t binbuf[255]; ssize_t len; while (isspace((int) *fmt)) fmt++; if ((radius_copy_vp(request, &vp, request, fmt) < 0) || !vp) return 0; fr_cursor_init(&cursor, &vp); len = fr_dhcp_encode_option(request, binbuf, sizeof(binbuf), &cursor); talloc_free(vp); if (len <= 0) { REDEBUG("DHCP option encoding failed: %s", fr_strerror()); return -1; } if ((size_t)((len * 2) + 1) > freespace) { REDEBUG("DHCP option encoding failed: Output buffer exhausted, needed %zd bytes, have %zd bytes", (len * 2) + 1, freespace); return -1; } return fr_bin2hex(*out, binbuf, len); }
static int arp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request) { int i; uint8_t const *p = request->packet->data, *end = p + request->packet->data_len; fr_cursor_t cursor; fr_cursor_init(&cursor, &request->packet->vps); for (i = 0; header_names[i].name != NULL; i++) { ssize_t ret; size_t len; fr_dict_attr_t const *da; VALUE_PAIR *vp = NULL; len = header_names[i].len; if (!fr_cond_assert((size_t)(end - p) < len)) return -1; /* Should have been detected in socket_recv */ da = fr_dict_attr_by_name(dict_arp, header_names[i].name); if (!da) return 0; MEM(vp = fr_pair_afrom_da(request->packet, da)); ret = fr_value_box_from_network(vp, &vp->data, da->type, da, p, len, true); if (ret <= 0) { fr_pair_to_unknown(vp); fr_pair_value_memcpy(vp, p, len); } DEBUG2("&%pP", vp); fr_cursor_insert(&cursor, vp); } return 0; }
/** Check group membership attributes to see if a user is a member. * * @param[in] inst rlm_ldap configuration. * @param[in] request Current request. * @param[in] check vp containing the group value (name or dn). * * @return One of the RLM_MODULE_* values. */ rlm_rcode_t rlm_ldap_check_cached(ldap_instance_t const *inst, REQUEST *request, VALUE_PAIR *check) { VALUE_PAIR *vp; int ret; vp_cursor_t cursor; fr_cursor_init(&cursor, &request->config_items); vp = fr_cursor_next_by_num(&cursor, inst->cache_da->attr, inst->cache_da->vendor, TAG_ANY); if (!vp) { return RLM_MODULE_INVALID; } for (; vp; vp = fr_cursor_next_by_num(&cursor, inst->cache_da->attr, inst->cache_da->vendor, TAG_ANY)) { ret = radius_compare_vps(request, check, vp); if (ret == 0) { RDEBUG2("User found. Matched cached membership"); return RLM_MODULE_OK; } if (ret < -1) { return RLM_MODULE_FAIL; } } RDEBUG2("Membership not found"); return RLM_MODULE_NOTFOUND; }
/** Print a list of valuepairs to the request list. * * @param[in] level Debug level (1-4). * @param[in] request to read logging params from. * @param[in] vp to print. */ void rdebug_pair_list(int level, REQUEST *request, VALUE_PAIR *vp) { vp_cursor_t cursor; char buffer[256]; if (!vp || !request || !request->log.func) return; if (!radlog_debug_enabled(L_DBG, level, request)) return; for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) { /* * Take this opportunity to verify all the VALUE_PAIRs are still valid. */ if (!talloc_get_type(vp, VALUE_PAIR)) { REDEBUG("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp)); fr_log_talloc_report(vp); rad_assert(0); } vp_prints(buffer, sizeof(buffer), vp); RDEBUGX(level, "\t%s", buffer); } }
static void print_packet(FILE *fp, RADIUS_PACKET *packet) { VALUE_PAIR *vp; vp_cursor_t cursor; if (!packet) { fprintf(fp, "\n"); return; } fprintf(fp, "%s\n", fr_packet_codes[packet->code]); for (vp = fr_cursor_init(&cursor, &packet->vps); vp; vp = fr_cursor_next(&cursor)) { /* * Take this opportunity to verify all the VALUE_PAIRs are still valid. */ if (!talloc_get_type(vp, VALUE_PAIR)) { ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp)); fr_log_talloc_report(vp); rad_assert(0); } vp_print(fp, vp); } fflush(fp); }
static int _map_proc_client_get_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx) { client_get_vp_ctx_t *client = uctx; VALUE_PAIR *head = NULL, *vp; fr_cursor_t cursor; fr_dict_attr_t const *da; CONF_PAIR const *cp; rad_assert(ctx != NULL); fr_cursor_init(&cursor, &head); /* * FIXME: allow multiple entries. */ if (map->lhs->type == TMPL_TYPE_ATTR) { da = map->lhs->tmpl_da; } else { char *attr; if (tmpl_aexpand(ctx, &attr, request, map->lhs, NULL, NULL) <= 0) { RWDEBUG("Failed expanding string"); return -1; } da = fr_dict_attr_by_name(request->dict, attr); if (!da) { RWDEBUG("No such attribute '%s'", attr); return -1; } talloc_free(attr); } for (cp = client->cp; cp; cp = cf_pair_find_next(client->cs, cp, client->field)) { char const *value = cf_pair_value(cp); MEM(vp = fr_pair_afrom_da(ctx, da)); if (fr_pair_value_from_str(vp, value, talloc_array_length(value) - 1, '\0', false) < 0) { RWDEBUG("Failed parsing value \"%pV\" for attribute %s: %s", fr_box_strvalue(value), map->lhs->tmpl_da->name, fr_strerror()); fr_pair_list_free(&head); talloc_free(vp); return -1; } vp->op = map->op; fr_cursor_append(&cursor, vp); if (map->op != T_OP_ADD) break; /* Create multiple attribute for multiple CONF_PAIRs */ } *out = head; return 0; }
/* * 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); }
/** Send a failure message * */ static int eap_sim_send_eap_failure_notification(eap_session_t *eap_session) { REQUEST *request = eap_session->request; RADIUS_PACKET *packet = eap_session->request->reply; fr_cursor_t cursor; VALUE_PAIR *vp; eap_sim_session_t *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t); fr_cursor_init(&cursor, &packet->vps); vp = fr_pair_find_by_da(packet->vps, attr_eap_sim_notification, TAG_ANY); if (!vp) { vp = fr_pair_afrom_da(packet, attr_eap_sim_notification); vp->vp_uint16 = FR_EAP_SIM_NOTIFICATION_VALUE_GENERAL_FAILURE; fr_cursor_append(&cursor, vp); } /* * Change the failure notification depending where * we are in the state machine. */ if (eap_sim_session->challenge_success) { vp->vp_uint16 &= ~0x4000; /* Unset phase bit */ } else { vp->vp_uint16 |= 0x4000; /* Set phase bit */ } vp->vp_uint16 &= ~0x8000; /* In both cases success bit should be low */ RDEBUG2("Sending SIM-Notification (%pV)", &vp->data); eap_session->this_round->request->code = FR_EAP_CODE_REQUEST; /* * Set the subtype to notification */ vp = fr_pair_afrom_da(packet, attr_eap_sim_subtype); vp->vp_uint16 = FR_EAP_SIM_SUBTYPE_VALUE_SIM_NOTIFICATION; fr_cursor_append(&cursor, vp); /* * If we're after the challenge phase * then we need to include a MAC to * protect notifications. */ if (eap_sim_session->challenge_success) { vp = fr_pair_afrom_da(packet, attr_eap_sim_mac); fr_pair_replace(&packet->vps, vp); } /* * Encode the packet */ if (eap_sim_compose(eap_session, NULL, 0) < 0) { fr_pair_list_free(&packet->vps); return -1; } return 0; }
/* * This hack strips out Cisco's VSA duplicities in lines * (Cisco not implemented VSA's in standard way. * * Cisco sends it's VSA attributes with the attribute name *again* * in the string, like: H323-Attribute = "h323-attribute=value". * This sort of behaviour is nonsense. */ static void cisco_vsa_hack(REQUEST *request) { int vendorcode; char *ptr; char newattr[MAX_STRING_LEN]; VALUE_PAIR *vp; vp_cursor_t cursor; for (vp = fr_cursor_init(&cursor, &request->packet->vps); vp; vp = fr_cursor_next(&cursor)) { vendorcode = vp->da->vendor; if (!((vendorcode == 9) || (vendorcode == 6618))) { continue; /* not a Cisco or Quintum VSA, continue */ } if (vp->da->type != PW_TYPE_STRING) { continue; } /* * No weird packing. Ignore it. */ ptr = strchr(vp->vp_strvalue, '='); /* find an '=' */ if (!ptr) { continue; } /* * Cisco-AVPair's get packed as: * * Cisco-AVPair = "h323-foo-bar = baz" * Cisco-AVPair = "h323-foo-bar=baz" * * which makes sense only if you're a lunatic. * This code looks for the attribute named inside * of the string, and if it exists, adds it as a new * attribute. */ if (vp->da->attr == 1) { char const *p; p = vp->vp_strvalue; gettoken(&p, newattr, sizeof(newattr), false); if (dict_attrbyname(newattr) != NULL) { pairmake_packet(newattr, ptr + 1, T_OP_EQ); } } else { /* h322-foo-bar = "h323-foo-bar = baz" */ /* * We strip out the duplicity from the * value field, we use only the value on * the right side of the '=' character. */ pairstrcpy(vp, ptr + 1); } } }
static void dhcp_packet_debug(RADIUS_PACKET *packet, bool received) { fr_cursor_t cursor; char buffer[256]; char src_ipaddr[INET6_ADDRSTRLEN]; char dst_ipaddr[INET6_ADDRSTRLEN]; #if defined(WITH_UDPFROMTO) && defined(WITH_IFINDEX_NAME_RESOLUTION) char if_name[IFNAMSIZ]; #endif VALUE_PAIR *vp; if (!packet) return; /* * Client-specific debugging re-prints the input * packet into the client log. * * This really belongs in a utility library */ printf("%s %s Id %08x from %s%s%s:%i to %s%s%s:%i " #if defined(WITH_UDPFROMTO) && defined(WITH_IFINDEX_NAME_RESOLUTION) "%s%s%s" #endif "length %zu\n", received ? "Received" : "Sending", dhcp_message_types[packet->code], packet->id, packet->src_ipaddr.af == AF_INET6 ? "[" : "", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.addr, src_ipaddr, sizeof(src_ipaddr)), packet->src_ipaddr.af == AF_INET6 ? "]" : "", packet->src_port, packet->dst_ipaddr.af == AF_INET6 ? "[" : "", inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.addr, dst_ipaddr, sizeof(dst_ipaddr)), packet->dst_ipaddr.af == AF_INET6 ? "]" : "", packet->dst_port, #if defined(WITH_UDPFROMTO) && defined(WITH_IFINDEX_NAME_RESOLUTION) packet->if_index ? "via " : "", packet->if_index ? fr_ifname_from_ifindex(if_name, packet->if_index) : "", packet->if_index ? " " : "", #endif packet->data_len); for (vp = fr_cursor_init(&cursor, &packet->vps); vp; vp = fr_cursor_next(&cursor)) { VP_VERIFY(vp); fr_pair_snprint(buffer, sizeof(buffer), vp); printf("\t%s\n", buffer); } }
/** Print a list of attributes and enumv * * @param fp to output to. * @param const_vp to print. */ void vp_printlist(FILE *fp, VALUE_PAIR const *const_vp) { VALUE_PAIR *vp; vp_cursor_t cursor; memcpy(&vp, &const_vp, sizeof(vp)); /* const work-arounds */ for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) { vp_print(fp, vp); } }
/** Return a VP from a value_pair_tmpl_t * * @param out where to write the retrieved vp. * @param request current request. * @param vpt the value pair template * @return -1 if VP could not be found, -2 if list could not be found, -3 if context could not be found. */ int tmpl_find_vp(VALUE_PAIR **out, REQUEST *request, value_pair_tmpl_t const *vpt) { VALUE_PAIR **vps, *vp; rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST)); if (out) *out = NULL; if (radius_request(&request, vpt->tmpl_request) < 0) { return -3; } vps = radius_list(request, vpt->tmpl_list); if (!vps) { return -2; } switch (vpt->type) { /* * May not may not be found, but it *is* a known name. */ case TMPL_TYPE_ATTR: { int num; vp_cursor_t cursor; if (vpt->tmpl_num == NUM_ANY) { vp = pairfind(*vps, vpt->tmpl_da->attr, vpt->tmpl_da->vendor, vpt->tmpl_tag); if (!vp) return -1; break; } (void) fr_cursor_init(&cursor, vps); num = vpt->tmpl_num; while ((vp = fr_cursor_next_by_da(&cursor, vpt->tmpl_da, vpt->tmpl_tag))) { VERIFY_VP(vp); if (num-- <= 0) goto finish; } return -1; } case TMPL_TYPE_LIST: vp = *vps; break; default: rad_assert(0); } finish: if (out) *out = vp; return 0; }
/* * Dump a whole list of attributes to DEBUG2 */ void vp_listdebug(VALUE_PAIR *vp) { vp_cursor_t cursor; char tmpPair[70]; for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) { vp_prints(tmpPair, sizeof(tmpPair), vp); DEBUG2(" %s", tmpPair); } }
/** Merges two sets of VPs * * The list represented by cursor will hold the union of cursor and * add lists. * * @param cursor to insert VALUE_PAIRs with * @param add one or more VALUE_PAIRs. */ void fr_cursor_merge(vp_cursor_t *cursor, VALUE_PAIR *add) { vp_cursor_t from; VALUE_PAIR *vp; for (vp = fr_cursor_init(&from, &add); vp; vp = fr_cursor_next(&from)) { fr_cursor_insert(cursor, vp); } }
/** Find the pair with the matching DAs * */ VALUE_PAIR *pair_find_by_da(VALUE_PAIR *vp, DICT_ATTR const *da, int8_t tag) { vp_cursor_t cursor; if(!fr_assert(da)) { return NULL; } (void) fr_cursor_init(&cursor, &vp); return fr_cursor_next_by_da(&cursor, da, tag); }
/** Copy a pairlist. * * Copy all pairs from 'from' regardless of tag, attribute or vendor. * * @param[in] ctx for new VALUE_PAIRs to be allocated in. * @param[in] from whence to copy VALUE_PAIRs. * @return the head of the new VALUE_PAIR list or NULL on error. */ VALUE_PAIR *paircopy(TALLOC_CTX *ctx, VALUE_PAIR *from) { vp_cursor_t src, dst; VALUE_PAIR *out = NULL, *vp; fr_cursor_init(&dst, &out); for (vp = fr_cursor_init(&src, &from); vp; vp = fr_cursor_next(&src)) { VERIFY_VP(vp); vp = paircopyvp(ctx, vp); if (!vp) { pairfree(&out); return NULL; } fr_cursor_insert(&dst, vp); /* paircopy sets next pointer to NULL */ } return out; }
/** Find the pair with the matching attribute * * @todo should take DAs and do a pointer comparison. */ VALUE_PAIR *pairfind(VALUE_PAIR *vp, unsigned int attr, unsigned int vendor, int8_t tag) { vp_cursor_t cursor; /* List head may be NULL if it contains no VPs */ if (!vp) return NULL; VERIFY_LIST(vp); (void) fr_cursor_init(&cursor, &vp); return fr_cursor_next_by_num(&cursor, attr, vendor, tag); }
/* * Convert field X to a VP. */ static int csv_map_getvalue(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx) { char const *str = uctx; VALUE_PAIR *head = NULL, *vp; vp_cursor_t cursor; DICT_ATTR const *da; rad_assert(ctx != NULL); fr_cursor_init(&cursor, &head); /* * FIXME: allow multiple entries. */ if (map->lhs->type == TMPL_TYPE_ATTR) { da = map->lhs->tmpl_da; } else { char *attr; if (tmpl_aexpand(ctx, &attr, request, map->lhs, NULL, NULL) <= 0) { RWDEBUG("Failed expanding string"); return -1; } da = dict_attrbyname(attr); if (!da) { RWDEBUG("No such attribute '%s'", attr); return -1; } talloc_free(attr); } vp = pairalloc(ctx, da); rad_assert(vp); if (pairparsevalue(vp, str, talloc_array_length(str) - 1) < 0) { char *escaped; escaped = fr_aprints(vp, str, talloc_array_length(str) - 1, '\''); RWDEBUG("Failed parsing value \"%s\" for attribute %s: %s", escaped, map->lhs->tmpl_da->name, fr_strerror()); talloc_free(vp); /* also frees escaped */ return -1; } vp->op = map->op; fr_cursor_merge(&cursor, vp); *out = head; return 0; }
/** Print a list of valuepairs to stderr or error log. * * @param[in] vp to print. */ void debug_pair_list(VALUE_PAIR *vp) { vp_cursor_t cursor; if (!vp || !debug_flag || !fr_log_fp) return; for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) { vp_print(fr_log_fp, vp); } fflush(fr_log_fp); }
/* * Convert field X to a VP. */ static int csv_map_getvalue(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx) { char const *str = uctx; VALUE_PAIR *head = NULL, *vp; fr_cursor_t cursor; fr_dict_attr_t const *da; rad_assert(ctx != NULL); fr_cursor_init(&cursor, &head); /* * FIXME: allow multiple entries. */ if (map->lhs->type == TMPL_TYPE_ATTR) { da = map->lhs->tmpl_da; } else { char *attr; if (tmpl_aexpand(ctx, &attr, request, map->lhs, NULL, NULL) <= 0) { RWDEBUG("Failed expanding string"); return -1; } da = fr_dict_attr_by_name(request->dict, attr); if (!da) { RWDEBUG("No such attribute '%s'", attr); return -1; } talloc_free(attr); } vp = fr_pair_afrom_da(ctx, da); rad_assert(vp); if (fr_pair_value_from_str(vp, str, talloc_array_length(str) - 1, '\0', true) < 0) { RWDEBUG("Failed parsing value \"%pV\" for attribute %s: %s", fr_box_strvalue_buffer(str), map->lhs->tmpl_da->name, fr_strerror()); talloc_free(vp); return -1; } vp->op = map->op; fr_cursor_append(&cursor, vp); *out = head; return 0; }
/** Merges multiple VALUE_PAIR into the cursor * * Add multiple VALUE_PAIR from add to cursor. * * @addtogroup module_safe * * @param cursor to insert VALUE_PAIRs with * @param add one or more VALUE_PAIRs (may be NULL, which results in noop). */ void fr_cursor_merge(vp_cursor_t *cursor, VALUE_PAIR *add) { vp_cursor_t from; VALUE_PAIR *vp; if (!add) return; if (!fr_assert(cursor->first)) return; /* cursor must have been initialised */ for (vp = fr_cursor_init(&from, &add); vp; vp = fr_cursor_next(&from)) { fr_cursor_insert(cursor, vp); } }
/** Free memory used by a valuepair list. * * @todo TLV: needs to free all dependents of each VP freed. */ void pairfree(VALUE_PAIR **vps) { VALUE_PAIR *vp; vp_cursor_t cursor; if (!vps || !*vps) { return; } for (vp = fr_cursor_init(&cursor, vps); vp; vp = fr_cursor_next(&cursor)) { VERIFY_VP(vp); talloc_free(vp); } *vps = NULL; }
/** Print a list of VALUE_PAIRs. * * @param[in] lvl Debug lvl (1-4). * @param[in] request to read logging params from. * @param[in] vp to print. * @param[in] prefix (optional). */ void log_request_pair_list(fr_log_lvl_t lvl, REQUEST *request, VALUE_PAIR *vp, char const *prefix) { fr_cursor_t cursor; if (!vp || !request || !request->log.dst) return; if (!log_debug_enabled(L_DBG, lvl, request)) return; RINDENT(); for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) { VP_VERIFY(vp); RDEBUGX(lvl, "%s%pP", prefix ? prefix : "&", vp); } REXDENT(); }
static int attr_filter_getfile(TALLOC_CTX *ctx, char const *filename, PAIR_LIST **pair_list) { vp_cursor_t cursor; int rcode; PAIR_LIST *attrs = NULL; PAIR_LIST *entry; VALUE_PAIR *vp; rcode = pairlist_read(ctx, filename, &attrs, 1); if (rcode < 0) { return -1; } /* * Walk through the 'attrs' file list. */ entry = attrs; while (entry) { entry->check = entry->reply; entry->reply = NULL; for (vp = fr_cursor_init(&cursor, &entry->check); vp; vp = fr_cursor_next(&cursor)) { /* * If it's NOT a vendor attribute, * and it's NOT a wire protocol * and we ignore Fall-Through, * then bitch about it, giving a good warning message. */ if ((vp->da->vendor == 0) && (vp->da->attr > 1000)) { WARN("[%s]:%d Check item \"%s\"\n\tfound in filter list for realm \"%s\".\n", filename, entry->lineno, vp->da->name, entry->name); } } entry = entry->next; } *pair_list = attrs; return 0; }
/** Send a success notification * */ static int eap_sim_send_eap_success_notification(eap_session_t *eap_session) { REQUEST *request = eap_session->request; RADIUS_PACKET *packet = eap_session->request->reply; eap_sim_session_t *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t); fr_cursor_t cursor; VALUE_PAIR *vp; RDEBUG2("Sending SIM-Notification (Success)"); eap_session->this_round->request->code = FR_EAP_CODE_REQUEST; if (!fr_cond_assert(eap_sim_session->challenge_success)) return -1; fr_cursor_init(&cursor, &packet->vps); /* * Set the subtype to notification */ vp = fr_pair_afrom_da(packet, attr_eap_sim_subtype); vp->vp_uint16 = FR_EAP_SIM_SUBTYPE_VALUE_SIM_NOTIFICATION; fr_cursor_append(&cursor, vp); vp = fr_pair_afrom_da(packet, attr_eap_sim_notification); vp->vp_uint16 = FR_EAP_SIM_NOTIFICATION_VALUE_SUCCESS; fr_cursor_append(&cursor, vp); /* * Need to include an AT_MAC attribute so that it will get * calculated. */ vp = fr_pair_afrom_da(packet, attr_eap_sim_mac); fr_pair_replace(&packet->vps, vp); /* * Encode the packet */ if (eap_sim_compose(eap_session, NULL, 0) < 0) { fr_pair_list_free(&packet->vps); return -1; } return 0; }