Signed / unsigned fixes and function prototypes
[freeradius.git] / src / lib / valuepair.c
index d6380c3..57fe9a2 100644 (file)
 #include <freeradius-devel/ident.h>
 RCSID("$Id$")
 
-#include       <freeradius-devel/autoconf.h>
-
-#include       <sys/types.h>
+#include       <freeradius-devel/libradius.h>
 
-#include       <stdio.h>
-#include       <stdlib.h>
-#include       <string.h>
 #include       <ctype.h>
 
 #ifdef HAVE_MALLOC_H
@@ -40,52 +35,59 @@ RCSID("$Id$")
 #  include     <regex.h>
 #endif
 
-#include       <freeradius-devel/missing.h>
-#include       <freeradius-devel/libradius.h>
-
 static const char *months[] = {
         "jan", "feb", "mar", "apr", "may", "jun",
         "jul", "aug", "sep", "oct", "nov", "dec" };
 
-
 /*
- *     Create a new valuepair.
+ *     This padding is necessary only for attributes that are NOT
+ *     in the dictionary, and then only because the rest of the
+ *     code accesses vp->name directly, rather than through an
+ *     accessor function.
+ *
+ *     The name padding only has to large enough for:
+ *
+ *             Vendor-65535-Attr-65535
+ *
+ *     i.e. 23 characters, plus a zero.  We add another 8 bytes for
+ *     padding, because the VALUE_PAIR structure may be un-aligned.
+ *
+ *     The result is that for the normal case, the server uses a less
+ *     memory (36 bytes * number of VALUE_PAIRs).
  */
