/** Convert a map to a VALUE_PAIR. * * @param[out] out Where to write the VALUE_PAIR(s). * @param[in] request structure (used only for talloc) * @param[in] map the map. The LHS (dst) has to be VPT_TYPE_ATTR or VPT_TYPE_LIST. * @param[in] ctx unused * @return 0 on success, -1 on failure, -2 on attribute not found/equivalent */ int radius_map2vp(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map, UNUSED void *ctx) { int rcode = 0; VALUE_PAIR *vp = NULL, *found, **from = NULL; DICT_ATTR const *da; REQUEST *context; vp_cursor_t cursor; rad_assert(request != NULL); rad_assert(map != NULL); *out = NULL; /* * Special case for !*, we don't need to parse the value, just allocate an attribute with * the right operator. */ if (map->op == T_OP_CMP_FALSE) { vp = pairalloc(request, map->dst->da); if (!vp) return -1; vp->op = map->op; *out = vp; return 0; } /* * List to list found, this is a special case because we don't need * to allocate any attributes, just found the current list, and change * the op. */ if ((map->dst->type == VPT_TYPE_LIST) && (map->src->type == VPT_TYPE_LIST)) { from = radius_list(request, map->src->list); if (!from) return -2; found = paircopy(request, *from); /* * List to list copy is invalid if the src list has no attributes. */ if (!found) return -2; for (vp = paircursor(&cursor, &found); vp; vp = pairnext(&cursor)) { vp->op = T_OP_ADD; } *out = found; return 0; } /* * Deal with all non-list founding operations. */ da = map->dst->da ? map->dst->da : map->src->da; switch (map->src->type) { case VPT_TYPE_XLAT: case VPT_TYPE_LITERAL: case VPT_TYPE_DATA: vp = pairalloc(request, da); if (!vp) return -1; vp->op = map->op; break; default: break; } /* * And parse the RHS */ switch (map->src->type) { case VPT_TYPE_XLAT: rad_assert(map->dst->da); /* Need to know where were going to write the new attribute */ /* * Don't call unnecessary expansions */ if (strchr(map->src->name, '%') != NULL) { ssize_t slen; char *str = NULL; slen = radius_axlat(&str, request, map->src->name, NULL, NULL); if (slen < 0) { rcode = slen; goto error; } rcode = pairparsevalue(vp, str); talloc_free(str); if (!rcode) { pairfree(&vp); rcode = -1; goto error; } break; } /* FALL-THROUGH */ case VPT_TYPE_LITERAL: if (!pairparsevalue(vp, map->src->name)) { rcode = -2; goto error; } break; case VPT_TYPE_ATTR: rad_assert(!map->dst->da || (map->src->da->type == map->dst->da->type) || (map->src->da->type == PW_TYPE_OCTETS) || (map->dst->da->type == PW_TYPE_OCTETS)); context = request; if (radius_request(&context, map->src->request) == 0) { from = radius_list(context, map->src->list); } /* * Can't add the attribute if the list isn't * valid. */ if (!from) { rcode = -2; goto error; } /* * Special case, destination is a list, found all instance of an attribute. */ if (map->dst->type == VPT_TYPE_LIST) { found = paircopy2(request, *from, map->src->da->attr, map->src->da->vendor, TAG_ANY); if (!found) { REDEBUG("Attribute \"%s\" not found in request", map->src->name); rcode = -2; goto error; } for (vp = paircursor(&cursor, &found); vp; vp = pairnext(&cursor)) { vp->op = T_OP_ADD; } *out = found; return 0; } /* * FIXME: allow tag references? */ found = pairfind(*from, map->src->da->attr, map->src->da->vendor, TAG_ANY); if (!found) { REDEBUG("Attribute \"%s\" not found in request", map->src->name); rcode = -2; goto error; } /* * Copy the data over verbatim, assuming it's * actually data. */ // rad_assert(found->type == VT_DATA); vp = paircopyvpdata(request, da, found); if (!vp) { return -1; } vp->op = map->op; break; case VPT_TYPE_DATA: rad_assert(map->src->da->type == map->dst->da->type); memcpy(&vp->data, map->src->vpd, sizeof(vp->data)); vp->length = map->src->length; break; /* * This essentially does the same as rlm_exec xlat, except it's non-configurable. * It's only really here as a convenience for people who expect the contents of * backticks to be executed in a shell. * * exec string is xlat expanded and arguments are shell escaped. */ case VPT_TYPE_EXEC: return radius_mapexec(out, request, map); default: rad_assert(0); /* Should of been caught at parse time */ error: pairfree(&vp); return rcode; } *out = vp; return 0; }
/** Convert a map to a VALUE_PAIR. * * @param[out] out Where to write the VALUE_PAIR(s). * @param[in] request structure (used only for talloc) * @param[in] map the map. The LHS (dst) has to be VPT_TYPE_ATTR or VPT_TYPE_LIST. * @param[in] ctx unused * @return 0 on success, -1 on failure, -2 on attribute not found/equivalent */ int radius_map2vp(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map, UNUSED void *ctx) { int rcode = 0; VALUE_PAIR *vp = NULL, *found, **from = NULL; DICT_ATTR const *da; REQUEST *context = request; vp_cursor_t cursor; rad_assert(request != NULL); rad_assert(map != NULL); *out = NULL; /* * Special case for !*, we don't need to parse RHS as this is a unary operator. */ if (map->op == T_OP_CMP_FALSE) { /* * Were deleting all the attributes in a list. This isn't like the other * mappings because lists aren't represented as attributes (yet), * so we can't return a <list> attribute with the !* operator for * radius_pairmove() to consume, and need to do the work here instead. */ if (map->dst->type == VPT_TYPE_LIST) { if (radius_request(&context, map->dst->request) == 0) { from = radius_list(context, map->dst->list); } if (!from) return -2; pairfree(from); /* @fixme hacky! */ if (map->dst->list == PAIR_LIST_REQUEST) { context->username = NULL; context->password = NULL; } return 0; } /* Not a list, but an attribute, radius_pairmove() will perform that actual delete */ vp = pairalloc(request, map->dst->da); if (!vp) return -1; vp->op = map->op; *out = vp; return 0; } /* * List to list found, this is a special case because we don't need * to allocate any attributes, just finding the current list, and change * the op. */ if ((map->dst->type == VPT_TYPE_LIST) && (map->src->type == VPT_TYPE_LIST)) { if (radius_request(&context, map->src->request) == 0) { from = radius_list(context, map->src->list); } if (!from) return -2; found = paircopy(request, *from); /* * List to list copy is invalid if the src list has no attributes. */ if (!found) return -2; for (vp = fr_cursor_init(&cursor, &found); vp; vp = fr_cursor_next(&cursor)) { vp->op = T_OP_ADD; } *out = found; return 0; } /* * Deal with all non-list operations. */ da = map->dst->da ? map->dst->da : map->src->da; switch (map->src->type) { case VPT_TYPE_XLAT: case VPT_TYPE_XLAT_STRUCT: case VPT_TYPE_LITERAL: case VPT_TYPE_DATA: vp = pairalloc(request, da); if (!vp) return -1; vp->op = map->op; break; default: break; } /* * And parse the RHS */ switch (map->src->type) { ssize_t slen; char *str; case VPT_TYPE_XLAT_STRUCT: rad_assert(map->dst->da); /* Need to know where were going to write the new attribute */ rad_assert(map->src->xlat != NULL); str = NULL; slen = radius_axlat_struct(&str, request, map->src->xlat, NULL, NULL); if (slen < 0) { rcode = slen; goto error; } /* * We do the debug printing because radius_axlat_struct * doesn't have access to the original string. It's been * mangled during the parsing to xlat_exp_t */ RDEBUG2("EXPAND %s", map->src->name); RDEBUG2(" --> %s", str); rcode = pairparsevalue(vp, str); talloc_free(str); if (!rcode) { pairfree(&vp); rcode = -1; goto error; } break; case VPT_TYPE_XLAT: rad_assert(map->dst->da); /* Need to know where were going to write the new attribute */ str = NULL; slen = radius_axlat(&str, request, map->src->name, NULL, NULL); if (slen < 0) { rcode = slen; goto error; } rcode = pairparsevalue(vp, str); talloc_free(str); if (!rcode) { pairfree(&vp); rcode = -1; goto error; } break; case VPT_TYPE_LITERAL: if (!pairparsevalue(vp, map->src->name)) { rcode = -2; goto error; } break; case VPT_TYPE_ATTR: rad_assert(!map->dst->da || (map->src->da->type == map->dst->da->type) || (map->src->da->type == PW_TYPE_OCTETS) || (map->dst->da->type == PW_TYPE_OCTETS)); /* * Special case, destination is a list, found all instance of an attribute. */ if (map->dst->type == VPT_TYPE_LIST) { context = request; if (radius_request(&context, map->src->request) == 0) { from = radius_list(context, map->src->list); } /* * Can't add the attribute if the list isn't * valid. */ if (!from) { rcode = -2; goto error; } found = paircopy2(request, *from, map->src->da->attr, map->src->da->vendor, TAG_ANY); if (!found) { REDEBUG("Attribute \"%s\" not found in request", map->src->name); rcode = -2; goto error; } for (vp = fr_cursor_init(&cursor, &found); vp; vp = fr_cursor_next(&cursor)) { vp->op = T_OP_ADD; } *out = found; return 0; } if (radius_vpt_get_vp(&found, request, map->src) < 0) { REDEBUG("Attribute \"%s\" not found in request", map->src->name); rcode = -2; goto error; } /* * Copy the data over verbatim, assuming it's * actually data. */ vp = paircopyvpdata(request, da, found); if (!vp) { return -1; } vp->op = map->op; break; case VPT_TYPE_DATA: rad_assert(map->src && map->src->da); rad_assert(map->dst && map->dst->da); rad_assert(map->src->da->type == map->dst->da->type); memcpy(&vp->data, map->src->vpd, sizeof(vp->data)); vp->length = map->src->length; break; /* * This essentially does the same as rlm_exec xlat, except it's non-configurable. * It's only really here as a convenience for people who expect the contents of * backticks to be executed in a shell. * * exec string is xlat expanded and arguments are shell escaped. */ case VPT_TYPE_EXEC: return radius_mapexec(out, request, map); default: rad_assert(0); /* Should of been caught at parse time */ error: pairfree(&vp); return rcode; } *out = vp; return 0; }