/** Convert CONFIG_PAIR to VALUE_PAIR_MAP. * * Treats the left operand as a * @verbatim<request>.<list>.<attribute>@endverbatim reference and the right * operand as a module specific value. * * The left operand will be pre-parsed into request ref, dst list, and da, * the right operand will be left as a string. * * Return must be freed with radius_mapfree. * * @param[in] cp to convert to map. * @param[in] request_def The default request to insert unqualified * attributes into. * @param[in] list_def The default list to insert unqualified attributes into. * @return VALUE_PAIR_MAP if successful or NULL on error. */ VALUE_PAIR_MAP *radius_cp2map(CONF_PAIR *cp, request_refs_t request_def, pair_lists_t list_def) { VALUE_PAIR_MAP *map; const char *attr; const char *value; map = rad_malloc(sizeof(VALUE_PAIR_MAP)); memset(map, 0, sizeof(VALUE_PAIR_MAP)); attr = cf_pair_attr(cp); map->dst = radius_attr2tmpl(attr, request_def, list_def); if (!map->dst){ goto error; } value = cf_pair_value(cp); if (!value) { radlog(L_ERR, "Missing attribute name"); goto error; } map->src = radius_str2tmpl(value); if (!map->src) { goto error; } map->op_token = cf_pair_operator(cp); /* * Infer whether we need to expand the mapping values * The old style attribute map allowed the user to specify * whether the LDAP value should be expanded. * We can't really support that easily, but equivalent * functionality should be available with %{eval:} */ switch (cf_pair_value_type(cp)) { case T_BARE_WORD: case T_SINGLE_QUOTED_STRING: map->src->do_xlat = FALSE; break; case T_BACK_QUOTED_STRING: case T_DOUBLE_QUOTED_STRING: map->src->do_xlat = TRUE; break; default: rad_assert(0); goto error; } return map; error: radius_mapfree(&map); return NULL; }
/** Convert strings to value_pair_map_e * * Treatment of operands depends on quotation, barewords are treated * as attribute references, double quoted values are treated as * expandable strings, single quoted values are treated as literal * strings. * * Return must be freed with talloc_free * * @param[in] ctx for talloc * @param[in] lhs of the operation * @param[in] lhs_type type of the LHS string * @param[in] op the operation to perform * @param[in] rhs of the operation * @param[in] rhs_type type of the RHS string * @param[in] dst_request_def The default request to insert unqualified * attributes into. * @param[in] dst_list_def The default list to insert unqualified attributes * into. * @param[in] src_request_def The default request to resolve attribute * references in. * @param[in] src_list_def The default list to resolve unqualified attributes * in. * @return value_pair_map_t if successful or NULL on error. */ value_pair_map_t *radius_str2map(TALLOC_CTX *ctx, char const *lhs, FR_TOKEN lhs_type, FR_TOKEN op, char const *rhs, FR_TOKEN rhs_type, request_refs_t dst_request_def, pair_lists_t dst_list_def, request_refs_t src_request_def, pair_lists_t src_list_def) { value_pair_map_t *map; map = talloc_zero(ctx, value_pair_map_t); if ((lhs_type == T_BARE_WORD) && (*lhs == '&')) { map->dst = radius_attr2tmpl(map, lhs + 1, dst_request_def, dst_list_def); } else { map->dst = radius_str2tmpl(map, lhs, lhs_type); } if (!map->dst) { error: talloc_free(map); return NULL; } map->op = op; /* * Ignore the RHS if it's a true / false comparison. */ if ((map->op == T_OP_CMP_TRUE) || (map->op == T_OP_CMP_FALSE)) { return map; } if ((rhs_type == T_BARE_WORD) && (*rhs == '&')) { map->src = radius_attr2tmpl(map, rhs + 1, src_request_def, src_list_def); } else { map->src = radius_str2tmpl(map, rhs, rhs_type); } if (!map->dst) goto error; return map; }
/** Convert CONFIG_PAIR (which may contain refs) to value_pair_map_t. * * Treats the left operand as an attribute reference * @verbatim<request>.<list>.<attribute>@endverbatim * * Treatment of left operand depends on quotation, barewords are treated as * attribute references, double quoted values are treated as expandable strings, * single quoted values are treated as literal strings. * * Return must be freed with talloc_free * * @param[in] ctx for talloc * @param[in] cp to convert to map. * @param[in] dst_request_def The default request to insert unqualified * attributes into. * @param[in] dst_list_def The default list to insert unqualified attributes * into. * @param[in] src_request_def The default request to resolve attribute * references in. * @param[in] src_list_def The default list to resolve unqualified attributes * in. * @return value_pair_map_t if successful or NULL on error. */ value_pair_map_t *radius_cp2map(TALLOC_CTX *ctx, CONF_PAIR *cp, request_refs_t dst_request_def, pair_lists_t dst_list_def, request_refs_t src_request_def, pair_lists_t src_list_def) { value_pair_map_t *map; char const *attr; char const *value; FR_TOKEN type; CONF_ITEM *ci = cf_pairtoitem(cp); if (!cp) return NULL; map = talloc_zero(ctx, value_pair_map_t); attr = cf_pair_attr(cp); value = cf_pair_value(cp); if (!value) { cf_log_err(ci, "Missing attribute value"); goto error; } map->dst = radius_attr2tmpl(map, attr, dst_request_def, dst_list_def); if (!map->dst) { cf_log_err(ci, "Syntax error in attribute definition"); goto error; } /* * Bare words always mean attribute references. */ type = cf_pair_value_type(cp); if (type == T_BARE_WORD) { if (*value == '&') { map->src = radius_attr2tmpl(map, value + 1, src_request_def, src_list_def); } else { if (!isdigit((int) *value) && ((strchr(value, ':') != NULL) || (dict_attrbyname(value) != NULL))) { map->src = radius_attr2tmpl(map, value, src_request_def, src_list_def); } if (map->src) { WDEBUG("%s[%d]: Please add '&' for attribute reference '%s = &%s'", cf_pair_filename(cp), cf_pair_lineno(cp), attr, value); } else { map->src = radius_str2tmpl(map, value, type); } } } else { map->src = radius_str2tmpl(map, value, type); } if (!map->src) { goto error; } map->op = cf_pair_operator(cp); map->ci = ci; /* * Lots of sanity checks for insane people... */ /* * We don't support implicit type conversion, * except for "octets" */ if (map->dst->da && map->src->da && (map->src->da->type != map->dst->da->type) && (map->src->da->type != PW_TYPE_OCTETS) && (map->dst->da->type != PW_TYPE_OCTETS)) { cf_log_err(ci, "Attribute type mismatch"); goto error; } /* * What exactly where you expecting to happen here? */ if ((map->dst->type == VPT_TYPE_ATTR) && (map->src->type == VPT_TYPE_LIST)) { cf_log_err(ci, "Can't copy list into an attribute"); goto error; } /* * Can't copy an xlat expansion or literal into a list, * we don't know what type of attribute we'd need * to create */ if ((map->dst->type == VPT_TYPE_LIST) && ((map->src->type == VPT_TYPE_XLAT) || (map->src->type == VPT_TYPE_LITERAL))) { cf_log_err(ci, "Can't copy value into list (we don't know which attribute to create)"); goto error; } /* * Depending on the attribute type, some operators are * disallowed. */ if (map->dst->type == VPT_TYPE_ATTR) { if ((map->op != T_OP_EQ) && (map->op != T_OP_CMP_EQ) && (map->op != T_OP_ADD) && (map->op != T_OP_SUB) && (map->op != T_OP_LE) && (map->op != T_OP_GE) && (map->op != T_OP_CMP_FALSE) && (map->op != T_OP_SET)) { cf_log_err(ci, "Invalid operator for attribute"); goto error; } } switch (map->src->type) { /* * Only += and -= operators are supported for list copy. */ case VPT_TYPE_LIST: switch (map->op) { case T_OP_SUB: case T_OP_ADD: break; default: cf_log_err(ci, "Operator \"%s\" not allowed " "for list copy", fr_int2str(fr_tokens, map->op, "<INVALID>")); goto error; } break; default: break; } return map; error: talloc_free(map); return NULL; }
/** Convert CONFIG_PAIR (which may contain refs) to value_pair_map_t. * * Treats the left operand as an attribute reference * @verbatim<request>.<list>.<attribute>@endverbatim * * Treatment of left operand depends on quotation, barewords are treated as * attribute references, double quoted values are treated as expandable strings, * single quoted values are treated as literal strings. * * Return must be freed with radius_mapfree. * * @param[in] cp to convert to map. * @param[in] dst_request_def The default request to insert unqualified * attributes into. * @param[in] dst_list_def The default list to insert unqualified attributes * into. * @param[in] src_request_def The default request to resolve attribute * references in. * @param[in] src_list_def The default list to resolve unqualified attributes * in. * @return value_pair_map_t if successful or NULL on error. */ value_pair_map_t *radius_cp2map(CONF_PAIR *cp, request_refs_t dst_request_def, pair_lists_t dst_list_def, request_refs_t src_request_def, pair_lists_t src_list_def) { value_pair_map_t *map; const char *attr; const char *value; FR_TOKEN type; CONF_ITEM *ci = cf_pairtoitem(cp); if (!cp) return NULL; map = rad_calloc(sizeof(value_pair_map_t)); attr = cf_pair_attr(cp); value = cf_pair_value(cp); if (!value) { cf_log_err(ci, "Missing attribute value"); goto error; } map->dst = radius_attr2tmpl(attr, dst_request_def, dst_list_def); if (!map->dst){ goto error; } /* * Bare words always mean attribute references. */ type = cf_pair_value_type(cp); map->src = type == T_BARE_WORD ? radius_attr2tmpl(value, src_request_def, src_list_def) : radius_str2tmpl(value, type); if (!map->src) { goto error; } map->op = cf_pair_operator(cp); map->ci = ci; /* * Lots of sanity checks for insane people... */ /* * We don't support implicit type conversion */ if (map->dst->da && map->src->da && (map->src->da->type != map->dst->da->type)) { cf_log_err(ci, "Attribute type mismatch"); goto error; } /* * What exactly where you expecting to happen here? */ if ((map->dst->type == VPT_TYPE_ATTR) && (map->src->type == VPT_TYPE_LIST)) { cf_log_err(ci, "Can't copy list into an attribute"); goto error; } switch (map->src->type) { /* * Only += and -= operators are supported for list copy. */ case VPT_TYPE_LIST: switch (map->op) { case T_OP_SUB: case T_OP_ADD: break; default: cf_log_err(ci, "Operator \"%s\" not allowed " "for list copy", fr_int2str(fr_tokens, map->op, "¿unknown?")); goto error; } break; /* * @todo add support for exec expansion. */ case VPT_TYPE_EXEC: cf_log_err(ci, "Exec values are not allowed"); break; default: break; } return map; error: radius_mapfree(&map); return NULL; }
/** Convert CONFIG_PAIR (which may contain refs) to value_pair_map_t. * * Treats the left operand as an attribute reference * @verbatim<request>.<list>.<attribute>@endverbatim * * Treatment of left operand depends on quotation, barewords are treated as * attribute references, double quoted values are treated as expandable strings, * single quoted values are treated as literal strings. * * Return must be freed with talloc_free * * @param[in] ctx for talloc * @param[in] cp to convert to map. * @param[in] dst_request_def The default request to insert unqualified * attributes into. * @param[in] dst_list_def The default list to insert unqualified attributes * into. * @param[in] src_request_def The default request to resolve attribute * references in. * @param[in] src_list_def The default list to resolve unqualified attributes * in. * @return value_pair_map_t if successful or NULL on error. */ value_pair_map_t *radius_cp2map(TALLOC_CTX *ctx, CONF_PAIR *cp, request_refs_t dst_request_def, pair_lists_t dst_list_def, request_refs_t src_request_def, pair_lists_t src_list_def) { value_pair_map_t *map; char const *attr; char const *value; FR_TOKEN type; CONF_ITEM *ci = cf_pairtoitem(cp); if (!cp) return NULL; map = talloc_zero(ctx, value_pair_map_t); map->op = cf_pair_operator(cp); map->ci = ci; attr = cf_pair_attr(cp); value = cf_pair_value(cp); if (!value) { cf_log_err(ci, "Missing attribute value"); goto error; } /* * LHS must always be an attribute reference. */ map->dst = radius_attr2tmpl(map, attr, dst_request_def, dst_list_def); if (!map->dst) { cf_log_err(ci, "Syntax error in attribute definition"); goto error; } /* * RHS might be an attribute reference. */ type = cf_pair_value_type(cp); map->src = radius_str2tmpl(map, value, type, src_request_def, src_list_def); if (!map->src) { goto error; } /* * Anal-retentive checks. */ if (debug_flag > 2) { if ((map->dst->type == VPT_TYPE_ATTR) && (*attr != '&')) { WARN("%s[%d]: Please change attribute reference to '&%s %s ...'", cf_pair_filename(cp), cf_pair_lineno(cp), attr, fr_int2str(fr_tokens, map->op, "<INVALID>")); } if ((map->src->type == VPT_TYPE_ATTR) && (*value != '&')) { WARN("%s[%d]: Please change attribute reference to '... %s &%s'", cf_pair_filename(cp), cf_pair_lineno(cp), fr_int2str(fr_tokens, map->op, "<INVALID>"), value); } } /* * Lots of sanity checks for insane people... */ /* * We don't support implicit type conversion, * except for "octets" */ if (map->dst->vpt_da && map->src->vpt_da && (map->src->vpt_da->type != map->dst->vpt_da->type) && (map->src->vpt_da->type != PW_TYPE_OCTETS) && (map->dst->vpt_da->type != PW_TYPE_OCTETS)) { cf_log_err(ci, "Attribute type mismatch"); goto error; } /* * What exactly where you expecting to happen here? */ if ((map->dst->type == VPT_TYPE_ATTR) && (map->src->type == VPT_TYPE_LIST)) { cf_log_err(ci, "Can't copy list into an attribute"); goto error; } /* * Depending on the attribute type, some operators are * disallowed. */ if (map->dst->type == VPT_TYPE_ATTR) { if ((map->op != T_OP_EQ) && (map->op != T_OP_CMP_EQ) && (map->op != T_OP_ADD) && (map->op != T_OP_SUB) && (map->op != T_OP_LE) && (map->op != T_OP_GE) && (map->op != T_OP_CMP_FALSE) && (map->op != T_OP_SET)) { cf_log_err(ci, "Invalid operator for attribute"); goto error; } /* * This will be an error in future versions of * the server. */ if ((map->op == T_OP_CMP_FALSE) && ((map->src->type != VPT_TYPE_LITERAL) || (strcmp(map->src->name, "ANY") != 0))) { WARN("%s[%d] Attribute deletion MUST use '!* ANY'", cf_pair_filename(cp), cf_pair_lineno(cp)); } } if (map->dst->type == VPT_TYPE_LIST) { /* * Only += and :=, and !* operators are supported * for lists. */ switch (map->op) { case T_OP_CMP_FALSE: if ((map->src->type != VPT_TYPE_LITERAL) || (strcmp(map->src->name, "ANY") != 0)) { cf_log_err(ci, "List deletion MUST use '!* ANY'"); goto error; } break; case T_OP_ADD: if ((map->src->type != VPT_TYPE_LIST) && (map->src->type != VPT_TYPE_EXEC)) { cf_log_err(ci, "Invalid source for list '+='"); goto error; } break; case T_OP_SET: if (map->src->type == VPT_TYPE_EXEC) { WARN("%s[%d] Please change ':=' to '=' for list assignment", cf_pair_filename(cp), cf_pair_lineno(cp)); break; } if (map->src->type != VPT_TYPE_LIST) { cf_log_err(ci, "Invalid source for ':=' operator"); goto error; } break; case T_OP_EQ: if (map->src->type != VPT_TYPE_EXEC) { cf_log_err(ci, "Invalid source for '=' operator"); goto error; } break; default: cf_log_err(ci, "Operator \"%s\" not allowed for list assignment", fr_int2str(fr_tokens, map->op, "<INVALID>")); goto error; } } return map; error: talloc_free(map); return NULL; }