-VALUE_PAIR *paircreate(int attr, int type)
-{
-       VALUE_PAIR      *vp;
-       DICT_ATTR       *da;
+#define FR_VP_NAME_PAD (32)
+#define FR_VP_NAME_LEN (24)
 
-       if ((vp = malloc(sizeof(VALUE_PAIR))) == NULL) {
-               librad_log("out of memory");
-               return NULL;
-       }
-       memset(vp, 0, sizeof(VALUE_PAIR));
-       vp->attribute = attr;
-       vp->operator = T_OP_EQ;
-       vp->type = type;
+VALUE_PAIR *pairalloc(DICT_ATTR *da)
+{
+       size_t name_len = 0;
+       VALUE_PAIR *vp;
 
        /*
-        *      Dictionary type over-rides what the caller says.
+        *      Not in the dictionary: the name is allocated AFTER
+        *      the VALUE_PAIR struct.
         */
-       if ((da = dict_attrbyvalue(attr)) != NULL) {
-               strcpy(vp->name, da->name);
+       if (!da) name_len = FR_VP_NAME_PAD;
+
+       vp = malloc(sizeof(*vp) + name_len);
+       if (!vp) return NULL;
+       memset(vp, 0, sizeof(*vp));
+
+       if (da) {
+               vp->attribute = da->attr;
+               vp->vendor = da->vendor;
                vp->type = da->type;
+               vp->name = da->name;
                vp->flags = da->flags;
-       } else if (VENDOR(attr) == 0) {
-               sprintf(vp->name, "Attr-%u", attr);
        } else {
-               DICT_VENDOR *v;
-
-               v = dict_vendorbyvalue(VENDOR(attr));
-               if (v) {
-                       sprintf(vp->name, "%s-Attr-%u",
-                               v->name, attr & 0xffff);
-               } else {
-                       sprintf(vp->name, "Vendor-%u-Attr-%u",
-                               VENDOR(attr), attr & 0xffff);
-               }
+               vp->attribute = 0;
+               vp->vendor = 0;
+               vp->type = PW_TYPE_OCTETS;
+               vp->name = NULL;
+               memset(&vp->flags, 0, sizeof(vp->flags));
+               vp->flags.unknown_attr = 1;
        }
+
        switch (vp->type) {
                case PW_TYPE_BYTE:
                        vp->length = 1;
@@ -98,6 +100,7 @@ VALUE_PAIR *paircreate(int attr, int type)
                case PW_TYPE_INTEGER:
                case PW_TYPE_IPADDR:
                case PW_TYPE_DATE:
+               case PW_TYPE_SIGNED:
                        vp->length = 4;
                        break;
 
@@ -113,6 +116,16 @@ VALUE_PAIR *paircreate(int attr, int type)
                        vp->length = sizeof(vp->vp_ipv6prefix);
                        break;
 
+               case PW_TYPE_ETHERNET:
+                       vp->length = sizeof(vp->vp_ether);
+                       break;
+
+               case PW_TYPE_TLV:
+                       vp->vp_tlv = NULL;
+                       vp->length = 0;
+                       break;
+
+               case PW_TYPE_COMBO_IP:
                default:
                        vp->length = 0;
                        break;
@@ -122,11 +135,64 @@ VALUE_PAIR *paircreate(int attr, int type)
 }
 
 /*
+ *     Create a new valuepair.
+ */
+VALUE_PAIR *paircreate_raw(int attr, int vendor, int type, VALUE_PAIR *vp)
+{
+       char *p = (char *) (vp + 1);
+
+       if (!vp->flags.unknown_attr) {
+               pairfree(&vp);
+               return NULL;
+       }
+
+       vp->vendor = vendor;
+       vp->attribute = attr;
+       vp->operator = T_OP_EQ;
+       vp->name = p;
+       vp->type = type;
+       vp->length = 0;
+       memset(&vp->flags, 0, sizeof(vp->flags));
+       vp->flags.unknown_attr = 1;
+       
+       if (!vp_print_name(p, FR_VP_NAME_LEN, vp->attribute, vp->vendor)) {
+               free(vp);
+               return NULL;
+       }
+
+       return vp;
+}
+
+/*
+ *     Create a new valuepair.
+ */
+VALUE_PAIR *paircreate(int attr, int vendor, int type)
+{
+       VALUE_PAIR      *vp;
+       DICT_ATTR       *da;
+
+       da = dict_attrbyvalue(attr, vendor);
+       if ((vp = pairalloc(da)) == NULL) {
+               fr_strerror_printf("out of memory");
+               return NULL;
+       }
+       vp->operator = T_OP_EQ;
+
+       /*
+        *      It isn't in the dictionary: update the name.
+        */
+       if (!da) return paircreate_raw(attr, vendor, type, vp);
+
+       return vp;
+}
+
+/*
  *      release the memory used by a single attribute-value pair
  *      just a wrapper around free() for now.
  */
 void pairbasicfree(VALUE_PAIR *pair)
 {
+       if (pair->type == PW_TYPE_TLV) free(pair->vp_tlv);
        /* clear the memory here */
        memset(pair, 0, sizeof(*pair));
        free(pair);
@@ -156,25 +222,30 @@ void pairfree(VALUE_PAIR **pair_ptr)
 /*
  *     Find the pair with the matching attribute
  */
-VALUE_PAIR * pairfind(VALUE_PAIR *first, int attr)
+VALUE_PAIR * pairfind(VALUE_PAIR *first, unsigned int attr, unsigned int vendor)
 {
-       while(first && first->attribute != attr)
+       while (first) {
+               if ((first->attribute == attr) && (first->vendor == vendor)) {
+                       return first;
+               }
                first = first->next;
-       return first;
+       }
+
+       return NULL;
 }
 
 
 /*
  *     Delete the pair(s) with the matching attribute
  */
-void pairdelete(VALUE_PAIR **first, int attr)
+void pairdelete(VALUE_PAIR **first, unsigned int attr, unsigned int vendor)
 {
        VALUE_PAIR *i, *next;
        VALUE_PAIR **last = first;
 
        for(i = *first; i; i = next) {
                next = i->next;
-               if (i->attribute == attr) {
+               if ((i->attribute == attr) && (i->vendor == vendor)) {
                        *last = next;
                        pairbasicfree(i);
                } else {
@@ -226,7 +297,8 @@ void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace)
                 *      Found the first attribute, replace it,
                 *      and return.
                 */
-               if (i->attribute == replace->attribute) {
+               if ((i->attribute == replace->attribute) &&
+                   (i->vendor == replace->vendor)) {
                        *prev = replace;
 
                        /*
@@ -250,10 +322,49 @@ void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace)
        *prev = replace;
 }
 
+
+/*
+ *     Copy just one VP.
+ */
+VALUE_PAIR *paircopyvp(const VALUE_PAIR *vp)
+{
+       size_t name_len;
+       VALUE_PAIR *n;
+       
+       if (!vp->flags.unknown_attr) {
+               name_len = 0;
+       } else {
+               name_len = FR_VP_NAME_PAD;
+       }
+       
+       if ((n = malloc(sizeof(*n) + name_len)) == NULL) {
+               fr_strerror_printf("out of memory");
+               return NULL;
+       }
+       memcpy(n, vp, sizeof(*n) + name_len);
+
+       /*
+        *      Reset the name field to point to the NEW attribute,
+        *      rather than to the OLD one.
+        */
+       if (vp->flags.unknown_attr) n->name = (char *) (n + 1);
+
+       n->next = NULL;
+
+       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 just a certain type of pairs.
  */
-VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr)
+VALUE_PAIR *paircopy2(VALUE_PAIR *vp, unsigned int attr, unsigned int vendor)
 {
        VALUE_PAIR      *first, *n, **last;
 
@@ -261,16 +372,14 @@ VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr)
        last = &first;
 
        while (vp) {
-               if (attr >= 0 && vp->attribute != attr) {
+               if ((attr > 0) &&
+                   !((vp->attribute == attr) && (vp->vendor == vendor))) {
                        vp = vp->next;
                        continue;
                }
-               if ((n = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
-                       librad_log("out of memory");
-                       return first;
-               }
-               memcpy(n, vp, sizeof(VALUE_PAIR));
-               n->next = NULL;
+
+               n = paircopyvp(vp);
+               if (!n) return first;
                *last = n;
                last = &n->next;
                vp = vp->next;
@@ -284,7 +393,7 @@ VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr)
  */
 VALUE_PAIR *paircopy(VALUE_PAIR *vp)
 {
-       return paircopy2(vp, -1);
+       return paircopy2(vp, 0, 0);
 }
 
 
@@ -359,7 +468,7 @@ void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
                if (i->attribute == PW_FALL_THROUGH ||
                    (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) {
 
-                       found = pairfind(*to, i->attribute);
+                       found = pairfind(*to, i->attribute, i->vendor);
                        switch (i->operator) {
 
                          /*
@@ -371,7 +480,7 @@ void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
                                        if (!i->vp_strvalue[0] ||
                                            (strcmp((char *)found->vp_strvalue,
                                                    (char *)i->vp_strvalue) == 0)){
-                                               pairdelete(to, found->attribute);
+                                               pairdelete(to, found->attribute, found->vendor);
 
                                                /*
                                                 *      'tailto' may have been
@@ -466,7 +575,7 @@ void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
                                        memcpy(found, i, sizeof(*found));
                                        found->next = mynext;
 
-                                       pairdelete(&found->next, found->attribute);
+                                       pairdelete(&found->next, found->attribute, found->vendor);
 
                                        /*
                                         *      'tailto' may have been
@@ -512,7 +621,7 @@ void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
 /*
  *     Move one kind of attributes from one list to the other
  */
-void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr)
+void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, unsigned int attr, unsigned int vendor)
 {
        VALUE_PAIR *to_tail, *i, *next;
        VALUE_PAIR *iprev = NULL;
@@ -530,27 +639,37 @@ void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr)
        for(i = *from; i; i = next) {
                next = i->next;
 
-
                /*
-                *      If the attribute to move is NOT a VSA, then it
-                *      ignores any attributes which do not match exactly.
+                *      vendor=0, attr = PW_VENDOR_SPECIFIC means
+                *      "match any vendor attribute".
                 */
-               if ((attr != PW_VENDOR_SPECIFIC) &&
-                   (i->attribute != attr)) {
+               if ((vendor == 0) && (attr == PW_VENDOR_SPECIFIC)) {
+                       /*
+                        *      It's a VSA: move it over.
+                        */
+                       if (i->vendor != 0) goto move;
+
+                       /*
+                        *      It's Vendor-Specific: move it over.
+                        */
+                       if (i->attribute == attr) goto move;
+
+                       /*
+                        *      It's not a VSA: ignore it.
+                        */
                        iprev = i;
                        continue;
                }
 
                /*
-                *      If the attribute to move IS a VSA, then it ignores
-                *      any non-VSA attribute.
+                *      If it isn't an exact match, ignore it.
                 */
-               if ((attr == PW_VENDOR_SPECIFIC) &&
-                   (VENDOR(i->attribute) == 0)) {
+               if (!((i->vendor == vendor) && (i->attribute == attr))) {
                        iprev = i;
                        continue;
                }
 
+       move:
                /*
                 *      Remove the attribute from the "from" list.
                 */
@@ -597,7 +716,7 @@ static char *mystrtok(char **ptr, const char *sep)
  *     Turn printable string into time_t
  *     Returns -1 on error, 0 on OK.
  */
-static int gettime(const char *valstr, time_t *lvalue)
+static int gettime(const char *valstr, time_t *date)
 {
        int             i;
        time_t          t;
@@ -610,7 +729,7 @@ static int gettime(const char *valstr, time_t *lvalue)
        /*
         * Test for unix timestamp date
         */
-       *lvalue = strtoul(valstr, &tail, 10);
+       *date = strtoul(valstr, &tail, 10);
        if (*tail == '\0') {
                return 0;
        }
@@ -619,7 +738,7 @@ static int gettime(const char *valstr, time_t *lvalue)
        memset(tm, 0, sizeof(*tm));
        tm->tm_isdst = -1;      /* don't know, and don't care about DST */
 
-       strNcpy(buf, valstr, sizeof(buf));
+       strlcpy(buf, valstr, sizeof(buf));
 
        p = buf;
        f[0] = mystrtok(&p, " \t");
@@ -712,13 +831,11 @@ static int gettime(const char *valstr, time_t *lvalue)
                f[2] = strchr(f[1], ':'); /* find : separator */
                if (f[2]) {
                  *(f[2]++) = '\0';     /* nuke it, and point to SS */
-               } else {
-                 strcpy(f[2], "0");    /* assignment would discard const */
-               }
+                 tm->tm_sec = atoi(f[2]);
+               }                       /* else leave it as zero */
 
                tm->tm_hour = atoi(f[0]);
                tm->tm_min = atoi(f[1]);
-               tm->tm_sec = atoi(f[2]);
        }
 
        /*
@@ -727,11 +844,12 @@ static int gettime(const char *valstr, time_t *lvalue)
        t = mktime(tm);
        if (t == (time_t) -1) return -1;
 
-       *lvalue = t;
+       *date = t;
 
        return 0;
 }
 
+static const char *hextab = "0123456789abcdef";
 
 /*
  *  Parse a string value into a given VALUE_PAIR
@@ -741,24 +859,109 @@ static int gettime(const char *valstr, time_t *lvalue)
  *  double-check the parsed value, to be sure it's legal for that
  *  type (length, etc.)
  */
+static uint32_t getint(const char *value, char **end)
+{
+       if ((value[0] == '0') && (value[1] == 'x')) {
+               return strtoul(value, end, 16);
+       }
+
+       return strtoul(value, end, 10);
+}
+
+static int check_for_whitespace(const char *value)
+{
+       while (*value) {
+               if (!isspace((int) *value)) return 0;
+
+               value++;
+       }
+
+       return 1;
+}
+
+
 VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
 {
        char            *p, *s=0;
        const char      *cp, *cs;
+       int             x;
+       size_t          length;
        DICT_VALUE      *dval;
 
+       if (!value) return NULL;
+
        /*
         *      Even for integers, dates and ip addresses we
         *      keep the original string in vp->vp_strvalue.
         */
-       strNcpy((char *)vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
-       vp->length = strlen(vp->vp_strvalue);
+       if (vp->type != PW_TYPE_TLV) {
+               strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
+               vp->length = strlen(vp->vp_strvalue);
+       }
 
        switch(vp->type) {
                case PW_TYPE_STRING:
                        /*
-                        *      Already handled above.
+                        *      Do escaping here
                         */
+                       p = vp->vp_strvalue;
+                       cp = value;
+                       length = 0;
+
+                       while (*cp && (length < (sizeof(vp->vp_strvalue) - 1))) {
+                               char c = *cp++;
+
+                               if (c == '\\') {
+                                       switch (*cp) {
+                                       case 'r':
+                                               c = '\r';
+                                               cp++;
+                                               break;
+                                       case 'n':
+                                               c = '\n';
+                                               cp++;
+                                               break;
+                                       case 't':
+                                               c = '\t';
+                                               cp++;
+                                               break;
+                                       case '"':
+                                               c = '"';
+                                               cp++;
+                                               break;
+                                       case '\'':
+                                               c = '\'';
+                                               cp++;
+                                               break;
+                                       case '\\':
+                                               c = '\\';
+                                               cp++;
+                                               break;
+                                       case '`':
+                                               c = '`';
+                                               cp++;
+                                               break;
+                                       case '\0':
+                                               c = '\\'; /* no cp++ */
+                                               break;
+                                       default:
+                                               if ((cp[0] >= '0') &&
+                                                   (cp[0] <= '9') &&
+                                                   (cp[1] >= '0') &&
+                                                   (cp[1] <= '9') &&
+                                                   (cp[2] >= '0') &&
+                                                   (cp[2] <= '9') &&
+                                                   (sscanf(cp, "%3o", &x) == 1)) {
+                                                       c = x;
+                                                       cp += 3;
+                                               } /* else just do '\\' */
+                                       }
+                               }
+                               *p++ = c;
+                               length++;
+                       }
+                       vp->vp_strvalue[length] = '\0';
+                       vp->length = length;
                        break;
 
                case PW_TYPE_IPADDR:
@@ -774,8 +977,10 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                         *      FIXME: complain if hostname
                         *      cannot be resolved, or resolve later!
                         */
+                       s = NULL;
                        if ((p = strrchr(value, '+')) != NULL && !p[1]) {
                                cs = s = strdup(value);
+                               if (!s) return NULL;
                                p = strrchr(s, '+');
                                *p = 0;
                                vp->flags.addport = 1;
@@ -783,109 +988,98 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                                p = NULL;
                                cs = value;
                        }
-                       
+
                        {
-                               lrad_ipaddr_t ipaddr;
+                               fr_ipaddr_t ipaddr;
 
                                if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
-                                       librad_log("Failed to find IP address for %s", cs);
+                                       free(s);
+                                       fr_strerror_printf("Failed to find IP address for %s", cs);
                                        return NULL;
                                }
 
-                               vp->lvalue = ipaddr.ipaddr.ip4addr.s_addr;
+                               vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
                        }
-                       if (s) free(s);
+                       free(s);
                        vp->length = 4;
                        break;
 
                case PW_TYPE_BYTE:
+                       vp->length = 1;
+
                        /*
                         *      Note that ALL integers are unsigned!
                         */
-                       if (isdigit((int) value[0]) &&
-                           (strspn(value, "0123456789") == strlen(value))) {
-                               vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
-                               if (vp->lvalue > 255) {
-                                       librad_log("Byte value \"%s\" is larger than 255", value);
+                       vp->vp_integer = getint(value, &p);
+                       if (!*p) {
+                               if (vp->vp_integer > 255) {
+                                       fr_strerror_printf("Byte value \"%s\" is larger than 255", value);
                                        return NULL;
                                }
-                               vp->length = 1;
-                       }
-
-                       /*
-                        *      Look for the named value for the given
-                        *      attribute.
-                        */
-                       else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
-                               librad_log("Unknown value %s for attribute %s",
-                                          value, vp->name);
-                               return NULL;
-                       } else {
-                               vp->lvalue = dval->value;
-                               vp->length = 1;
+                               break;
                        }
-                       break;
+                       if (check_for_whitespace(p)) break;
+                       goto check_for_value;
 
                case PW_TYPE_SHORT:
                        /*
                         *      Note that ALL integers are unsigned!
                         */
-                       if (isdigit((int) value[0]) &&
-                           (strspn(value, "0123456789") == strlen(value))) {
-                               vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
-                               if (vp->lvalue > 65535) {
-                                       librad_log("Byte value \"%s\" is larger than 65535", value);
+                       vp->vp_integer = getint(value, &p);
+                       vp->length = 2;
+                       if (!*p) {
+                               if (vp->vp_integer > 65535) {
+                                       fr_strerror_printf("Byte value \"%s\" is larger than 65535", value);
                                        return NULL;
                                }
-                               vp->length = 2;
-                       }
-
-                       /*
-                        *      Look for the named value for the given
-                        *      attribute.
-                        */
-                       else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
-                               librad_log("Unknown value %s for attribute %s",
-                                          value, vp->name);
-                               return NULL;
-                       } else {
-                               vp->lvalue = dval->value;
-                               vp->length = 2;
+                               break;
                        }
-                       break;
+                       if (check_for_whitespace(p)) break;
+                       goto check_for_value;
 
                case PW_TYPE_INTEGER:
                        /*
                         *      Note that ALL integers are unsigned!
                         */
-                       if (isdigit((int) value[0]) &&
-                           (strspn(value, "0123456789") == strlen(value))) {
-                               vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
-                               vp->length = 4;
-                       }
+                       vp->vp_integer = getint(value, &p);
+                       vp->length = 4;
+                       if (!*p) break;
+                       if (check_for_whitespace(p)) break;
 
+       check_for_value:
                        /*
                         *      Look for the named value for the given
                         *      attribute.
                         */
-                       else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
-                               librad_log("Unknown value %s for attribute %s",
+                       if ((dval = dict_valbyname(vp->attribute, vp->vendor, value)) == NULL) {
+                               fr_strerror_printf("Unknown value %s for attribute %s",
                                           value, vp->name);
                                return NULL;
-                       } else {
-                               vp->lvalue = dval->value;
-                               vp->length = 4;
                        }
+                       vp->vp_integer = dval->value;
                        break;
 
                case PW_TYPE_DATE:
-                       if (gettime(value, (time_t *)&vp->lvalue) < 0) {
-                               librad_log("failed to parse time string "
-                                          "\"%s\"", value);
-                               return NULL;
+                       {
+                               /*
+                                *      time_t may be 64 bits, whule vp_date
+                                *      MUST be 32-bits.  We need an
+                                *      intermediary variable to handle
+                                *      the conversions.
+                                */
+                               time_t date;
+
+                               if (gettime(value, &date) < 0) {
+                                       fr_strerror_printf("failed to parse time string "
+                                                  "\"%s\"", value);
+                                       return NULL;
+                               }
+
+                               vp->vp_date = date;
                        }
                        vp->length = 4;
                        break;
+
                case PW_TYPE_ABINARY:
 #ifdef ASCEND_BINARY
                        if (strncasecmp(value, "0x", 2) == 0) {
@@ -894,8 +1088,8 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                        }
 
                        if (ascend_parse_filter(vp) < 0 ) {
-                               librad_log("failed to parse Ascend binary attribute: %s",
-                                          librad_errstr);
+                               fr_strerror_printf("failed to parse Ascend binary attribute: %s",
+                                          fr_strerror());
                                return NULL;
                        }
                        break;
@@ -912,7 +1106,7 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                        if (strncasecmp(value, "0x", 2) == 0) {
                                uint8_t *us;
                                cp = value + 2;
-                               us = vp->vp_strvalue;
+                               us = vp->vp_octets;
                                vp->length = 0;
 
 
@@ -921,16 +1115,17 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                                 *      die.
                                 */
                                if ((strlen(cp) & 0x01) != 0) {
-                                       librad_log("Hex string is not an even length string.");
+                                       fr_strerror_printf("Hex string is not an even length string.");
                                        return NULL;
                                }
-                               
-                               
-                               while (*cp && vp->length < MAX_STRING_LEN) {
+
+
+                               while (*cp &&
+                                      (vp->length < MAX_STRING_LEN)) {
                                        unsigned int tmp;
 
                                        if (sscanf(cp, "%02x", &tmp) != 1) {
-                                               librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
+                                               fr_strerror_printf("Non-hex characters at %c%c", cp[0], cp[1]);
                                                return NULL;
                                        }
 
@@ -938,65 +1133,152 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                                        *(us++) = tmp;
                                        vp->length++;
                                }
-                               *us = '\0';
                        }
                        break;
 
                case PW_TYPE_IFID:
-                       if (ifid_aton(value, vp->vp_strvalue) == NULL) {
-                               librad_log("failed to parse interface-id "
+                       if (ifid_aton(value, (void *) &vp->vp_ifid) == NULL) {
+                               fr_strerror_printf("failed to parse interface-id "
                                           "string \"%s\"", value);
                                return NULL;
                        }
                        vp->length = 8;
-                       vp->vp_strvalue[vp->length] = '\0';
                        break;
 
                case PW_TYPE_IPV6ADDR:
-                       if (inet_pton(AF_INET6, value, vp->vp_strvalue) <= 0) {
-                               librad_log("failed to parse IPv6 address "
-                                          "string \"%s\"", value);
-                               return NULL;
+                       {
+                               fr_ipaddr_t ipaddr;
+
+                               if (ip_hton(value, AF_INET6, &ipaddr) < 0) {
+                                       char buffer[1024];
+
+                                       strlcpy(buffer, fr_strerror(), sizeof(buffer));
+
+                                       fr_strerror_printf("failed to parse IPv6 address "
+                                                           "string \"%s\": %s", value, buffer);
+                                       return NULL;
+                               }
+                               vp->vp_ipv6addr = ipaddr.ipaddr.ip6addr;
+                               vp->length = 16; /* length of IPv6 address */
                        }
-                       vp->length = 16; /* length of IPv6 address */
-                       vp->vp_strvalue[vp->length] = '\0';
                        break;
-                       /*
-                        *  Anything else.
-                        */
+
                case PW_TYPE_IPV6PREFIX:
                        p = strchr(value, '/');
                        if (!p || ((p - value) >= 256)) {
-                               librad_log("invalid IPv6 prefix "
+                               fr_strerror_printf("invalid IPv6 prefix "
                                           "string \"%s\"", value);
                                return NULL;
                        } else {
                                unsigned int prefix;
                                char buffer[256], *eptr;
-                               
+
                                memcpy(buffer, value, p - value);
                                buffer[p - value] = '\0';
-                               
-                               if (inet_pton(AF_INET6, buffer, vp->vp_strvalue + 2) <= 0) {
-                                       librad_log("failed to parse IPv6 address "
+
+                               if (inet_pton(AF_INET6, buffer, vp->vp_octets + 2) <= 0) {
+                                       fr_strerror_printf("failed to parse IPv6 address "
                                                   "string \"%s\"", value);
                                        return NULL;
                                }
-                               
+
                                prefix = strtoul(p + 1, &eptr, 10);
                                if ((prefix > 128) || *eptr) {
-                                       librad_log("failed to parse IPv6 address "
+                                       fr_strerror_printf("failed to parse IPv6 address "
                                                   "string \"%s\"", value);
                                        return NULL;
                                }
-                               vp->vp_strvalue[1] = prefix;
+                               vp->vp_octets[1] = prefix;
                        }
-                       vp->vp_strvalue[0] = '\0';
+                       vp->vp_octets[0] = '\0';
                        vp->length = 16 + 2;
                        break;
 
+               case PW_TYPE_ETHERNET:
+                       {
+                               const char *c1, *c2;
+
+                               length = 0;
+                               cp = value;
+                               while (*cp) {
+                                       if (cp[1] == ':') {
+                                               c1 = hextab;
+                                               c2 = memchr(hextab, tolower((int) cp[0]), 16);
+                                               cp += 2;
+                                       } else if ((cp[1] != '\0') &&
+                                                  ((cp[2] == ':') ||
+                                                   (cp[2] == '\0'))) {
+                                                  c1 = memchr(hextab, tolower((int) cp[0]), 16);
+                                                  c2 = memchr(hextab, tolower((int) cp[1]), 16);
+                                                  cp += 2;
+                                                  if (*cp == ':') cp++;
+                                       } else {
+                                               c1 = c2 = NULL;
+                                       }
+                                       if (!c1 || !c2 || (length >= sizeof(vp->vp_ether))) {
+                                               fr_strerror_printf("failed to parse Ethernet address \"%s\"", value);
+                                               return NULL;
+                                       }
+                                       vp->vp_ether[length] = ((c1-hextab)<<4) + (c2-hextab);
+                                       length++;
+                               }
+                       }
+                       vp->length = 6;
+                       break;
+
+               case PW_TYPE_COMBO_IP:
+                       if (inet_pton(AF_INET6, value, vp->vp_strvalue) > 0) {
+                               vp->type = PW_TYPE_IPV6ADDR;
+                               vp->length = 16; /* length of IPv6 address */
+                               vp->vp_strvalue[vp->length] = '\0';
+
+                       } else {
+                               fr_ipaddr_t ipaddr;
+
+                               if (ip_hton(value, AF_INET, &ipaddr) < 0) {
+                                       fr_strerror_printf("Failed to find IPv4 address for %s", value);
+                                       return NULL;
+                               }
+
+                               vp->type = PW_TYPE_IPADDR;
+                               vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
+                               vp->length = 4;
+                       }
+                       break;
+
+               case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
+                       vp->vp_signed = (int32_t) strtol(value, &p, 10);
+                       vp->length = 4;
+                       break;
+
+               case PW_TYPE_TLV: /* don't use this! */
+                       if (strncasecmp(value, "0x", 2) != 0) {
+                               fr_strerror_printf("Invalid TLV specification");
+                               return NULL;
+                       }
+                       length = strlen(value + 2) / 2;
+                       if (vp->length < length) {
+                               free(vp->vp_tlv);
+                               vp->vp_tlv = NULL;
+                       }
+                       vp->vp_tlv = malloc(length);
+                       if (!vp->vp_tlv) {
+                               fr_strerror_printf("No memory");
+                               return NULL;
+                       }
+                       if (fr_hex2bin(value + 2, vp->vp_tlv,
+                                      length) != length) {
+                               fr_strerror_printf("Invalid hex data in TLV");
+                               return NULL;
+                       }
+                       vp->length = length;
+                       break;
+
+                       /*
+                        *  Anything else.
+                        */
                default:
-                       librad_log("unknown attribute type %d", vp->type);
+                       fr_strerror_printf("unknown attribute type %d", vp->type);
                        return NULL;
        }
 
@@ -1009,119 +1291,178 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
  *
  *     Attr-%d
  *     Vendor-%d-Attr-%d
+ *     VendorName-Attr-%d
  */
 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
                                int operator)
 {
-       int             attr;
-       const char      *p;
+       int             attr, vendor;
+       size_t          size;
+       const char      *p = attribute;
+       char            *q;
        VALUE_PAIR      *vp;
 
        /*
         *      Unknown attributes MUST be of type 'octets'
         */
        if (value && (strncasecmp(value, "0x", 2) != 0)) {
-               goto error;
+               fr_strerror_printf("Invalid octet string \"%s\" for attribute name \"%s\"", value, attribute);
+               return NULL;
        }
 
+       vendor = 0;
+
        /*
-        *      Attr-%d
+        *      Pull off vendor prefix first.
         */
-       if (strncasecmp(attribute, "Attr-", 5) == 0) {
-               attr = atoi(attribute + 5);
-               p = attribute + 5;
-               p += strspn(p, "0123456789");
-               if (*p != 0) goto error;
+       if (strncasecmp(p, "Attr-", 5) != 0) {
+               if (strncasecmp(p, "Vendor-", 7) == 0) {
+                       vendor = (int) strtol(p + 7, &q, 10);
+                       if ((vendor == 0) || (vendor > FR_MAX_VENDOR)) {
+                               fr_strerror_printf("Invalid vendor value in attribute name \"%s\"", attribute);
+                               return NULL;
+                       }
 
-               /*
-                *      Vendor-%d-Attr-%d
-                */
-       } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
-               int vendor;
+                       p = q;
 
-               vendor = atoi(attribute + 7);
-               if ((vendor == 0) || (vendor > 65535)) goto error;
+               } else {        /* must be vendor name */
+                       char buffer[256];
 
-               p = attribute + 7;
-               p += strspn(p, "0123456789");
+                       q = strchr(p, '-');
 
-               /*
-                *      Not Vendor-%d-Attr-%d
-                */
-               if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
+                       if (!q) {
+                               fr_strerror_printf("Invalid vendor name in attribute name \"%s\"", attribute);
+                               return NULL;
+                       }
 
-               p += 6;
-               attr = atoi(p);
+                       if ((size_t) (q - p) >= sizeof(buffer)) {
+                               fr_strerror_printf("Vendor name too long in attribute name \"%s\"", attribute);
+                               return NULL;
+                       }
 
-               p += strspn(p, "0123456789");
-               if (*p != 0) goto error;
+                       memcpy(buffer, p, (q - p));
+                       buffer[q - p] = '\0';
 
-               if ((attr == 0) || (attr > 65535)) goto error;
+                       vendor = dict_vendorbyname(buffer);
+                       if (!vendor) {
+                               fr_strerror_printf("Unknown vendor name in attribute name \"%s\"", attribute);
+                               return NULL;
+                       }
 
-               attr |= (vendor << 16);
+                       p = q;
+               }
 
-               /*
-                *      VendorName-Attr-%d
-                */
-       } else if (((p = strchr(attribute, '-')) != NULL) &&
-                  (strncasecmp(p, "-Attr-", 6) == 0)) {
-               int vendor;
-               char buffer[256];
+               if (*p != '-') {
+                       fr_strerror_printf("Invalid text following vendor definition in attribute name \"%s\"", attribute);
+                       return NULL;
+               }
+               p++;
+       }
 
-               if (((size_t) (p - attribute)) >= sizeof(buffer)) goto error;
+       /*
+        *      Attr-%d
+        */
+       if (strncasecmp(p, "Attr-", 5) != 0) {
+               fr_strerror_printf("Invalid format in attribute name \"%s\"", attribute);
+               return NULL;
+       }
 
-               memcpy(buffer, attribute, p - attribute);
-               buffer[p - attribute] = '\0';
+       attr = strtol(p + 5, &q, 10);
 
-               vendor = dict_vendorbyname(buffer);
-               if (vendor == 0) goto error;
+       /*
+        *      Invalid, or trailing text after number.
+        */
+       if ((attr == 0) || *q) {
+               fr_strerror_printf("Invalid value in attribute name \"%s\"", attribute);
+               return NULL;
+       }
 
-               p += 6;
-               attr = atoi(p);
+       /*
+        *      Double-check the size of attr.
+        */
+       if (vendor) {
+               DICT_VENDOR *dv = dict_vendorbyvalue(vendor);
 
-               p += strspn(p, "0123456789");
-               if (*p != 0) goto error;
+               if (!dv) {
+                       if (attr > 255) {
+                       attr_error:
+                               fr_strerror_printf("Invalid attribute number in attribute name \"%s\"", attribute);
+                               return NULL;
+                       }
 
-               if ((attr == 0) || (attr > 65535)) goto error;
+               } else switch (dv->type) {
+                       case 1:
+                               if (attr > 255) goto attr_error;
+                               break;
 
-               attr |= (vendor << 16);
+                       case 2:
+                               if (attr > 65535) goto attr_error;
+                               break;
 
-       } else {                /* very much unknown: die */
-       error:
-               librad_log("Unknown attribute \"%s\"", attribute);
-               return NULL;
+                       case 4:
+                               break;
+
+                       default:
+                               fr_strerror_printf("Internal sanity check failed");
+                               return NULL;
+               }
        }
 
        /*
-        *      We've now parsed the attribute properly, and verified
-        *      it to have value 'octets'.  Let's create it.
+        *      We've now parsed the attribute properly, Let's create
+        *      it.  This next stop also looks the attribute up in the
+        *      dictionary, and creates the appropriate type for it.
         */
-       if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
-               librad_log("out of memory");
+       if ((vp = paircreate(attr, vendor, PW_TYPE_OCTETS)) == NULL) {
+               fr_strerror_printf("out of memory");
                return NULL;
        }
-       memset(vp, 0, sizeof(VALUE_PAIR));
-       vp->type = PW_TYPE_OCTETS;
+
+       vp->operator = (operator == 0) ? T_OP_EQ : operator;
+       if (!value) return vp;
+
+       size = strlen(value + 2);
 
        /*
-        *      It may not be valid hex characters.  If not, die.
+        *      We may be reading something like Attr-5.  i.e.
+        *      who-ever wrote the text didn't understand it, but we
+        *      do.
         */
-       if (pairparsevalue(vp, value) == NULL) {
-               pairfree(&vp);
-               return NULL;
+       switch (vp->type) {
+       default:
+               if (size == (vp->length * 2)) break;
+               vp->type = PW_TYPE_OCTETS;
+               /* FALL-THROUGH */
+               
+       case PW_TYPE_STRING:
+       case PW_TYPE_OCTETS:
+       case PW_TYPE_ABINARY:
+               vp->length = size >> 1;
+               break;
        }
 
-       if (VENDOR(attr) == 0) {
-               sprintf(vp->name, "Attr-%u", attr);
-       } else {
-               sprintf(vp->name, "Vendor-%u-Attr-%u",
-                       VENDOR(attr), attr & 0xffff);
+       if (fr_hex2bin(value + 2, vp->vp_octets, size) != vp->length) {
+               fr_strerror_printf("Invalid hex string");
+               free(vp);
+               return NULL;
        }
 
-       vp->attribute = attr;
-       vp->operator = (operator == 0) ? T_OP_EQ : operator;
-       vp->next = NULL;
-
+       /*
+        *      Move contents around based on type.  This is
+        *      to work around the historical use of "lvalue".
+        */
+       switch (vp->type) {
+       case PW_TYPE_DATE:
+       case PW_TYPE_IPADDR:
+       case PW_TYPE_INTEGER:
+               memcpy(&vp->lvalue, vp->vp_octets, sizeof(vp->lvalue));
+               vp->vp_strvalue[0] = '\0';
+               break;
+               
+       default:
+               break;
+       }
+       
        return vp;
 }
 
@@ -1136,10 +1477,8 @@ VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
        char            *tc, *ts;
        signed char     tag;
        int             found_tag;
-#ifdef HAVE_REGEX_H
-       int             res;
-       regex_t         cre;
-#endif
+       char            buffer[64];
+       const char      *attrname = attribute;
 
        /*
         *    Check for tags in 'Attribute:Tag' format.
@@ -1149,11 +1488,15 @@ VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
 
        ts = strrchr(attribute, ':');
        if (ts && !ts[1]) {
-               librad_log("Invalid tag for attribute %s", attribute);
+               fr_strerror_printf("Invalid tag for attribute %s", attribute);
                return NULL;
        }
 
        if (ts && ts[1]) {
+               strlcpy(buffer, attribute, sizeof(buffer));
+               attrname = buffer;
+               ts = strrchr(attrname, ':');
+
                 /* Colon found with something behind it */
                 if (ts[1] == '*' && ts[2] == 0) {
                         /* Wildcard tag for check items */
@@ -1166,7 +1509,7 @@ VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
                                 *ts = 0;
                         else tag = 0;
                 } else {
-                        librad_log("Invalid tag for attribute %s", attribute);
+                        fr_strerror_printf("Invalid tag for attribute %s", attribute);
                         return NULL;
                 }
                 found_tag = 1;
@@ -1176,22 +1519,15 @@ VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
         *      It's not found in the dictionary, so we use
         *      another method to create the attribute.
         */
-       if ((da = dict_attrbyname(attribute)) == NULL) {
-               return pairmake_any(attribute, value, operator);
+       if ((da = dict_attrbyname(attrname)) == NULL) {
+               return pairmake_any(attrname, value, operator);
        }
 
-       if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
-               librad_log("out of memory");
+       if ((vp = pairalloc(da)) == NULL) {
+               fr_strerror_printf("out of memory");
                return NULL;
        }
-
-       memset(vp, 0, sizeof(VALUE_PAIR));
-       vp->attribute = da->attr;
-       vp->type = da->type;
        vp->operator = (operator == 0) ? T_OP_EQ : operator;
-       strcpy(vp->name, da->name);
-       vp->flags = da->flags;
-       vp->next = NULL;
 
        /*      Check for a tag in the 'Merit' format of:
         *      :Tag:Value.  Print an error if we already found
@@ -1201,13 +1537,12 @@ VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
        if (value && (*value == ':' && da->flags.has_tag)) {
                /* If we already found a tag, this is invalid */
                if(found_tag) {
-                       pairbasicfree(vp);
-                       librad_log("Duplicate tag %s for attribute %s",
+                       fr_strerror_printf("Duplicate tag %s for attribute %s",
                                   value, vp->name);
                        DEBUG("Duplicate tag %s for attribute %s\n",
                                   value, vp->name);
+                       pairbasicfree(vp);
                        return NULL;
-
                }
                /* Colon found and attribute allows a tag */
                if (value[1] == '*' && value[2] == ':') {
@@ -1250,36 +1585,21 @@ VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
                 */
        case T_OP_REG_EQ:       /* =~ */
        case T_OP_REG_NE:       /* !~ */
-               if (vp->type == PW_TYPE_INTEGER) {
-                       return vp;
-               }
-#ifdef HAVE_REGEX_H
-               /*
-                *      Regular expression match with no regular
-                *      expression is wrong.
-                */
                if (!value) {
-                       pairfree(&vp);
+                       fr_strerror_printf("No regular expression found in %s",
+                                          vp->name);
+                       pairbasicfree(vp);
                        return NULL;
                }
+         
+               strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
+               vp->length = strlen(vp->vp_strvalue);
+               /*
+                *      If anything goes wrong, this is a run-time error,
+                *      not a compile-time error.
+                */
+               return vp;
 
-               res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
-               if (res != 0) {
-                       char    msg[128];
-
-                       regerror(res, &cre, msg, sizeof(msg));
-                       librad_log("Illegal regular expression in attribute: %s: %s",
-                               vp->name, msg);
-                       pairbasicfree(vp);
-                       return NULL;
-               }
-               regfree(&cre);
-#else
-               librad_log("Regelar expressions not enabled in this build, error in attribute %s",
-                               vp->name);
-               pairbasicfree(vp);
-               return NULL;
-#endif
        }
 
        /*
@@ -1325,13 +1645,13 @@ static const int valid_attr_name[256] = {
  *     Read a valuepair from a buffer, and advance pointer.
  *     Sets *eol to T_EOL if end of line was encountered.
  */
-VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
+VALUE_PAIR *pairread(const char **ptr, FR_TOKEN *eol)
 {
        char            buf[64];
        char            attr[64];
-       char            value[512];
-       char            *p, *q;
-       LRAD_TOKEN      token, t, xlat;
+       char            value[1024], *q;
+       const char      *p;
+       FR_TOKEN        token, t, xlat;
        VALUE_PAIR      *vp;
        size_t          len;
 
@@ -1342,13 +1662,13 @@ VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
 
        if (!*p) {
                *eol = T_OP_INVALID;
-               librad_log("No token read where we expected an attribute name");
+               fr_strerror_printf("No token read where we expected an attribute name");
                return NULL;
        }
 
        if (*p == '#') {
                *eol = T_HASH;
-               librad_log("Read a comment instead of a token");
+               fr_strerror_printf("Read a comment instead of a token");
                return NULL;
        }
 
@@ -1363,14 +1683,14 @@ VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
 
        if (len == sizeof(attr)) {
                *eol = T_OP_INVALID;
-               librad_log("Attribute name is too long");
+               fr_strerror_printf("Attribute name is too long");
                return NULL;
        }
 
        /*
         *      We may have Foo-Bar:= stuff, so back up.
         */
-       if (attr[len - 1] == ':') {
+       if ((len > 0) && (attr[len - 1] == ':')) {
                p--;
                len--;
        }
@@ -1381,14 +1701,14 @@ VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
        /* Now we should have an operator here. */
        token = gettoken(ptr, buf, sizeof(buf));
        if (token < T_EQSTART || token > T_EQEND) {
-               librad_log("expecting operator");
+               fr_strerror_printf("expecting operator");
                return NULL;
        }
 
        /* Read value.  Note that empty string values are allowed */
        xlat = gettoken(ptr, value, sizeof(value));
        if (xlat == T_EOL) {
-               librad_log("failed to get value");
+               fr_strerror_printf("failed to get value");
                return NULL;
        }
 
@@ -1398,7 +1718,7 @@ VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
        p = *ptr;
        t = gettoken(&p, buf, sizeof(buf));
        if (t != T_EOL && t != T_COMMA && t != T_HASH) {
-               librad_log("Expected end of line or comma");
+               fr_strerror_printf("Expected end of line or comma");
                return NULL;
        }
 
@@ -1423,7 +1743,7 @@ VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
                p = strchr(value, '%');
                if (p && (p[1] == '{')) {
                        if (strlen(value) >= sizeof(vp->vp_strvalue)) {
-                               librad_log("Value too long");
+                               fr_strerror_printf("Value too long");
                                return NULL;
                        }
                        vp = pairmake(attr, NULL, token);
@@ -1432,21 +1752,55 @@ VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
                                return NULL;
                        }
 
-                       strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
+                       strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
                        vp->flags.do_xlat = 1;
                        vp->length = 0;
                } else {
+                       /*
+                        *      Parse && escape it, as defined by the
+                        *      data type.
+                        */
                        vp = pairmake(attr, value, token);
+                       if (!vp) {
+                               *eol = T_OP_INVALID;
+                               return NULL;
+                       }
                }
                break;
 
+       case T_SINGLE_QUOTED_STRING:
+               vp = pairmake(attr, NULL, token);
+               if (!vp) {
+                       *eol = T_OP_INVALID;
+                       return NULL;
+               }
+
+               /*
+                *      String and octet types get copied verbatim.
+                */
+               if ((vp->type == PW_TYPE_STRING) ||
+                   (vp->type == PW_TYPE_OCTETS)) {
+                       strlcpy(vp->vp_strvalue, value,
+                               sizeof(vp->vp_strvalue));
+                       vp->length = strlen(vp->vp_strvalue);
+
+                       /*
+                        *      Everything else gets parsed: it's
+                        *      DATA, not a string!
+                        */
+               } else if (!pairparsevalue(vp, value)) {
+                       pairfree(&vp);
+                       *eol = T_OP_INVALID;
+                       return NULL;
+               }
+               break;
 
                /*
                 *      Mark the pair to be allocated later.
                 */
        case T_BACK_QUOTED_STRING:
                if (strlen(value) >= sizeof(vp->vp_strvalue)) {
-                       librad_log("Value too long");
+                       fr_strerror_printf("Value too long");
                        return NULL;
                }
 
@@ -1457,7 +1811,7 @@ VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
                }
 
                vp->flags.do_xlat = 1;
-               strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
+               strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
                vp->length = 0;
                break;
        }
@@ -1477,12 +1831,12 @@ VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
  *     Read one line of attribute/value pairs. This might contain
  *     multiple pairs seperated by comma's.
  */
-LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
+FR_TOKEN userparse(const char *buffer, VALUE_PAIR **first_pair)
 {
        VALUE_PAIR      *vp;
-       char            *p;
-       LRAD_TOKEN      last_token = T_OP_INVALID;
-       LRAD_TOKEN      previous_token;
+       const char      *p;
+       FR_TOKEN        last_token = T_OP_INVALID;
+       FR_TOKEN        previous_token;
 
        /*
         *      We allow an empty line.
@@ -1520,7 +1874,7 @@ LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
 {
        char buf[8192];
-       LRAD_TOKEN last_token = T_EOL;
+       FR_TOKEN last_token = T_EOL;
        VALUE_PAIR *vp;
        VALUE_PAIR *list;
        int error = 0;
@@ -1551,7 +1905,7 @@ VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
                last_token = userparse(buf, &vp);
                if (!vp) {
                        if (last_token != T_EOL) {
-                               librad_perror("%s", errprefix);
+                               fr_perror("%s", errprefix);
                                error = 1;
                                break;
                        }
@@ -1581,6 +1935,8 @@ VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
  *     e.g. "foo" != "bar"
  *
  *     Returns true (comparison is true), or false (comparison is not true);
+ *
+ *     FIXME: Ignores tags!
  */
 int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
 {
@@ -1605,12 +1961,12 @@ int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
                {
                        regex_t reg;
                        char buffer[MAX_STRING_LEN * 4 + 1];
-                       
+
                        compare = regcomp(&reg, one->vp_strvalue,
                                          REG_EXTENDED);
                        if (compare != 0) {
                                regerror(compare, &reg, buffer, sizeof(buffer));
-                               librad_log("Illegal regular expression in attribute: %s: %s",
+                               fr_strerror_printf("Illegal regular expression in attribute: %s: %s",
                                           one->name, buffer);
                                return -1;
                        }
@@ -1632,7 +1988,7 @@ int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
        default:                /* we're OK */
                break;
        }
-               
+
        /*
         *      After doing the previous check for special comparisons,
         *      do the per-type comparison here.
@@ -1642,19 +1998,17 @@ int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
        case PW_TYPE_OCTETS:
        {
                size_t length;
-               const uint8_t *p, *q;
 
                if (one->length < two->length) {
                        length = one->length;
                } else {
                        length = two->length;
                }
-               
-               p = two->vp_octets;
-               q = one->vp_octets;
-               while (length) {
-                       compare = ((int) *p) - ((int) *q);
-                       if (compare != 0) goto type_switch;
+
+               if (length) {
+                       compare = memcmp(two->vp_octets, one->vp_octets,
+                                        length);
+                       if (compare != 0) break;
                }
 
                /*
@@ -1668,20 +2022,14 @@ int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
                break;
 
        case PW_TYPE_STRING:
-               if (one->flags.caseless) {
-                       compare = strcasecmp(two->vp_strvalue,
-                                            one->vp_strvalue);
-               } else {
-                       compare = strcmp(two->vp_strvalue,
-                                        one->vp_strvalue);
-               }
+               compare = strcmp(two->vp_strvalue, one->vp_strvalue);
                break;
-               
+
        case PW_TYPE_BYTE:
        case PW_TYPE_SHORT:
        case PW_TYPE_INTEGER:
        case PW_TYPE_DATE:
-               compare = two->lvalue - one->lvalue;
+               compare = two->vp_integer - one->vp_integer;
                break;
 
        case PW_TYPE_IPADDR:
@@ -1692,7 +2040,7 @@ int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
                compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
                                 sizeof(two->vp_ipv6addr));
                break;
-               
+
        case PW_TYPE_IPV6PREFIX:
                compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
                                 sizeof(two->vp_ipv6prefix));
@@ -1710,17 +2058,16 @@ int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
        /*
         *      Now do the operator comparison.
         */
- type_switch:
        switch (one->operator) {
        case T_OP_CMP_EQ:
                return (compare == 0);
-               
+
        case T_OP_NE:
                return (compare != 0);
-               
+
        case T_OP_LT:
                return (compare < 0);
-               
+
        case T_OP_GT:
                return (compare > 0);