Signed / unsigned fixes and function prototypes
[freeradius.git] / src / lib / valuepair.c
index b060542..57fe9a2 100644 (file)
@@ -100,6 +100,7 @@ VALUE_PAIR *pairalloc(DICT_ATTR *da)
                case PW_TYPE_INTEGER:
                case PW_TYPE_IPADDR:
                case PW_TYPE_DATE:
+               case PW_TYPE_SIGNED:
                        vp->length = 4;
                        break;
 
@@ -119,6 +120,12 @@ VALUE_PAIR *pairalloc(DICT_ATTR *da)
                        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;
@@ -127,18 +134,46 @@ VALUE_PAIR *pairalloc(DICT_ATTR *da)
        return vp;
 }
 
+/*
+ *     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 type)
+VALUE_PAIR *paircreate(int attr, int vendor, int type)
 {
        VALUE_PAIR      *vp;
        DICT_ATTR       *da;
 
-       da = dict_attrbyvalue(attr);
+       da = dict_attrbyvalue(attr, vendor);
        if ((vp = pairalloc(da)) == NULL) {
-               librad_log("out of memory");
+               fr_strerror_printf("out of memory");
                return NULL;
        }
        vp->operator = T_OP_EQ;
@@ -146,40 +181,7 @@ VALUE_PAIR *paircreate(int attr, int type)
        /*
         *      It isn't in the dictionary: update the name.
         */
-       if (!da) {
-               size_t len = 0;
-               char *p = (char *) (vp + 1);
-               
-               vp->vendor = VENDOR(attr);
-               vp->attribute = attr;
-               vp->name = p;
-               vp->type = type; /* be forgiving */
-
-               if (vp->vendor) {
-                       DICT_VENDOR *v;
-
-                       v = dict_vendorbyvalue(vp->vendor);
-                       if (v) {
-                               snprintf(p, FR_VP_NAME_LEN, "%s-", v->name);
-                       } else {
-                               snprintf(p, FR_VP_NAME_LEN, "Vendor-%u-", vp->vendor);
-                       }
-
-                       len = strlen(p);
-                       if (len == FR_VP_NAME_LEN) {
-                               free(vp);
-                               return NULL;
-                       }
-               }
-               
-               snprintf(p + len, FR_VP_NAME_LEN - len, "Attr-%u",
-                        attr & 0xffff);
-               len += strlen(p + len);
-               if (len == FR_VP_NAME_LEN) {
-                       free(vp);
-                       return NULL;
-               }
-       }
+       if (!da) return paircreate_raw(attr, vendor, type, vp);
 
        return vp;
 }
@@ -190,6 +192,7 @@ VALUE_PAIR *paircreate(int attr, int type)
  */
 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);
@@ -219,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 {
@@ -289,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;
 
                        /*
@@ -313,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;
 
@@ -324,25 +372,14 @@ VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr)
        last = &first;
 
        while (vp) {
-               size_t name_len;
-
-               if (attr >= 0 && vp->attribute != attr) {
+               if ((attr > 0) &&
+                   !((vp->attribute == attr) && (vp->vendor == vendor))) {
                        vp = vp->next;
                        continue;
                }
 
-               if (!vp->flags.unknown_attr) {
-                       name_len = 0;
-               } else {
-                       name_len = FR_VP_NAME_PAD;
-               }
-               
-               if ((n = malloc(sizeof(*n))) == NULL) {
-                       librad_log("out of memory");
-                       return first;
-               }
-               memcpy(n, vp, sizeof(*n) + name_len);
-               n->next = NULL;
+               n = paircopyvp(vp);
+               if (!n) return first;
                *last = n;
                last = &n->next;
                vp = vp->next;
@@ -356,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);
 }
 
 
@@ -431,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) {
 
                          /*
@@ -443,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
@@ -538,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
@@ -584,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;
@@ -602,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.
                 */
@@ -784,13 +831,11 @@ static int gettime(const char *valstr, time_t *date)
                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]);
        }
 
        /*
@@ -814,6 +859,27 @@ static const char *hextab = "0123456789abcdef";
  *  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;
@@ -822,12 +888,16 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
        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.
         */
