]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Switch to using explicit template types
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 16 Jan 2013 14:30:08 +0000 (14:30 +0000)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 16 Jan 2013 14:30:08 +0000 (14:30 +0000)
Add support for copying lists to rlm_cache

Add more sanity checks to rlm_ldap and rlm_cache

Reformat more code in rlm_ldap

src/include/libradius.h
src/include/radiusd.h
src/lib/valuepair.c
src/main/valuepair.c
src/modules/rlm_cache/rlm_cache.c
src/modules/rlm_ldap/rlm_ldap.c

index c84ff64fc9f612a4cb78900a21608942d0bf830b..c2eeeddba68f3d8f370399a9f187eb8510d2e57f 100644 (file)
@@ -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);
index 1214a9003c63b5746ccb1d4be2e15ccad2476c67..8aa9b869a16b35697f00ceb8706a7ee4c285ce1f 100644 (file)
@@ -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;
 
index 3a13c70998496c54ed8aa3303a2ebf4c2b2df863..448df28a5d0ae39a76e89ab25942910ef98d3005 100644 (file)
@@ -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
  *
index 49f64c817d401080547135e4e89472ab6296e24a..5607caf1b59d988edbe0c5a67b1b15f9ef65a790 100644 (file)
@@ -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;
 }
index d7bb9df3596cf946852b1ae5bdf209c4d6c1f659..4b7b0cbf51290265df577f84aba17fe9631f51be 100644 (file)
@@ -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.
index e2d4851070550ac7237bf8919f54180b32c965d3..99953d3e3a0817acfd8210004dc1ef46c62a8a92 100644 (file)
@@ -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;
                }