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);
#endif
}
+ RDEBUG("WARNING: Specified list \"%s\" is not available in "
+ "this context", fr_int2str(pair_lists, list, "¿unknown?"));
+
return NULL;
}
* 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:
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;
*
* @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;
*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.
* @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)
{
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.
* @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);
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;
}
*
* @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;
*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<request>.<list>.<attribute>@endverbatim reference and the right
- * operand as a module specific value.
+ * Treats the left operand as an attribute reference
+ * @verbatim<request>.<list>.<attribute>@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.
*
* @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;
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.
* @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);
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);
*/
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;
}
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;
}
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
} 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;
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.
*
*/
*/
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;
}
}
}
-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;
* 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]);
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;
}
-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;
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;