-       strlcpy(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:
@@ -838,7 +908,7 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                        cp = value;
                        length = 0;
 
-                       while (*cp && (length < sizeof(vp->vp_strvalue))) {
+                       while (*cp && (length < (sizeof(vp->vp_strvalue) - 1))) {
                                char c = *cp++;
 
                                if (c == '\\') {
@@ -863,6 +933,10 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                                                c = '\'';
                                                cp++;
                                                break;
+                                       case '\\':
+                                               c = '\\';
+                                               cp++;
+                                               break;
                                        case '`':
                                                c = '`';
                                                cp++;
@@ -886,6 +960,7 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                                *p++ = c;
                                length++;
                        }
+                       vp->vp_strvalue[length] = '\0';
                        vp->length = length;
                        break;
 
@@ -902,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;
@@ -916,95 +993,70 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                                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->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
                        }
-                       if (s) free(s);
+                       free(s);
                        vp->length = 4;
                        break;
 
                case PW_TYPE_BYTE:
-                       if ((value[0] == '0') && (value[1] == 'x')) {
-                               goto do_octets;
-                       }
+                       vp->length = 1;
 
                        /*
                         *      Note that ALL integers are unsigned!
                         */
-                       vp->vp_integer = (uint32_t) strtoul(value, &p, 10);
+                       vp->vp_integer = getint(value, &p);
                        if (!*p) {
                                if (vp->vp_integer > 255) {
-                                       librad_log("Byte value \"%s\" is larger than 255", value);
+                                       fr_strerror_printf("Byte value \"%s\" is larger than 255", value);
                                        return NULL;
                                }
-                               vp->length = 1;
                                break;
                        }
-
-                       /*
-                        *      Look for the named value for the given
-                        *      attribute.
-                        */
-                       if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
-                               librad_log("Unknown value %s for attribute %s",
-                                          value, vp->name);
-                               return NULL;
-                       }
-                       vp->vp_integer = dval->value;
-                       vp->length = 1;
-                       break;
+                       if (check_for_whitespace(p)) break;
+                       goto check_for_value;
 
                case PW_TYPE_SHORT:
                        /*
                         *      Note that ALL integers are unsigned!
                         */
-                       vp->vp_integer = (uint32_t) strtoul(value, &p, 10);
+                       vp->vp_integer = getint(value, &p);
+                       vp->length = 2;
                        if (!*p) {
                                if (vp->vp_integer > 65535) {
-                                       librad_log("Byte value \"%s\" is larger than 65535", value);
+                                       fr_strerror_printf("Byte value \"%s\" is larger than 65535", value);
                                        return NULL;
                                }
-                               vp->length = 2;
                                break;
                        }
-
-                       /*
-                        *      Look for the named value for the given
-                        *      attribute.
-                        */
-                       if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
-                               librad_log("Unknown value %s for attribute %s",
-                                          value, vp->name);
-                               return NULL;
-                       }
-                       vp->vp_integer = dval->value;
-                       vp->length = 2;
-                       break;
+                       if (check_for_whitespace(p)) break;
+                       goto check_for_value;
 
                case PW_TYPE_INTEGER:
                        /*
                         *      Note that ALL integers are unsigned!
                         */
-                       vp->vp_integer = (uint32_t) strtoul(value, &p, 10);
-                       if (!*p) {
-                               vp->length = 4;
-                               break;
-                       }
+                       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.
                         */
-                       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;
                        }
                        vp->vp_integer = dval->value;
-                       vp->length = 4;
                        break;
 
                case PW_TYPE_DATE:
@@ -1018,7 +1070,7 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                                time_t date;
 
                                if (gettime(value, &date) < 0) {
-                                       librad_log("failed to parse time string "
+                                       fr_strerror_printf("failed to parse time string "
                                                   "\"%s\"", value);
                                        return NULL;
                                }
@@ -1036,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;
@@ -1047,8 +1099,8 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                         *      then fall through to raw octets, so that
                         *      the user can at least make them by hand...
                         */
-#endif
        do_octets:
+#endif
                        /* raw octets: 0x01020304... */
                case PW_TYPE_OCTETS:
                        if (strncasecmp(value, "0x", 2) == 0) {
@@ -1063,7 +1115,7 @@ 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;
                                }
 
@@ -1073,7 +1125,7 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                                        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;
                                        }
 
