From: Arran Cudbard-Bell Date: Tue, 15 Jan 2013 17:47:10 +0000 (+0000) Subject: Update attrmap functions to be more flexible, and add CS to map function from rlm_ldap X-Git-Tag: release_3_0_0_beta1~1315 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d5a7380207d0574a38f5cbc24c780715289b4b82;p=thirdparty%2Ffreeradius-server.git Update attrmap functions to be more flexible, and add CS to map function from rlm_ldap --- diff --git a/src/include/radiusd.h b/src/include/radiusd.h index da77620dafe..1214a9003c6 100644 --- a/src/include/radiusd.h +++ b/src/include/radiusd.h @@ -720,49 +720,74 @@ pair_lists_t radius_list_name(const char **name, pair_lists_t unknown); int radius_request(REQUEST **request, request_refs_t name); request_refs_t radius_request_name(const char **name, request_refs_t unknown); -/* - * See main/valuepair.c - * +/** A pre-parsed template attribute + * * Value pair template, used when processing various mappings sections * to create a real valuepair later. + * + * @see value_pair_map_t */ -typedef struct value_pair_tmpl { - const char *name; - const DICT_ATTR *da; - - int do_xlat; - - request_refs_t request; - pair_lists_t list; -} VALUE_PAIR_TMPL; - -/* - * Value pair map +typedef struct value_pair_tmpl_t { + const char *name; //!< Original attribute ref string, or + //!< where this refers to a none FR + //!< attribute, just the string id for + //!< the attribute. + + request_refs_t request; //!< Request to search or insert in. + pair_lists_t list; //!< List to search or insert in. + + const DICT_ATTR *da; //!< Resolved dictionary attribute. + int do_xlat; //!< Controls whether the VP value + //!< (when it's created), is also + //!< xlat expanded. +} value_pair_tmpl_t; + +/** Value pair map + * + * Value pair maps contain a pair of templates, that describe a src attribute + * or value, and a destination attribute. + * + * Neither src or dst need to be an FR attribute, and their type can be inferred + * from whether map->da is NULL (not FR). + * + * @see value_pair_tmpl_t */ typedef struct value_pair_map { - VALUE_PAIR_TMPL *dst; - VALUE_PAIR_TMPL *src; + value_pair_tmpl_t *dst; //!< Typically describes the attribute + //!< to add or modify. + value_pair_tmpl_t *src; //!< Typically describes a value or a + //!< src attribute to copy. - FR_TOKEN op_token; + FR_TOKEN op; //!< The operator that controls + //!< insertion of the dst attribute. - struct value_pair_map *next; -} VALUE_PAIR_MAP; + struct value_pair_map *next; //!< The next valuepair map. +} value_pair_map_t; typedef VALUE_PAIR *(*radius_tmpl_getvalue_t)(REQUEST *request, - const VALUE_PAIR_TMPL *src, + const value_pair_map_t *map, void *ctx); -void radius_tmplfree(VALUE_PAIR_TMPL **tmpl); -int radius_parse_attr(const char *name, VALUE_PAIR_TMPL *vpt, +void radius_tmplfree(value_pair_tmpl_t **tmpl); +int radius_parse_attr(const char *name, value_pair_tmpl_t *vpt, request_refs_t request_def, pair_lists_t list_def); -VALUE_PAIR_TMPL *radius_attr2tmpl(const char *name, request_refs_t request_def, - pair_lists_t list_def); -VALUE_PAIR_TMPL *radius_str2tmpl(const char *name); -VALUE_PAIR_MAP *radius_cp2map(CONF_PAIR *cp, request_refs_t request_def, - pair_lists_t list_def); -int radius_map2request(REQUEST *request, const VALUE_PAIR_MAP *map, +value_pair_tmpl_t *radius_attr2tmpl(const char *name, + request_refs_t request_def, + pair_lists_t list_def); + +value_pair_tmpl_t *radius_str2tmpl(const char *name, FR_TOKEN type); +int radius_attrmap(CONF_SECTION *cs, value_pair_map_t **head, + pair_lists_t dst_list_def, pair_lists_t src_list_def, + unsigned int max); +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); + +int radius_map2request(REQUEST *request, const value_pair_map_t *map, const char *src, radius_tmpl_getvalue_t func, void *ctx); -void radius_mapfree(VALUE_PAIR_MAP **map); +void radius_mapfree(value_pair_map_t **map); int radius_get_vp(REQUEST *request, const char *name, VALUE_PAIR **vp_p); diff --git a/src/main/valuepair.c b/src/main/valuepair.c index 2a712f9b48d..ed50352755d 100644 --- a/src/main/valuepair.c +++ b/src/main/valuepair.c @@ -946,6 +946,9 @@ VALUE_PAIR **radius_list(REQUEST *request, pair_lists_t list) #endif } + RDEBUG("WARNING: Specified list \"%s\" is not available in " + "this context", fr_int2str(pair_lists, list, "¿unknown?")); + return NULL; } @@ -1008,13 +1011,13 @@ pair_lists_t radius_list_name(const char **name, pair_lists_t unknown) * Resolve name to a current request. * * @see radius_list - * @param[in,out] request to use as context, and to write result to. + * @param[in,out] context Base context to use, and to write the result back to. * @param[in] name (request) to resolve to. * @return 0 if request is valid in this context, else -1. */ -int radius_request(REQUEST **request, request_refs_t name) +int radius_request(REQUEST **context, request_refs_t name) { - rad_assert(request && *request); + REQUEST *request = *context; switch (name) { case REQUEST_CURRENT: @@ -1022,11 +1025,15 @@ int radius_request(REQUEST **request, request_refs_t name) case REQUEST_PARENT: /* for future use in request chaining */ case REQUEST_OUTER: - if (!(*request)->parent) { + if (!request->parent) { + RDEBUG("WARNING: Specified request \"%s\" is " + "not available in this context", + fr_int2str(request_refs, name, + "¿unknown?")); return FALSE; } - *request = (*request)->parent; + *context = request->parent; break; @@ -1078,7 +1085,7 @@ request_refs_t radius_request_name(const char **name, request_refs_t unknown) * * @param[in,out] tmpl to free. */ -void radius_tmplfree(VALUE_PAIR_TMPL **tmpl) +void radius_tmplfree(value_pair_tmpl_t **tmpl) { if (*tmpl == NULL) return; @@ -1091,7 +1098,7 @@ void radius_tmplfree(VALUE_PAIR_TMPL **tmpl) *tmpl = NULL; } -/** Parse qualifiers to convert attrname into a VALUE_PAIR_TMPL. +/** Parse qualifiers to convert attrname into a value_pair_tmpl_t. * * VPTs are used in various places where we need to pre-parse configuration * sections into attribute mappings. @@ -1107,7 +1114,7 @@ void radius_tmplfree(VALUE_PAIR_TMPL **tmpl) * @param[in] list_def The default list to insert unqualified attributes into. * @return -1 on error or 0 on success. */ -int radius_parse_attr(const char *name, VALUE_PAIR_TMPL *vpt, +int radius_parse_attr(const char *name, value_pair_tmpl_t *vpt, request_refs_t request_def, pair_lists_t list_def) { @@ -1151,7 +1158,7 @@ int radius_parse_attr(const char *name, VALUE_PAIR_TMPL *vpt, return 0; } -/** Parse qualifiers to convert attrname into a VALUE_PAIR_TMPL. +/** Parse qualifiers to convert attrname into a value_pair_tmpl_t. * * VPTs are used in various places where we need to pre-parse configuration * sections into attribute mappings. @@ -1160,18 +1167,17 @@ int radius_parse_attr(const char *name, VALUE_PAIR_TMPL *vpt, * @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 pointer to a VALUE_PAIR_TMPL struct (must be freed with + * @return pointer to a value_pair_tmpl_t struct (must be freed with * radius_tmplfree) or NULL on error. */ -VALUE_PAIR_TMPL *radius_attr2tmpl(const char *name, - request_refs_t request_def, - pair_lists_t list_def) +value_pair_tmpl_t *radius_attr2tmpl(const char *name, + request_refs_t request_def, + pair_lists_t list_def) { - VALUE_PAIR_TMPL *vpt; + value_pair_tmpl_t *vpt; const char *copy = strdup(name); - vpt = rad_malloc(sizeof(VALUE_PAIR_TMPL)); - memset(vpt, 0, sizeof(VALUE_PAIR_TMPL)); + vpt = rad_calloc(sizeof(value_pair_tmpl_t)); if (radius_parse_attr(copy, vpt, request_def, list_def) < 0) { radius_tmplfree(&vpt); @@ -1181,20 +1187,33 @@ VALUE_PAIR_TMPL *radius_attr2tmpl(const char *name, return vpt; } -/** Convert module specific attribute id to VALUE_PAIR_TMPL. +/** Convert module specific attribute id to value_pair_tmpl_t. * * @param[in] name string to convert. * @return pointer to new VPT. */ -VALUE_PAIR_TMPL *radius_str2tmpl(const char *name) +value_pair_tmpl_t *radius_str2tmpl(const char *name, FR_TOKEN type) { - VALUE_PAIR_TMPL *vpt; + value_pair_tmpl_t *vpt; - vpt = rad_malloc(sizeof(VALUE_PAIR_TMPL)); - memset(vpt, 0, sizeof(VALUE_PAIR_TMPL)); - + vpt = rad_calloc(sizeof(value_pair_tmpl_t)); vpt->name = strdup(name); + switch (type) + { + case T_BARE_WORD: + case T_SINGLE_QUOTED_STRING: + vpt->do_xlat = FALSE; + break; + case T_BACK_QUOTED_STRING: + case T_DOUBLE_QUOTED_STRING: + vpt->do_xlat = TRUE; + break; + default: + rad_assert(0); + return NULL; + } + return vpt; } @@ -1202,9 +1221,9 @@ VALUE_PAIR_TMPL *radius_str2tmpl(const char *name) * * @param map Head of the map linked list. */ -void radius_mapfree(VALUE_PAIR_MAP **map) +void radius_mapfree(value_pair_map_t **map) { - VALUE_PAIR_MAP *next, *vpm; + value_pair_map_t *next, *vpm; if (!map) return; @@ -1223,14 +1242,14 @@ void radius_mapfree(VALUE_PAIR_MAP **map) *map = NULL; } -/** Convert CONFIG_PAIR to VALUE_PAIR_MAP. +/** Convert CONFIG_PAIR (which may contain refs) to value_pair_map_t. * - * Treats the left operand as a - * @verbatim..@endverbatim reference and the right - * operand as a module specific value. + * Treats the left operand as an attribute reference + * @verbatim..@endverbatim * - * The left operand will be pre-parsed into request ref, dst list, and da, - * the right operand will be left as a string. + * 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. * @@ -1238,60 +1257,47 @@ void radius_mapfree(VALUE_PAIR_MAP **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. + * @return value_pair_map_t 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_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 *map; + value_pair_map_t *map; const char *attr; const char *value; + FR_TOKEN type; - 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; - } + map = rad_calloc(sizeof(value_pair_map_t)); + attr = cf_pair_attr(cp); value = cf_pair_value(cp); if (!value) { - radlog(L_ERR, "Missing attribute name"); + cf_log_err(cf_pairtoitem(cp), "Missing attribute value"); goto error; } - map->src = radius_str2tmpl(value); - if (!map->src) { + map->dst = radius_attr2tmpl(attr, dst_request_def, dst_list_def); + if (!map->dst){ 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:} + * Bare words always mean attribute references. */ - 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; + 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); return map; @@ -1300,9 +1306,89 @@ VALUE_PAIR_MAP *radius_cp2map(CONF_PAIR *cp, request_refs_t request_def, return NULL; } -/** Convert VALUE_PAIR_MAP to VALUE_PAIR(s) and add them to a REQUEST. +/** Convert an 'update' config section into an attribute map. + * + * Uses 'name2' of section to set default request and lists. + * + * @param[in] cs to convert to map. + * @param[out] head Where to store the head of the map. + * @param[in] dst_list_def The default destination list, usually dictated by + * the section the module is being called in. + * @param[in] src_list_def The default source list, usually dictated by the + * section the module is being called in. + * @return -1 on error, else 0. + */ +int radius_attrmap(CONF_SECTION *cs, value_pair_map_t **head, + pair_lists_t dst_list_def, pair_lists_t src_list_def, + unsigned int max) +{ + const char *cs_list, *p; + + request_refs_t request_def = REQUEST_CURRENT; + + CONF_ITEM *ci = cf_sectiontoitem(cs); + CONF_PAIR *cp; + + unsigned int total = 0; + value_pair_map_t **tail, *map; + *head = NULL; + tail = head; + + if (!cs) return 0; + + cs_list = p = cf_section_name2(cs); + if (cs_list) { + request_def = radius_request_name(&p, REQUEST_UNKNOWN); + if (request_def == REQUEST_UNKNOWN) { + cf_log_err(ci, "Default request specified " + "in mapping section is invalid"); + return -1; + } + + dst_list_def = fr_str2int(pair_lists, p, PAIR_LIST_UNKNOWN); + if (dst_list_def == PAIR_LIST_UNKNOWN) { + cf_log_err(ci, "Default list \"%s\" specified " + "in mapping section is invalid", p); + return -1; + } + } + + for (ci = cf_item_find_next(cs, NULL); + ci != NULL; + ci = cf_item_find_next(cs, ci)) { + if (total++ == max) { + cf_log_err(ci, "Map size exceeded"); + goto error; + } + + if (!cf_item_is_pair(ci)) { + cf_log_err(ci, "Entry is not in \"attribute = " + "value\" format"); + goto error; + } + + cp = cf_itemtopair(ci); + map = radius_cp2map(cp, request_def, dst_list_def, + REQUEST_CURRENT, src_list_def); + if (!map) { + goto error; + } + + *tail = map; + tail = &(map->next); + } + + return 0; + + error: + radius_mapfree(head); + return -1; +} + + +/** Convert value_pair_map_t to VALUE_PAIR(s) and add them to a REQUEST. * - * Takes a single VALUE_PAIR_MAP, resolves request and list identifiers + * Takes a single value_pair_map_t, resolves request and list identifiers * to pointers in the current request, the attempts to retrieve module * specific value(s) using callback, and adds the resulting values to the * correct request/list. @@ -1316,14 +1402,14 @@ VALUE_PAIR_MAP *radius_cp2map(CONF_PAIR *cp, request_refs_t request_def, * @return -1 if either attribute or qualifier weren't valid in this context * or callback returned NULL pointer, else 0. */ -int radius_map2request(REQUEST *request, const VALUE_PAIR_MAP *map, +int radius_map2request(REQUEST *request, const value_pair_map_t *map, const char *src, radius_tmpl_getvalue_t func, void *ctx) { VALUE_PAIR **list, *vp, *head; char buffer[MAX_STRING_LEN]; if (radius_request(&request, map->dst->request) < 0) { - RDEBUG("WARNING: Request in mapping \"%s\" -> \"%s\" " + RDEBUG("WARNING: Mapping \"%s\" -> \"%s\" " "invalid in this context, skipping!", map->src->name, map->dst->name); @@ -1332,20 +1418,20 @@ int radius_map2request(REQUEST *request, const VALUE_PAIR_MAP *map, list = radius_list(request, map->dst->list); if (!list) { - RDEBUG("WARNING: List in mapping \"%s\" -> \"%s\" " + RDEBUG("WARNING: Mapping \"%s\" -> \"%s\" " "invalid in this context, skipping!", map->src->name, map->dst->name); return -1; } - head = func(request, map->dst, ctx); + head = func(request, map, ctx); if (head == NULL) { return -1; } for (vp = head; vp != NULL; vp = vp->next) { - vp->operator = map->op_token; + vp->operator = map->op; if (debug_flag) { vp_prints_value(buffer, sizeof(buffer), vp, 1); @@ -1375,7 +1461,7 @@ int radius_map2request(REQUEST *request, const VALUE_PAIR_MAP *map, */ int radius_get_vp(REQUEST *request, const char *name, VALUE_PAIR **vp_p) { - VALUE_PAIR_TMPL vpt; + value_pair_tmpl_t vpt; VALUE_PAIR **vps; *vp_p = NULL; @@ -1386,19 +1472,11 @@ int radius_get_vp(REQUEST *request, const char *name, VALUE_PAIR **vp_p) } if (radius_request(&request, vpt.request) < 0) { - RDEBUG("WARNING: Specified request \"%s\" is not available in " - "this context", fr_int2str(request_refs, vpt.request, - "¿unknown?")); - return 0; } vps = radius_list(request, vpt.list); - if (!vps) { - RDEBUG("WARNING: Specified list \"%s\" is not available in " - "this context", fr_int2str(pair_lists, vpt.list, - "¿unknown?")); - + if (!vps) { return 0; } diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index b4e3559be8b..e2d48510705 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -66,16 +66,17 @@ typedef struct { int chase_referrals; int rebind; - int ldap_debug; /* Debug flag for LDAP SDK */ + int ldap_debug; //!< Debug flag for the SDK. - const char *xlat_name; /* name used to xlat */ + const char *xlat_name; //!< Instance name. int expect_password; /* * RADIUS attribute to LDAP attribute maps */ - VALUE_PAIR_MAP *user_map; /* Applied to users and profiles */ + value_pair_map_t *user_map; //!< Attribute map applied to users and + //!< profiles. /* * Access related configuration @@ -329,7 +330,7 @@ typedef struct ldap_conn { } LDAP_CONN; typedef struct xlat_attrs { - const VALUE_PAIR_MAP *maps; + const value_pair_map_t *maps; const char *attrs[MAX_ATTRMAP]; } xlat_attrs_t; @@ -1320,76 +1321,6 @@ check_attr: return 0; } -/** Parse update section - * - * Verify that the ldap update section makes sense, and add attribute names - * to array of attributes for efficient querying later. - */ -static int build_attrmap(CONF_SECTION *cs, VALUE_PAIR_MAP **head) -{ - const char *cs_list, *p; - - request_refs_t request_def = REQUEST_CURRENT; - pair_lists_t list_def = PAIR_LIST_REQUEST; - - CONF_ITEM *ci = cf_sectiontoitem(cs); - CONF_PAIR *cp; - - unsigned int total = 0; - VALUE_PAIR_MAP **tail, *map; - *head = NULL; - tail = head; - - if (!cs) return 0; - - cs_list = p = cf_section_name2(cs); - if (cs_list) { - request_def = radius_request_name(&p, REQUEST_UNKNOWN); - if (request_def == REQUEST_UNKNOWN) { - cf_log_err(ci, "rlm_ldap: Default request specified " - "in mapping section is invalid"); - return -1; - } - - list_def = fr_str2int(pair_lists, p, PAIR_LIST_UNKNOWN); - if (list_def == PAIR_LIST_UNKNOWN) { - cf_log_err(ci, "rlm_ldap: Default list specified " - "in mapping section is invalid"); - return -1; - } - } - - for (ci = cf_item_find_next(cs, NULL); - ci != NULL; - ci = cf_item_find_next(cs, ci)) { - if (total++ == MAX_ATTRMAP) { - cf_log_err(ci, "rlm_ldap: Attribute map size exceeded"); - goto error; - } - - if (!cf_item_is_pair(ci)) { - cf_log_err(ci, "rlm_ldap: Entry is not in \"attribute =" - " ldap-attribute\" format"); - goto error; - } - - cp = cf_itemtopair(ci); - map = radius_cp2map(cp, REQUEST_CURRENT, list_def); - if (!map) { - goto error; - } - - *tail = map; - tail = &(map->next); - } - - return 0; - - error: - radius_mapfree(head); - return -1; -} - /** Detach from the LDAP server and cleanup internal state. * */ @@ -1531,7 +1462,8 @@ static int ldap_instantiate(CONF_SECTION * conf, void **instance) */ cs = cf_section_sub_find(conf, "update"); if (cs) { - if (build_attrmap(cs, &(inst->user_map)) < 0) { + if (radius_attrmap(cs, &(inst->user_map), PAIR_LIST_REPLY, + PAIR_LIST_REQUEST, MAX_ATTRMAP) < 0) { goto error; } } @@ -1618,7 +1550,7 @@ static int check_access(ldap_instance *inst, REQUEST* request, LDAP_CONN *conn, } -static VALUE_PAIR *ldap_getvalue(REQUEST *request, const VALUE_PAIR_TMPL *dst, +static VALUE_PAIR *ldap_getvalue(REQUEST *request, const value_pair_map_t *map, void *ctx) { rlm_ldap_result_t *self = ctx; @@ -1636,7 +1568,7 @@ static VALUE_PAIR *ldap_getvalue(REQUEST *request, const VALUE_PAIR_TMPL *dst, * just use whatever was set in the attribute map. */ for (i = 0; i < self->count; i++) { - vp = pairalloc(dst->da); + vp = pairalloc(map->dst->da); rad_assert(vp); pairparsevalue(vp, self->values[i]); @@ -1651,7 +1583,7 @@ static VALUE_PAIR *ldap_getvalue(REQUEST *request, const VALUE_PAIR_TMPL *dst, static void xlat_attrsfree(const xlat_attrs_t *expanded) { - const VALUE_PAIR_MAP *map; + const value_pair_map_t *map; unsigned int total = 0; const char *name; @@ -1668,10 +1600,10 @@ static void xlat_attrsfree(const xlat_attrs_t *expanded) } -static int xlat_attrs(REQUEST *request, const VALUE_PAIR_MAP *maps, +static int xlat_attrs(REQUEST *request, const value_pair_map_t *maps, xlat_attrs_t *expanded) { - const VALUE_PAIR_MAP *map; + const value_pair_map_t *map; unsigned int total = 0; size_t len; @@ -1720,7 +1652,7 @@ static void do_attrmap(UNUSED ldap_instance *inst, REQUEST *request, LDAP *handle, const xlat_attrs_t *expanded, LDAPMessage *entry) { - const VALUE_PAIR_MAP *map; + const value_pair_map_t *map; unsigned int total = 0; rlm_ldap_result_t result;