From: Arran Cudbard-Bell Date: Wed, 16 Jan 2013 14:30:08 +0000 (+0000) Subject: Switch to using explicit template types X-Git-Tag: release_3_0_0_beta1~1311 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1dd6e056b0ab6fcdc91e068e39288fa527059948;p=thirdparty%2Ffreeradius-server.git Switch to using explicit template types Add support for copying lists to rlm_cache Add more sanity checks to rlm_ldap and rlm_cache Reformat more code in rlm_ldap --- diff --git a/src/include/libradius.h b/src/include/libradius.h index c84ff64fc9f..c2eeeddba68 100644 --- a/src/include/libradius.h +++ b/src/include/libradius.h @@ -419,6 +419,7 @@ void pairadd(VALUE_PAIR **, VALUE_PAIR *); void pairreplace(VALUE_PAIR **first, VALUE_PAIR *add); int paircmp(VALUE_PAIR *check, VALUE_PAIR *data); VALUE_PAIR *paircopyvp(const VALUE_PAIR *vp); +VALUE_PAIR *paircopyvpdata(const DICT_ATTR *da, const VALUE_PAIR *vp); VALUE_PAIR *paircopy(VALUE_PAIR *vp); VALUE_PAIR *paircopy2(VALUE_PAIR *vp, unsigned int attr, unsigned int vendor, int8_t tag); void pairmove(VALUE_PAIR **to, VALUE_PAIR **from); diff --git a/src/include/radiusd.h b/src/include/radiusd.h index 1214a9003c6..8aa9b869a16 100644 --- a/src/include/radiusd.h +++ b/src/include/radiusd.h @@ -470,18 +470,20 @@ typedef struct main_config_t { /* for paircompare_register */ typedef int (*RAD_COMPARE_FUNC)(void *instance, REQUEST *,VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **); -typedef enum request_fail_t { - REQUEST_FAIL_UNKNOWN = 0, - REQUEST_FAIL_NO_THREADS, /* no threads to handle it */ - REQUEST_FAIL_DECODE, /* rad_decode didn't like it */ - REQUEST_FAIL_PROXY, /* call to proxy modules failed */ - REQUEST_FAIL_PROXY_SEND, /* proxy_send didn't like it */ - REQUEST_FAIL_NO_RESPONSE, /* we weren't told to respond, so we reject */ - REQUEST_FAIL_HOME_SERVER, /* the home server didn't respond */ - REQUEST_FAIL_HOME_SERVER2, /* another case of the above */ - REQUEST_FAIL_HOME_SERVER3, /* another case of the above */ - REQUEST_FAIL_NORMAL_REJECT, /* authentication failure */ - REQUEST_FAIL_SERVER_TIMEOUT /* the server took too long to process the request */ +typedef enum request_fail { + REQUEST_FAIL_UNKNOWN = 0, + REQUEST_FAIL_NO_THREADS, //!< No threads to handle it. + REQUEST_FAIL_DECODE, //!< Rad_decode didn't like it. + REQUEST_FAIL_PROXY, //!< Call to proxy modules failed. + REQUEST_FAIL_PROXY_SEND, //!< Proxy_send didn't like it. + REQUEST_FAIL_NO_RESPONSE, //!< We weren't told to respond, + //!< so we reject. + REQUEST_FAIL_HOME_SERVER, //!< The home server didn't respond. + REQUEST_FAIL_HOME_SERVER2, //!< Another case of the above. + REQUEST_FAIL_HOME_SERVER3, //!< Another case of the above. + REQUEST_FAIL_NORMAL_REJECT, //!< Authentication failure. + REQUEST_FAIL_SERVER_TIMEOUT //!< The server took too long to + //!< process the request. } request_fail_t; /* @@ -720,6 +722,18 @@ 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); + +typedef enum vpt_type { + VPT_TYPE_UNKNOWN = 0, + VPT_TYPE_LITERAL, //!< Is a literal string. + VPT_TYPE_XLAT, //!< Needs to be expanded. + VPT_TYPE_ATTR, //!< Is an attribute. + VPT_TYPE_LIST, //!< Is a list. + VPT_TYPE_EXEC //!< Needs to be executed. +} vpt_type_t; + +extern const FR_NAME_NUMBER vpt_types[]; + /** A pre-parsed template attribute * * Value pair template, used when processing various mappings sections @@ -737,9 +751,7 @@ typedef struct value_pair_tmpl_t { 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. + vpt_type_t type; //!< What type of value tmpl refers to. } value_pair_tmpl_t; /** Value pair map @@ -761,6 +773,10 @@ typedef struct value_pair_map { FR_TOKEN op; //!< The operator that controls //!< insertion of the dst attribute. + CONF_ITEM *ci; //!< Config item that the map was + //!< created from. Mainly used for + //!< logging validation errors. + struct value_pair_map *next; //!< The next valuepair map. } value_pair_map_t; diff --git a/src/lib/valuepair.c b/src/lib/valuepair.c index 3a13c709984..448df28a5d0 100644 --- a/src/lib/valuepair.c +++ b/src/lib/valuepair.c @@ -408,6 +408,43 @@ VALUE_PAIR *paircopyvp(const VALUE_PAIR *vp) return n; } +/** Copy data from one VP to another + * + * Allocate a new pair using da, and copy over the value from the specified + * vp. + * + * @todo Should be able to do type conversions. + * + * @param[in] da of new attribute to alloc. + * @param[in] vp to copy data from. + * @return the new valuepair. + */ +VALUE_PAIR *paircopyvpdata(const DICT_ATTR *da, const VALUE_PAIR *vp) +{ + VALUE_PAIR *n; + + if (!vp) return NULL; + + if (da->type != vp->type) return NULL; + + n = pairalloc(da); + if (!n) { + return NULL; + } + + memcpy(&(n->data), &(vp->data), sizeof(n->data)); + + n->length = vp->length; + + if ((n->type == PW_TYPE_TLV) && + (n->vp_tlv != NULL)) { + n->vp_tlv = malloc(n->length); + memcpy(n->vp_tlv, vp->vp_tlv, n->length); + } + + return n; +} + /** Copy matching pairs * diff --git a/src/main/valuepair.c b/src/main/valuepair.c index 49f64c817d4..5607caf1b59 100644 --- a/src/main/valuepair.c +++ b/src/main/valuepair.c @@ -80,6 +80,15 @@ const FR_NAME_NUMBER request_refs[] = { { NULL , -1 } }; +const FR_NAME_NUMBER vpt_types[] = { + {"unknown", VPT_TYPE_UNKNOWN }, + {"literal", VPT_TYPE_LITERAL }, + {"expanded", VPT_TYPE_XLAT }, + {"attribute ref", VPT_TYPE_ATTR }, + {"list", VPT_TYPE_LIST }, + {"exec", VPT_TYPE_EXEC } +}; + struct cmp { unsigned int attribute; unsigned int otherattr; @@ -988,7 +997,6 @@ pair_lists_t radius_list_name(const char **name, pair_lists_t unknown) * No colon was found and the first char was upper case * indicating an attribute. * - * This allows the function to be used to resolve list names too. */ q = strchr(p, ':'); if (((q && (q[1] >= '0') && (q[1] <= '9'))) || @@ -1148,13 +1156,21 @@ int radius_parse_attr(const char *name, value_pair_tmpl_t *vpt, return -1; } + if (*p == '\0') { + vpt->type = VPT_TYPE_LIST; + + return 0; + } + vpt->da = dict_attrbyname(p); if (!vpt->da) { radlog(L_ERR, "Attribute \"%s\" unknown", p); - + return -1; } + vpt->type = VPT_TYPE_ATTR; + return 0; } @@ -1204,12 +1220,14 @@ value_pair_tmpl_t *radius_str2tmpl(const char *name, FR_TOKEN type) { case T_BARE_WORD: case T_SINGLE_QUOTED_STRING: - vpt->do_xlat = FALSE; - break; - case T_BACK_QUOTED_STRING: + vpt->type = VPT_TYPE_LITERAL; + break; case T_DOUBLE_QUOTED_STRING: - vpt->do_xlat = TRUE; - break; + vpt->type = VPT_TYPE_XLAT; + break; + case T_BACK_QUOTED_STRING: + vpt->type = VPT_TYPE_EXEC; + break; default: rad_assert(0); return NULL; @@ -1275,13 +1293,16 @@ value_pair_map_t *radius_cp2map(CONF_PAIR *cp, 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(cf_pairtoitem(cp), "Missing attribute value"); + cf_log_err(ci, "Missing attribute value"); goto error; } @@ -1304,6 +1325,61 @@ value_pair_map_t *radius_cp2map(CONF_PAIR *cp, } 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; @@ -1316,7 +1392,7 @@ value_pair_map_t *radius_cp2map(CONF_PAIR *cp, * * Uses 'name2' of section to set default request and lists. * - * @param[in] cs to convert to map. + * @param[in] parent 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. @@ -1325,7 +1401,7 @@ value_pair_map_t *radius_cp2map(CONF_PAIR *cp, * @param[in] max number of mappings to process. * @return -1 on error, else 0. */ -int radius_attrmap(CONF_SECTION *cs, value_pair_map_t **head, +int radius_attrmap(CONF_SECTION *parent, value_pair_map_t **head, pair_lists_t dst_list_def, pair_lists_t src_list_def, unsigned int max) { @@ -1333,6 +1409,7 @@ int radius_attrmap(CONF_SECTION *cs, value_pair_map_t **head, request_refs_t request_def = REQUEST_CURRENT; + CONF_SECTION *cs; CONF_ITEM *ci = cf_sectiontoitem(cs); CONF_PAIR *cp; @@ -1341,6 +1418,9 @@ int radius_attrmap(CONF_SECTION *cs, value_pair_map_t **head, *head = NULL; tail = head; + if (!parent) return 0; + + cs = cf_section_sub_find(parent, "update"); if (!cs) return 0; cs_list = p = cf_section_name2(cs); @@ -1396,7 +1476,7 @@ int radius_attrmap(CONF_SECTION *cs, value_pair_map_t **head, /** Convert value_pair_map_t to VALUE_PAIR(s) and add them to a REQUEST. * * Takes a single value_pair_map_t, resolves request and list identifiers - * to pointers in the current request, the attempts to retrieve module + * to pointers in the current request, then attempts to retrieve module * specific value(s) using callback, and adds the resulting values to the * correct request/list. * @@ -1487,10 +1567,24 @@ int radius_get_vp(REQUEST *request, const char *name, VALUE_PAIR **vp_p) return 0; } + switch (vpt.type) + { /* * May not may not be found, but it *is* a known name. */ - *vp_p = pairfind(*vps, vpt.da->attr, vpt.da->vendor, TAG_ANY); - + case VPT_TYPE_ATTR: + *vp_p = pairfind(*vps, vpt.da->attr, vpt.da->vendor, TAG_ANY); + break; + + case VPT_TYPE_LIST: + *vp_p = *vps; + break; + + default: + rad_assert(0); + return -1; + break; + } + return 0; } diff --git a/src/modules/rlm_cache/rlm_cache.c b/src/modules/rlm_cache/rlm_cache.c index d7bb9df3596..4b7b0cbf512 100644 --- a/src/modules/rlm_cache/rlm_cache.c +++ b/src/modules/rlm_cache/rlm_cache.c @@ -133,7 +133,7 @@ static void cache_merge(rlm_cache_t *inst, REQUEST *request, if (c->request && request->packet) { RDEBUG2("Merging cached request list:"); - rdebug_pair_list(2, request, c->control); + rdebug_pair_list(2, request, c->request); vp = paircopy(c->request); pairmove(&request->packet->vps, &vp); @@ -142,7 +142,7 @@ static void cache_merge(rlm_cache_t *inst, REQUEST *request, if (c->reply && request->reply) { RDEBUG2("Merging cached reply list:"); - rdebug_pair_list(2, request, c->control); + rdebug_pair_list(2, request, c->reply); vp = paircopy(c->reply); pairmove(&request->reply->vps, &vp); @@ -273,7 +273,6 @@ static rlm_cache_entry_t *cache_add(rlm_cache_t *inst, REQUEST *request, for (map = inst->maps; map != NULL; map = map->next) { rad_assert(map->dst && map->src); - rad_assert(map->dst->da); /* * Specifying inner/outer request doesn't work here @@ -299,14 +298,17 @@ static rlm_cache_entry_t *cache_add(rlm_cache_t *inst, REQUEST *request, /* * Resolve the destination in the current request. - * We need to add the to_cache there too if any of these are + * We need to add the to_cache there too if any of these + * are. * true : * - Map specifies an xlat'd string. * - Map specifies a literal string. * - Map src and dst lists differ. + * - Map src and dst attributes differ */ - from = NULL; - if (!map->src->da || (map->src->list != map->dst->list)) + to_req = NULL; + if (!map->src->da || (map->src->list != map->dst->list) || + (map->src->da != map->dst->da)) { context = request; /* @@ -323,15 +325,22 @@ static rlm_cache_entry_t *cache_add(rlm_cache_t *inst, REQUEST *request, * We infer that src was an attribute ref from the fact * it contains a da. */ - da = map->src->da; - if (da) { + RDEBUG4(":: dst is \"%s\" src is \"%s\"", + fr_int2str(vpt_types, map->dst->type, "¿unknown?"), + fr_int2str(vpt_types, map->src->type, "¿unknown?")); + + switch (map->src->type) + { + case VPT_TYPE_ATTR: + from = NULL; + da = map->src->da; context = request; if (radius_request(&context, map->src->request) == 0) { from = radius_list(context, map->src->list); } /* - * Can't add this attribute if the list isn't + * Can't add the attribute if the list isn't * valid. */ if (!from) continue; @@ -351,14 +360,28 @@ static rlm_cache_entry_t *cache_add(rlm_cache_t *inst, REQUEST *request, case T_OP_SET: case T_OP_EQ: case T_OP_SUB: - vp = paircopyvp(found); - vp->operator = map->op; + vp = map->dst->type == VPT_TYPE_LIST ? + paircopyvp(found) : + paircopyvpdata(map->dst->da, found); + + if (!vp) continue; + pairadd(to_cache, vp); + + if (to_req) { + vp = paircopyvp(vp); + radius_pairmove(request, to_req, vp); + } break; case T_OP_ADD: do { - vp = paircopyvp(found); + vp = map->dst->type == VPT_TYPE_LIST ? + paircopyvp(found) : + paircopyvpdata(map->dst->da, + found); + if (!vp) continue; + vp->operator = map->op; pairadd(to_cache, vp); @@ -381,11 +404,42 @@ static rlm_cache_entry_t *cache_add(rlm_cache_t *inst, REQUEST *request, rad_assert(0); return NULL; } + break; + case VPT_TYPE_LIST: + rad_assert(map->src->type == VPT_TYPE_LIST); + + from = NULL; + context = request; + if (radius_request(&context, map->src->request) == 0) { + from = radius_list(context, map->src->list); + } + if (!from) continue; + + found = paircopy(*from); + if (!found) continue; + + for (vp = found; vp != NULL; vp = vp->next) { + RDEBUG("\t%s%s %s %s%s", map->dst->name, + vp->name, + fr_int2str(fr_tokens, map->op, "¿unknown?"), + map->src->name, + vp->name); + vp->operator = map->op; + } + + pairadd(to_cache, found); + + if (to_req) { + vp = paircopy(found); + radius_pairmove(request, to_req, vp); + } + + break; /* * It was most likely a double quoted string that now * needs to be expanded. */ - } else if (map->src->do_xlat) { + case VPT_TYPE_XLAT: if (radius_xlat(buffer, sizeof(buffer), map->src->name, request, NULL, NULL) <= 0) { continue; @@ -413,7 +467,7 @@ static rlm_cache_entry_t *cache_add(rlm_cache_t *inst, REQUEST *request, /* * Literal string. */ - } else { + case VPT_TYPE_LITERAL: RDEBUG("\t%s %s '%s'", map->dst->name, fr_int2str(fr_tokens, map->op, "¿unknown?"), map->src->name); @@ -433,6 +487,10 @@ static rlm_cache_entry_t *cache_add(rlm_cache_t *inst, REQUEST *request, } break; + + default: + rad_assert(0); + return NULL; } } @@ -458,54 +516,61 @@ static rlm_cache_entry_t *cache_add(rlm_cache_t *inst, REQUEST *request, */ static int cache_verify(rlm_cache_t *inst, value_pair_map_t **head) { - CONF_ITEM *ci; - CONF_PAIR *cp; - FR_TOKEN op; - FR_TOKEN type; - - for (ci = cf_item_find_next(inst->cs, NULL); - ci != NULL; - ci = cf_item_find_next(inst->cs, ci)) { - cp = cf_itemtopair(ci); - type = cf_pair_value_type(cp); - op = cf_pair_operator(cp); - - switch (type) { - case T_BARE_WORD: - switch (op) { + value_pair_map_t *map; + + if (radius_attrmap(inst->cs, head, PAIR_LIST_REQUEST, + PAIR_LIST_REQUEST, MAX_ATTRMAP) < 0) { + return -1; + } + + if (!*head) { + cf_log_err(cf_sectiontoitem(inst->cs), + "Cache config must contain an update section, and " + "that section must not be empty"); + + return -1; + } + + for (map = *head; map != NULL; map = map->next) { + + if ((map->dst->type != VPT_TYPE_ATTR) && + (map->dst->type != VPT_TYPE_LIST)) { + cf_log_err(map->ci, "Left operand must be an attribute " + "ref or a list"); + + return -1; + } + + switch (map->src->type) + { + /* + * Only =, :=, += and -= operators are supported for + * cache entries. + */ + case VPT_TYPE_LITERAL: + case VPT_TYPE_XLAT: + case VPT_TYPE_ATTR: + switch (map->op) { case T_OP_SET: case T_OP_EQ: case T_OP_SUB: case T_OP_ADD: break; - + default: - cf_log_err(ci, "Operator \"%s\" not " - "allowed for attribute references", - fr_int2str(fr_tokens, op, - "¿unknown?")); + cf_log_err(map->ci, "Operator \"%s\" not " + "allowed for %s values", + fr_int2str(fr_tokens, map->op, + "¿unknown?"), + fr_int2str(vpt_types, map->src->type, + "¿unknown?")); return -1; } - - break; - case T_SINGLE_QUOTED_STRING: - case T_DOUBLE_QUOTED_STRING: - break; - default: - cf_log_err(ci, "Unsupported value type \"%s\"", - fr_int2str(fr_tokens, type, "¿unknown?")); - return -1; + break; } } - - /* - * We end up iterating over the entire section twice, but this - * is only done on instantiate so it's not really that much of an - * issue. - */ - return radius_attrmap(inst->cs, head, PAIR_LIST_REQUEST, - PAIR_LIST_REQUEST, MAX_ATTRMAP); + return 0; } /* @@ -525,6 +590,14 @@ static size_t cache_xlat(void *instance, REQUEST *request, radius_xlat(buffer, sizeof(buffer), inst->key, request, NULL, NULL); + list = radius_list_name(&p, PAIR_LIST_REQUEST); + + target = dict_attrbyname(p); + if (!target) { + radlog(L_ERR, "rlm_cache: Unknown attribute \"%s\"", p); + return -1; + } + PTHREAD_MUTEX_LOCK(&inst->cache_mutex); c = cache_find(inst, request, buffer); @@ -532,8 +605,7 @@ static size_t cache_xlat(void *instance, REQUEST *request, RDEBUG("No cache entry for key \"%s\"", buffer); goto done; } - - list = radius_list_name(&p, PAIR_LIST_REQUEST); + switch (list) { case PAIR_LIST_REQUEST: vps = c->request; @@ -556,13 +628,7 @@ static size_t cache_xlat(void *instance, REQUEST *request, fr_int2str(pair_lists, list, "¿Unknown?")); return 0; } - - target = dict_attrbyname(p); - if (!target) { - radlog(L_ERR, "rlm_cache: Unknown attribute \"%s\"", p); - goto done; - } - + vp = pairfind(vps, target->attr, target->vendor, TAG_ANY); if (!vp) { RDEBUG("No instance of this attribute has been cached"); @@ -630,12 +696,8 @@ static int cache_instantiate(CONF_SECTION *conf, void **instance) const char *xlat_name; rlm_cache_t *inst; - inst = rad_malloc(sizeof(*inst)); - if (!inst) { - return -1; - } - memset(inst, 0, sizeof(*inst)); - + inst = rad_calloc(sizeof(*inst)); + inst->cs = conf; /* * If the configuration parameters can't be parsed, then * fail. @@ -704,14 +766,6 @@ static int cache_instantiate(CONF_SECTION *conf, void **instance) cache_detach(inst); return -1; } - - - inst->cs = cf_section_sub_find(conf, "update"); - if (!inst->cs) { - radlog(L_ERR, "rlm_cache: Failed to find \"update\" subsection"); - cache_detach(inst); - return -1; - } /* * Make sure the users don't screw up too badly. diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index e2d48510705..99953d3e3a0 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -1376,6 +1376,65 @@ static int parse_sub_section(CONF_SECTION *parent, return 0; } +static int ldap_map_verify(ldap_instance *inst, value_pair_map_t **head) +{ + value_pair_map_t *map; + + if (radius_attrmap(inst->cs, head, PAIR_LIST_REPLY, + PAIR_LIST_REQUEST, MAX_ATTRMAP) < 0) { + return -1; + } + /* + * Attrmap only performs some basic validation checks, we need + * to do rlm_cache specific checks here. + */ + for (map = *head; map != NULL; map = map->next) { + if (map->dst->type != VPT_TYPE_ATTR) { + cf_log_err(map->ci, "Left operand must be an " + "attribute ref"); + + return -1; + } + + if (map->src->type == VPT_TYPE_LIST) { + cf_log_err(map->ci, "Right operand must not be " + "a list"); + + return -1; + } + + switch (map->src->type) + { + /* + * Only =, :=, += and -= operators are supported for + * cache entries. + */ + case VPT_TYPE_LITERAL: + case VPT_TYPE_XLAT: + case VPT_TYPE_ATTR: + switch (map->op) { + case T_OP_SET: + case T_OP_EQ: + case T_OP_SUB: + case T_OP_ADD: + break; + + default: + cf_log_err(map->ci, "Operator \"%s\" not " + "allowed for %s values", + fr_int2str(fr_tokens, map->op, + "¿unknown?"), + fr_int2str(vpt_types, map->src->type, + "¿unknown?")); + return -1; + } + default: + break; + } + } + return 0; +} + /** Parses config * Uses section of radiusd config file passed as parameter to create an * instance of the module. @@ -1383,7 +1442,6 @@ static int parse_sub_section(CONF_SECTION *parent, static int ldap_instantiate(CONF_SECTION * conf, void **instance) { ldap_instance *inst; - CONF_SECTION *cs; inst = rad_calloc(sizeof *inst); inst->cs = conf; @@ -1460,12 +1518,8 @@ static int ldap_instantiate(CONF_SECTION * conf, void **instance) /* * Build the attribute map */ - cs = cf_section_sub_find(conf, "update"); - if (cs) { - if (radius_attrmap(cs, &(inst->user_map), PAIR_LIST_REPLY, - PAIR_LIST_REQUEST, MAX_ATTRMAP) < 0) { - goto error; - } + if (ldap_map_verify(inst, &(inst->user_map)) < 0) { + goto error; } /* @@ -1593,8 +1647,14 @@ static void xlat_attrsfree(const xlat_attrs_t *expanded) name = expanded->attrs[total++]; if (!name) return; - if (map->src->do_xlat) { + switch (map->src->type) + { + case VPT_TYPE_XLAT: + case VPT_TYPE_ATTR: rad_cfree(name); + break; + default: + break; } } } @@ -1609,28 +1669,59 @@ static int xlat_attrs(REQUEST *request, const value_pair_map_t *maps, size_t len; char *buffer; + VALUE_PAIR *found, **from = NULL; + REQUEST *context; + for (map = maps; map != NULL; map = map->next) { - if (map->src->do_xlat) { + switch (map->src->type) + { + case VPT_TYPE_XLAT: buffer = rad_malloc(MAX_ATTR_STR_LEN); len = radius_xlat(buffer, MAX_ATTR_STR_LEN, map->src->name, request, NULL, NULL); - if (!len) { + if (len <= 0) { RDEBUG("Expansion of LDAP attribute " "\"%s\" failed", map->src->name); - expanded->attrs[total] = NULL; - - xlat_attrsfree(expanded); - - return -1; + goto error; } expanded->attrs[total++] = buffer; - } else { + break; + + case VPT_TYPE_ATTR: + context = request; + + if (radius_request(&context, map->src->request) == 0) { + from = radius_list(context, map->src->list); + } + if (!from) continue; + + found = pairfind(*from, map->src->da->attr, + map->src->da->vendor, TAG_ANY); + if (!found) continue; + + buffer = rad_malloc(MAX_ATTR_STR_LEN); + strlcpy(buffer, found->vp_strvalue, MAX_ATTR_STR_LEN); + + expanded->attrs[total++] = buffer; + break; + + case VPT_TYPE_LITERAL: expanded->attrs[total++] = map->src->name; + break; + default: + rad_assert(0); + error: + expanded->attrs[total] = NULL; + + xlat_attrsfree(expanded); + + return -1; } + } expanded->attrs[total] = NULL; @@ -1701,14 +1792,14 @@ static void do_check_reply(ldap_instance *inst, REQUEST *request) */ if (inst->expect_password && (debug_flag > 1)) { if (!pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY) && - !pairfind(request->config_items, PW_NT_PASSWORD, 0, TAG_ANY) && - !pairfind(request->config_items, PW_USER_PASSWORD, 0, TAG_ANY) && - !pairfind(request->config_items, PW_PASSWORD_WITH_HEADER, 0, TAG_ANY) && - !pairfind(request->config_items, PW_CRYPT_PASSWORD, 0, TAG_ANY)) { - RDEBUG("WARNING: No \"known good\" password " - "was found in LDAP. Are you sure that " - "the user is configured correctly?"); - } + !pairfind(request->config_items, PW_NT_PASSWORD, 0, TAG_ANY) && + !pairfind(request->config_items, PW_USER_PASSWORD, 0, TAG_ANY) && + !pairfind(request->config_items, PW_PASSWORD_WITH_HEADER, 0, TAG_ANY) && + !pairfind(request->config_items, PW_CRYPT_PASSWORD, 0, TAG_ANY)) { + RDEBUG("WARNING: No \"known good\" password " + "was found in LDAP. Are you sure that " + "the user is configured correctly?"); + } } } @@ -2179,10 +2270,7 @@ static rlm_rcode_t user_modify(ldap_instance *inst, REQUEST *request, passed[last_pass] = NULL; } else if (do_xlat) { p = rad_malloc(1024); - radius_xlat(p, 1024, value, request, NULL, NULL); - - if (*p == '\0') { - + if (radius_xlat(p, 1024, value, request, NULL, NULL) <= 0) { RDEBUG("xlat failed or empty value string, " "skipping attribute \"%s\"", attr); @@ -2209,32 +2297,35 @@ static rlm_rcode_t user_modify(ldap_instance *inst, REQUEST *request, switch (op) { - /* - * T_OP_EQ is *NOT* supported, it is impossible to - * support because of the lack of transactions in LDAP - */ - case T_OP_ADD: - mod_s[total].mod_op = LDAP_MOD_ADD; + /* + * T_OP_EQ is *NOT* supported, it is impossible to + * support because of the lack of transactions in LDAP + */ + case T_OP_ADD: + mod_s[total].mod_op = LDAP_MOD_ADD; break; - case T_OP_SET: - mod_s[total].mod_op = LDAP_MOD_REPLACE; + + case T_OP_SET: + mod_s[total].mod_op = LDAP_MOD_REPLACE; break; - case T_OP_SUB: - case T_OP_CMP_FALSE: - mod_s[total].mod_op = LDAP_MOD_DELETE; + + case T_OP_SUB: + case T_OP_CMP_FALSE: + mod_s[total].mod_op = LDAP_MOD_DELETE; break; + #ifdef LDAP_MOD_INCREMENT - case T_OP_INCRM: - mod_s[total].mod_op = LDAP_MOD_INCREMENT; + case T_OP_INCRM: + mod_s[total].mod_op = LDAP_MOD_INCREMENT; break; #endif - default: - radlog(L_ERR, "rlm_ldap (%s): Operator '%s' " - "is not supported for LDAP modify " - "operations", inst->xlat_name, - fr_int2str(fr_tokens, op, "¿unknown?")); - - goto error; + default: + radlog(L_ERR, "rlm_ldap (%s): Operator '%s' " + "is not supported for LDAP modify " + "operations", inst->xlat_name, + fr_int2str(fr_tokens, op, "¿unknown?")); + + goto error; } /* @@ -2262,9 +2353,8 @@ static rlm_rcode_t user_modify(ldap_instance *inst, REQUEST *request, * Perform all modifications as the default admin user. */ if (conn->rebound) { - ldap_errno = ldap_bind_wrapper(&conn, - inst->login, inst->password, - TRUE); + ldap_errno = ldap_bind_wrapper(&conn, inst->login, + inst->password, TRUE); if (ldap_errno != RLM_MODULE_OK) { goto error; }