@@ -1086,7 +1138,7 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
 
                case PW_TYPE_IFID:
                        if (ifid_aton(value, (void *) &vp->vp_ifid) == NULL) {
-                               librad_log("failed to parse interface-id "
+                               fr_strerror_printf("failed to parse interface-id "
                                           "string \"%s\"", value);
                                return NULL;
                        }
@@ -1094,18 +1146,27 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                        break;
 
                case PW_TYPE_IPV6ADDR:
-                       if (inet_pton(AF_INET6, value, &vp->vp_ipv6addr) <= 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 */
                        break;
 
                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 {
@@ -1116,14 +1177,14 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                                buffer[p - value] = '\0';
 
                                if (inet_pton(AF_INET6, buffer, vp->vp_octets + 2) <= 0) {
-                                       librad_log("failed to parse IPv6 address "
+                                       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;
                                }
@@ -1155,7 +1216,7 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                                                c1 = c2 = NULL;
                                        }
                                        if (!c1 || !c2 || (length >= sizeof(vp->vp_ether))) {
-                                               librad_log("failed to parse Ethernet address \"%s\"", value);
+                                               fr_strerror_printf("failed to parse Ethernet address \"%s\"", value);
                                                return NULL;
                                        }
                                        vp->vp_ether[length] = ((c1-hextab)<<4) + (c2-hextab);
@@ -1165,11 +1226,59 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                        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;
        }
 
@@ -1197,11 +1306,11 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
         *      Unknown attributes MUST be of type 'octets'
         */
        if (value && (strncasecmp(value, "0x", 2) != 0)) {
-               librad_log("Invalid octet string \"%s\" for attribute name \"%s\"", value, attribute);
+               fr_strerror_printf("Invalid octet string \"%s\" for attribute name \"%s\"", value, attribute);
                return NULL;
        }
 
-       attr = vendor = 0;
+       vendor = 0;
 
        /*
         *      Pull off vendor prefix first.
@@ -1209,24 +1318,25 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
        if (strncasecmp(p, "Attr-", 5) != 0) {
                if (strncasecmp(p, "Vendor-", 7) == 0) {
                        vendor = (int) strtol(p + 7, &q, 10);
-                       if ((vendor == 0) || (vendor > 65535)) {
-                               librad_log("Invalid vendor value in attribute name \"%s\"", attribute);
+                       if ((vendor == 0) || (vendor > FR_MAX_VENDOR)) {
+                               fr_strerror_printf("Invalid vendor value in attribute name \"%s\"", attribute);
                                return NULL;
                        }
 
                        p = q;
 
                } else {        /* must be vendor name */
-                       q = strchr(p, '-');
                        char buffer[256];
 
+                       q = strchr(p, '-');
+
                        if (!q) {
-                               librad_log("Invalid vendor name in attribute name \"%s\"", attribute);
+                               fr_strerror_printf("Invalid vendor name in attribute name \"%s\"", attribute);
                                return NULL;
                        }
 
                        if ((size_t) (q - p) >= sizeof(buffer)) {
-                               librad_log("Vendor name too long in attribute name \"%s\"", attribute);
+                               fr_strerror_printf("Vendor name too long in attribute name \"%s\"", attribute);
                                return NULL;
                        }
 
@@ -1235,7 +1345,7 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
 
                        vendor = dict_vendorbyname(buffer);
                        if (!vendor) {
-                               librad_log("Unknown vendor name in attribute name \"%s\"", attribute);
+                               fr_strerror_printf("Unknown vendor name in attribute name \"%s\"", attribute);
                                return NULL;
                        }
 
@@ -1243,7 +1353,7 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
                }
 
                if (*p != '-') {
-                       librad_log("Invalid text following vendor definition in attribute name \"%s\"", attribute);
+                       fr_strerror_printf("Invalid text following vendor definition in attribute name \"%s\"", attribute);
                        return NULL;
                }
                p++;
@@ -1253,7 +1363,7 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
         *      Attr-%d
         */
        if (strncasecmp(p, "Attr-", 5) != 0) {
-               librad_log("Invalid format in attribute name \"%s\"", attribute);
+               fr_strerror_printf("Invalid format in attribute name \"%s\"", attribute);
                return NULL;
        }
 
@@ -1263,7 +1373,7 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
         *      Invalid, or trailing text after number.
         */
        if ((attr == 0) || *q) {
-               librad_log("Invalid value in attribute name \"%s\"", attribute);
+               fr_strerror_printf("Invalid value in attribute name \"%s\"", attribute);
                return NULL;
        }
 
@@ -1276,7 +1386,7 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
                if (!dv) {
                        if (attr > 255) {
                        attr_error:
-                               librad_log("Invalid attribute number in attribute name \"%s\"", attribute);
+                               fr_strerror_printf("Invalid attribute number in attribute name \"%s\"", attribute);
                                return NULL;
                        }
 
@@ -1289,28 +1399,28 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
                                if (attr > 65535) goto attr_error;
                                break;
 
-                       case 4: /* Internal limitations! */
-                               if (attr > 65535) goto attr_error;
+                       case 4:
                                break;
 
                        default:
-                               librad_log("Internal sanity check failed");
+                               fr_strerror_printf("Internal sanity check failed");
                                return NULL;
                }
        }
 
