Signed / unsigned fixes and function prototypes
[freeradius.git] / src / lib / valuepair.c
index 97c7b93..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,19 +181,7 @@ VALUE_PAIR *paircreate(int attr, int type)
        /*
         *      It isn't in the dictionary: update the name.
         */
-       if (!da) {
-               char *p = (char *) (vp + 1);
-               
-               vp->vendor = VENDOR(attr);
-               vp->attribute = attr;
-               vp->name = p;
-               vp->type = type; /* be forgiving */
-
-               if (!vp_print_name(p, FR_VP_NAME_LEN, vp->attribute)) {
-                       free(vp);
-                       return NULL;
-               }
-       }
+       if (!da) return paircreate_raw(attr, vendor, type, vp);
 
        return vp;
 }
@@ -169,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);
@@ -198,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 {
@@ -268,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;
 
                        /*
@@ -308,11 +338,25 @@ VALUE_PAIR *paircopyvp(const VALUE_PAIR *vp)
        }
        
        if ((n = malloc(sizeof(*n) + name_len)) == NULL) {
-               librad_log("out of memory");
+               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;
 }
 
@@ -320,7 +364,7 @@ VALUE_PAIR *paircopyvp(const VALUE_PAIR *vp)
 /*
  *     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;
 
@@ -328,7 +372,8 @@ 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;
                }
@@ -348,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);
 }
 
 
@@ -423,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) {
 
                          /*
@@ -435,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
@@ -530,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
@@ -576,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;
@@ -594,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.
                 */
@@ -776,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]);
        }
 
        /*
@@ -806,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;
@@ -814,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:
@@ -855,6 +933,10 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                                                c = '\'';
                                                cp++;
                                                break;
+                                       case '\\':
+                                               c = '\\';
+                                               cp++;
+                                               break;
                                        case '`':
                                                c = '`';
                                                cp++;
@@ -878,6 +960,7 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                                *p++ = c;
                                length++;
                        }
+                       vp->vp_strvalue[length] = '\0';
                        vp->length = length;
                        break;
 
@@ -911,7 +994,7 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
 
                                if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
                                        free(s);
-                                       librad_log("Failed to find IP address for %s", cs);
+                                       fr_strerror_printf("Failed to find IP address for %s", cs);
                                        return NULL;
                                }
 
@@ -922,84 +1005,58 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                        break;
 
                case PW_TYPE_BYTE:
-                       if (value && (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:
@@ -1013,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;
                                }
@@ -1031,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;
@@ -1042,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) {
@@ -1058,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;
                                }
 
@@ -1068,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;
                                        }
 
@@ -1081,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;
                        }
@@ -1089,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 {
@@ -1111,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;
                                }
@@ -1150,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);
@@ -1160,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;
        }
 
@@ -1192,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.
@@ -1204,8 +1318,8 @@ 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;
                        }
 
@@ -1217,12 +1331,12 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
                        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;
                        }
 
@@ -1231,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;
                        }
 
@@ -1239,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++;
@@ -1249,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;
        }
 
@@ -1259,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;
        }
 
@@ -1272,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;
                        }
 
@@ -1285,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);
 
        /*
@@ -1328,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;
        }
@@ -1349,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;
 }
 
@@ -1365,10 +1477,6 @@ 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;
 
@@ -1380,7 +1488,7 @@ 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;
        }
 
@@ -1401,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;
@@ -1416,7 +1524,7 @@ VALUE_PAIR *pairmake(const char *attribute, const char *value, int 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;
@@ -1429,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] == ':') {
@@ -1478,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("Regular expressions not enabled in this build, error in attribute %s",
-                               vp->name);
-               pairbasicfree(vp);
-               return NULL;
-#endif
        }
 
        /*
@@ -1557,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;
@@ -1570,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;
        }
 
@@ -1591,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--;
        }
@@ -1609,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;
        }
 
@@ -1626,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;
        }
 
@@ -1651,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);
@@ -1664,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;
                }
 
@@ -1779,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;
                        }
@@ -1809,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)
 {
@@ -1838,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;
                        }