-       attr |= vendor << 16;
-
        /*
         *      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 = paircreate(attr, PW_TYPE_OCTETS)) == NULL) {
-               librad_log("out of memory");
+       if ((vp = paircreate(attr, vendor, PW_TYPE_OCTETS)) == NULL) {
+               fr_strerror_printf("out of memory");
                return NULL;
        }
 
+       vp->operator = (operator == 0) ? T_OP_EQ : operator;
+       if (!value) return vp;
+
        size = strlen(value + 2);
 
        /*
@@ -1332,7 +1442,7 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
        }
 
        if (fr_hex2bin(value + 2, vp->vp_octets, size) != vp->length) {
-               librad_log("Invalid hex string");
+               fr_strerror_printf("Invalid hex string");
                free(vp);
                return NULL;
        }
@@ -1353,8 +1463,6 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
                break;
        }
        
-       vp->operator = (operator == 0) ? T_OP_EQ : operator;
-
        return vp;
 }
 
@@ -1369,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.
@@ -1382,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 */
@@ -1399,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;
@@ -1409,12 +1519,12 @@ 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 = pairalloc(da)) == NULL) {
-               librad_log("out of memory");
+               fr_strerror_printf("out of memory");
                return NULL;
        }
        vp->operator = (operator == 0) ? T_OP_EQ : operator;
@@ -1427,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] == ':') {
@@ -1476,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
        }
 
        /*
@@ -1555,7 +1649,7 @@ VALUE_PAIR *pairread(const char **ptr, FR_TOKEN *eol)
 {
        char            buf[64];
        char            attr[64];
-       char            value[512], *q;
+       char            value[1024], *q;
        const char      *p;
        FR_TOKEN        token, t, xlat;
        VALUE_PAIR      *vp;
@@ -1568,13 +1662,13 @@ VALUE_PAIR *pairread(const char **ptr, FR_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;
        }
 
@@ -1589,14 +1683,14 @@ VALUE_PAIR *pairread(const char **ptr, FR_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--;
        }
@@ -1607,14 +1701,14 @@ VALUE_PAIR *pairread(const char **ptr, FR_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;
        }
 
@@ -1624,7 +1718,7 @@ VALUE_PAIR *pairread(const char **ptr, FR_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;
        }
 
@@ -1649,7 +1743,7 @@ VALUE_PAIR *pairread(const char **ptr, FR_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);
@@ -1662,17 +1756,51 @@ VALUE_PAIR *pairread(const char **ptr, FR_TOKEN *eol)
                        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;
                }
 
@@ -1777,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;
                        }
@@ -1807,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)
 {
@@ -1836,7 +1966,7 @@ int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
                                          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;
                        }
@@ -1868,7 +1998,6 @@ 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;
@@ -1876,11 +2005,10 @@ int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
                        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;
                }
 
                /*
@@ -1930,7 +2058,6 @@ 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);