#include <freeradius-devel/ident.h>
RCSID("$Id$")
-#include <freeradius-devel/autoconf.h>
-
-#include <sys/types.h>
+#include <freeradius-devel/libradius.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include <ctype.h>
#ifdef HAVE_MALLOC_H
# include <regex.h>
#endif
-#include <freeradius-devel/missing.h>
-#include <freeradius-devel/libradius.h>
-
static const char *months[] = {
"jan", "feb", "mar", "apr", "may", "jun",
"jul", "aug", "sep", "oct", "nov", "dec" };
-
/*
- * Create a new valuepair.
+ * This padding is necessary only for attributes that are NOT
+ * in the dictionary, and then only because the rest of the
+ * code accesses vp->name directly, rather than through an
+ * accessor function.
+ *
+ * The name padding only has to large enough for:
+ *
+ * Vendor-65535-Attr-65535
+ *
+ * i.e. 23 characters, plus a zero. We add another 8 bytes for
+ * padding, because the VALUE_PAIR structure may be un-aligned.
+ *
+ * The result is that for the normal case, the server uses a less
+ * memory (36 bytes * number of VALUE_PAIRs).
*/
-VALUE_PAIR *paircreate(int attr, int type)
-{
- VALUE_PAIR *vp;
- DICT_ATTR *da;
+#define FR_VP_NAME_PAD (32)
+#define FR_VP_NAME_LEN (24)
- if ((vp = malloc(sizeof(VALUE_PAIR))) == NULL) {
- librad_log("out of memory");
- return NULL;
- }
- memset(vp, 0, sizeof(VALUE_PAIR));
- vp->attribute = attr;
- vp->operator = T_OP_EQ;
- vp->type = type;
+VALUE_PAIR *pairalloc(DICT_ATTR *da)
+{
+ size_t name_len = 0;
+ VALUE_PAIR *vp;
/*
- * Dictionary type over-rides what the caller says.
+ * Not in the dictionary: the name is allocated AFTER
+ * the VALUE_PAIR struct.
*/
- if ((da = dict_attrbyvalue(attr)) != NULL) {
- strcpy(vp->name, da->name);
+ if (!da) name_len = FR_VP_NAME_PAD;
+
+ vp = malloc(sizeof(*vp) + name_len);
+ if (!vp) return NULL;
+ memset(vp, 0, sizeof(*vp));
+
+ if (da) {
+ vp->attribute = da->attr;
+ vp->vendor = da->vendor;
vp->type = da->type;
+ vp->name = da->name;
vp->flags = da->flags;
- } else if (VENDOR(attr) == 0) {
- sprintf(vp->name, "Attr-%u", attr);
} else {
- DICT_VENDOR *v;
-
- v = dict_vendorbyvalue(VENDOR(attr));
- if (v) {
- sprintf(vp->name, "%s-Attr-%u",
- v->name, attr & 0xffff);
- } else {
- sprintf(vp->name, "Vendor-%u-Attr-%u",
- VENDOR(attr), attr & 0xffff);
- }
+ vp->attribute = 0;
+ vp->vendor = 0;
+ vp->type = PW_TYPE_OCTETS;
+ vp->name = NULL;
+ memset(&vp->flags, 0, sizeof(vp->flags));
+ vp->flags.unknown_attr = 1;
}
+
switch (vp->type) {
case PW_TYPE_BYTE:
vp->length = 1;
case PW_TYPE_INTEGER:
case PW_TYPE_IPADDR:
case PW_TYPE_DATE:
+ case PW_TYPE_SIGNED:
vp->length = 4;
break;
vp->length = sizeof(vp->vp_ipv6prefix);
break;
+ case PW_TYPE_ETHERNET:
+ vp->length = sizeof(vp->vp_ether);
+ break;
+
+ case PW_TYPE_TLV:
+ vp->vp_tlv = NULL;
+ vp->length = 0;
+ break;
+
+ case PW_TYPE_COMBO_IP:
default:
vp->length = 0;
break;
}
/*
+ * Create a new valuepair.
+ */
+VALUE_PAIR *paircreate_raw(int attr, int vendor, int type, VALUE_PAIR *vp)
+{
+ char *p = (char *) (vp + 1);
+
+ if (!vp->flags.unknown_attr) {
+ pairfree(&vp);
+ return NULL;
+ }
+
+ vp->vendor = vendor;
+ vp->attribute = attr;
+ vp->operator = T_OP_EQ;
+ vp->name = p;
+ vp->type = type;
+ vp->length = 0;
+ memset(&vp->flags, 0, sizeof(vp->flags));
+ vp->flags.unknown_attr = 1;
+
+ if (!vp_print_name(p, FR_VP_NAME_LEN, vp->attribute, vp->vendor)) {
+ free(vp);
+ return NULL;
+ }
+
+ return vp;
+}
+
+/*
+ * Create a new valuepair.
+ */
+VALUE_PAIR *paircreate(int attr, int vendor, int type)
+{
+ VALUE_PAIR *vp;
+ DICT_ATTR *da;
+
+ da = dict_attrbyvalue(attr, vendor);
+ if ((vp = pairalloc(da)) == NULL) {
+ fr_strerror_printf("out of memory");
+ return NULL;
+ }
+ vp->operator = T_OP_EQ;
+
+ /*
+ * It isn't in the dictionary: update the name.
+ */
+ if (!da) return paircreate_raw(attr, vendor, type, vp);
+
+ return vp;
+}
+
+/*
* release the memory used by a single attribute-value pair
* just a wrapper around free() for now.
*/
void pairbasicfree(VALUE_PAIR *pair)
{
+ if (pair->type == PW_TYPE_TLV) free(pair->vp_tlv);
/* clear the memory here */
memset(pair, 0, sizeof(*pair));
free(pair);
/*
* 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 {
* Found the first attribute, replace it,
* and return.
*/
- if (i->attribute == replace->attribute) {
+ if ((i->attribute == replace->attribute) &&
+ (i->vendor == replace->vendor)) {
*prev = 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;
last = &first;
while (vp) {
- if (attr >= 0 && vp->attribute != attr) {
+ if ((attr > 0) &&
+ !((vp->attribute == attr) && (vp->vendor == vendor))) {
vp = vp->next;
continue;
}
- if ((n = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
- librad_log("out of memory");
- return first;
- }
- memcpy(n, vp, sizeof(VALUE_PAIR));
- n->next = NULL;
+
+ n = paircopyvp(vp);
+ if (!n) return first;
*last = n;
last = &n->next;
vp = vp->next;
*/
VALUE_PAIR *paircopy(VALUE_PAIR *vp)
{
- return paircopy2(vp, -1);
+ return paircopy2(vp, 0, 0);
}
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) {
/*
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
memcpy(found, i, sizeof(*found));
found->next = mynext;
- pairdelete(&found->next, found->attribute);
+ pairdelete(&found->next, found->attribute, found->vendor);
/*
* 'tailto' may have been
/*
* 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;
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.
*/
* Turn printable string into time_t
* Returns -1 on error, 0 on OK.
*/
-static int gettime(const char *valstr, uint32_t *lvalue)
+static int gettime(const char *valstr, time_t *date)
{
int i;
time_t t;
/*
* Test for unix timestamp date
*/
- *lvalue = strtoul(valstr, &tail, 10);
+ *date = strtoul(valstr, &tail, 10);
if (*tail == '\0') {
return 0;
}
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]);
}
/*
t = mktime(tm);
if (t == (time_t) -1) return -1;
- *lvalue = t;
+ *date = t;
return 0;
}
+static const char *hextab = "0123456789abcdef";
/*
* Parse a string value into a given VALUE_PAIR
* double-check the parsed value, to be sure it's legal for that
* type (length, etc.)
*/
+static uint32_t getint(const char *value, char **end)
+{
+ if ((value[0] == '0') && (value[1] == 'x')) {
+ return strtoul(value, end, 16);
+ }
+
+ return strtoul(value, end, 10);
+}
+
+static int check_for_whitespace(const char *value)
+{
+ while (*value) {
+ if (!isspace((int) *value)) return 0;
+
+ value++;
+ }
+
+ return 1;
+}
+
+
VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
{
char *p, *s=0;
const char *cp, *cs;
+ int x;
+ size_t length;
DICT_VALUE *dval;
+ if (!value) return NULL;
+
/*
* Even for integers, dates and ip addresses we
* keep the original string in vp->vp_strvalue.
*/
- strlcpy((char *)vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
- vp->length = strlen(vp->vp_strvalue);
+ if (vp->type != PW_TYPE_TLV) {
+ strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
+ vp->length = strlen(vp->vp_strvalue);
+ }
switch(vp->type) {
case PW_TYPE_STRING:
/*
- * Already handled above.
+ * Do escaping here
*/
+ p = vp->vp_strvalue;
+ cp = value;
+ length = 0;
+
+ while (*cp && (length < (sizeof(vp->vp_strvalue) - 1))) {
+ char c = *cp++;
+
+ if (c == '\\') {
+ switch (*cp) {
+ case 'r':
+ c = '\r';
+ cp++;
+ break;
+ case 'n':
+ c = '\n';
+ cp++;
+ break;
+ case 't':
+ c = '\t';
+ cp++;
+ break;
+ case '"':
+ c = '"';
+ cp++;
+ break;
+ case '\'':
+ c = '\'';
+ cp++;
+ break;
+ case '\\':
+ c = '\\';
+ cp++;
+ break;
+ case '`':
+ c = '`';
+ cp++;
+ break;
+ case '\0':
+ c = '\\'; /* no cp++ */
+ break;
+ default:
+ if ((cp[0] >= '0') &&
+ (cp[0] <= '9') &&
+ (cp[1] >= '0') &&
+ (cp[1] <= '9') &&
+ (cp[2] >= '0') &&
+ (cp[2] <= '9') &&
+ (sscanf(cp, "%3o", &x) == 1)) {
+ c = x;
+ cp += 3;
+ } /* else just do '\\' */
+ }
+ }
+ *p++ = c;
+ length++;
+ }
+ vp->vp_strvalue[length] = '\0';
+ vp->length = length;
break;
case PW_TYPE_IPADDR:
* 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;
p = NULL;
cs = value;
}
-
+
{
- lrad_ipaddr_t ipaddr;
+ fr_ipaddr_t ipaddr;
if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
- librad_log("Failed to find IP address for %s", cs);
+ free(s);
+ fr_strerror_printf("Failed to find IP address for %s", cs);
return NULL;
}
- vp->lvalue = ipaddr.ipaddr.ip4addr.s_addr;
+ vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
}
- if (s) free(s);
+ free(s);
vp->length = 4;
break;
case PW_TYPE_BYTE:
+ vp->length = 1;
+
/*
* Note that ALL integers are unsigned!
*/
- vp->lvalue = (uint32_t) strtoul(value, &p, 10);
+ vp->vp_integer = getint(value, &p);
if (!*p) {
- if (vp->lvalue > 255) {
- librad_log("Byte value \"%s\" is larger than 255", value);
+ if (vp->vp_integer > 255) {
+ 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->lvalue = 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->lvalue = (uint32_t) strtoul(value, &p, 10);
+ vp->vp_integer = getint(value, &p);
+ vp->length = 2;
if (!*p) {
- if (vp->lvalue > 65535) {
- librad_log("Byte value \"%s\" is larger than 65535", value);
+ if (vp->vp_integer > 65535) {
+ 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->lvalue = 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->lvalue = (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->lvalue = dval->value;
- vp->length = 4;
+ vp->vp_integer = dval->value;
break;
case PW_TYPE_DATE:
- if (gettime(value, &vp->lvalue) < 0) {
- librad_log("failed to parse time string "
- "\"%s\"", value);
- return NULL;
+ {
+ /*
+ * time_t may be 64 bits, whule vp_date
+ * MUST be 32-bits. We need an
+ * intermediary variable to handle
+ * the conversions.
+ */
+ time_t date;
+
+ if (gettime(value, &date) < 0) {
+ fr_strerror_printf("failed to parse time string "
+ "\"%s\"", value);
+ return NULL;
+ }
+
+ vp->vp_date = date;
}
vp->length = 4;
break;
+
case PW_TYPE_ABINARY:
#ifdef ASCEND_BINARY
if (strncasecmp(value, "0x", 2) == 0) {
}
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;
* die.
*/
if ((strlen(cp) & 0x01) != 0) {
- librad_log("Hex string is not an even length string.");
+ fr_strerror_printf("Hex string is not an even length string.");
return NULL;
}
-
-
+
+
while (*cp &&
(vp->length < MAX_STRING_LEN)) {
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;
}
break;
case PW_TYPE_IFID:
- if (ifid_aton(value, (unsigned char *) vp->vp_strvalue) == NULL) {
- librad_log("failed to parse interface-id "
+ if (ifid_aton(value, (void *) &vp->vp_ifid) == NULL) {
+ fr_strerror_printf("failed to parse interface-id "
"string \"%s\"", value);
return NULL;
}
vp->length = 8;
- vp->vp_strvalue[vp->length] = '\0';
break;
case PW_TYPE_IPV6ADDR:
- if (inet_pton(AF_INET6, value, vp->vp_strvalue) <= 0) {
- librad_log("failed to parse IPv6 address "
- "string \"%s\"", value);
- return NULL;
+ {
+ fr_ipaddr_t ipaddr;
+
+ if (ip_hton(value, AF_INET6, &ipaddr) < 0) {
+ char buffer[1024];
+
+ strlcpy(buffer, fr_strerror(), sizeof(buffer));
+
+ fr_strerror_printf("failed to parse IPv6 address "
+ "string \"%s\": %s", value, buffer);
+ return NULL;
+ }
+ vp->vp_ipv6addr = ipaddr.ipaddr.ip6addr;
+ vp->length = 16; /* length of IPv6 address */
}
- vp->length = 16; /* length of IPv6 address */
- vp->vp_strvalue[vp->length] = '\0';
break;
- /*
- * Anything else.
- */
+
case PW_TYPE_IPV6PREFIX:
p = strchr(value, '/');
if (!p || ((p - value) >= 256)) {
- librad_log("invalid IPv6 prefix "
+ fr_strerror_printf("invalid IPv6 prefix "
"string \"%s\"", value);
return NULL;
} else {
unsigned int prefix;
char buffer[256], *eptr;
-
+
memcpy(buffer, value, p - value);
buffer[p - value] = '\0';
-
- if (inet_pton(AF_INET6, buffer, vp->vp_strvalue + 2) <= 0) {
- librad_log("failed to parse IPv6 address "
+
+ if (inet_pton(AF_INET6, buffer, vp->vp_octets + 2) <= 0) {
+ fr_strerror_printf("failed to parse IPv6 address "
"string \"%s\"", value);
return NULL;
}
-
+
prefix = strtoul(p + 1, &eptr, 10);
if ((prefix > 128) || *eptr) {
- librad_log("failed to parse IPv6 address "
+ fr_strerror_printf("failed to parse IPv6 address "
"string \"%s\"", value);
return NULL;
}
- vp->vp_strvalue[1] = prefix;
+ vp->vp_octets[1] = prefix;
}
- vp->vp_strvalue[0] = '\0';
+ vp->vp_octets[0] = '\0';
vp->length = 16 + 2;
break;
+ case PW_TYPE_ETHERNET:
+ {
+ const char *c1, *c2;
+
+ length = 0;
+ cp = value;
+ while (*cp) {
+ if (cp[1] == ':') {
+ c1 = hextab;
+ c2 = memchr(hextab, tolower((int) cp[0]), 16);
+ cp += 2;
+ } else if ((cp[1] != '\0') &&
+ ((cp[2] == ':') ||
+ (cp[2] == '\0'))) {
+ c1 = memchr(hextab, tolower((int) cp[0]), 16);
+ c2 = memchr(hextab, tolower((int) cp[1]), 16);
+ cp += 2;
+ if (*cp == ':') cp++;
+ } else {
+ c1 = c2 = NULL;
+ }
+ if (!c1 || !c2 || (length >= sizeof(vp->vp_ether))) {
+ fr_strerror_printf("failed to parse Ethernet address \"%s\"", value);
+ return NULL;
+ }
+ vp->vp_ether[length] = ((c1-hextab)<<4) + (c2-hextab);
+ length++;
+ }
+ }
+ vp->length = 6;
+ break;
+
+ case PW_TYPE_COMBO_IP:
+ if (inet_pton(AF_INET6, value, vp->vp_strvalue) > 0) {
+ vp->type = PW_TYPE_IPV6ADDR;
+ vp->length = 16; /* length of IPv6 address */
+ vp->vp_strvalue[vp->length] = '\0';
+
+ } else {
+ fr_ipaddr_t ipaddr;
+
+ if (ip_hton(value, AF_INET, &ipaddr) < 0) {
+ fr_strerror_printf("Failed to find IPv4 address for %s", value);
+ return NULL;
+ }
+
+ vp->type = PW_TYPE_IPADDR;
+ vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
+ vp->length = 4;
+ }
+ break;
+
+ case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
+ vp->vp_signed = (int32_t) strtol(value, &p, 10);
+ vp->length = 4;
+ break;
+
+ case PW_TYPE_TLV: /* don't use this! */
+ if (strncasecmp(value, "0x", 2) != 0) {
+ fr_strerror_printf("Invalid TLV specification");
+ return NULL;
+ }
+ length = strlen(value + 2) / 2;
+ if (vp->length < length) {
+ free(vp->vp_tlv);
+ vp->vp_tlv = NULL;
+ }
+ vp->vp_tlv = malloc(length);
+ if (!vp->vp_tlv) {
+ fr_strerror_printf("No memory");
+ return NULL;
+ }
+ if (fr_hex2bin(value + 2, vp->vp_tlv,
+ length) != length) {
+ fr_strerror_printf("Invalid hex data in TLV");
+ return NULL;
+ }
+ vp->length = length;
+ break;
+
+ /*
+ * Anything else.
+ */
default:
- librad_log("unknown attribute type %d", vp->type);
+ fr_strerror_printf("unknown attribute type %d", vp->type);
return NULL;
}
*
* Attr-%d
* Vendor-%d-Attr-%d
+ * VendorName-Attr-%d
*/
static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
int operator)
{
- int attr;
- const char *p;
+ int attr, vendor;
+ size_t size;
+ const char *p = attribute;
+ char *q;
VALUE_PAIR *vp;
/*
* Unknown attributes MUST be of type 'octets'
*/
if (value && (strncasecmp(value, "0x", 2) != 0)) {
- goto error;
+ fr_strerror_printf("Invalid octet string \"%s\" for attribute name \"%s\"", value, attribute);
+ return NULL;
}
+ vendor = 0;
+
/*
- * Attr-%d
+ * Pull off vendor prefix first.
*/
- if (strncasecmp(attribute, "Attr-", 5) == 0) {
- attr = atoi(attribute + 5);
- p = attribute + 5;
- p += strspn(p, "0123456789");
- if (*p != 0) goto error;
+ if (strncasecmp(p, "Attr-", 5) != 0) {
+ if (strncasecmp(p, "Vendor-", 7) == 0) {
+ vendor = (int) strtol(p + 7, &q, 10);
+ if ((vendor == 0) || (vendor > FR_MAX_VENDOR)) {
+ fr_strerror_printf("Invalid vendor value in attribute name \"%s\"", attribute);
+ return NULL;
+ }
- /*
- * Vendor-%d-Attr-%d
- */
- } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
- int vendor;
+ p = q;
- vendor = atoi(attribute + 7);
- if ((vendor == 0) || (vendor > 65535)) goto error;
+ } else { /* must be vendor name */
+ char buffer[256];
- p = attribute + 7;
- p += strspn(p, "0123456789");
+ q = strchr(p, '-');
- /*
- * Not Vendor-%d-Attr-%d
- */
- if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
+ if (!q) {
+ fr_strerror_printf("Invalid vendor name in attribute name \"%s\"", attribute);
+ return NULL;
+ }
- p += 6;
- attr = atoi(p);
+ if ((size_t) (q - p) >= sizeof(buffer)) {
+ fr_strerror_printf("Vendor name too long in attribute name \"%s\"", attribute);
+ return NULL;
+ }
- p += strspn(p, "0123456789");
- if (*p != 0) goto error;
+ memcpy(buffer, p, (q - p));
+ buffer[q - p] = '\0';
- if ((attr == 0) || (attr > 65535)) goto error;
+ vendor = dict_vendorbyname(buffer);
+ if (!vendor) {
+ fr_strerror_printf("Unknown vendor name in attribute name \"%s\"", attribute);
+ return NULL;
+ }
- attr |= (vendor << 16);
+ p = q;
+ }
- /*
- * VendorName-Attr-%d
- */
- } else if (((p = strchr(attribute, '-')) != NULL) &&
- (strncasecmp(p, "-Attr-", 6) == 0)) {
- int vendor;
- char buffer[256];
+ if (*p != '-') {
+ fr_strerror_printf("Invalid text following vendor definition in attribute name \"%s\"", attribute);
+ return NULL;
+ }
+ p++;
+ }
- if (((size_t) (p - attribute)) >= sizeof(buffer)) goto error;
+ /*
+ * Attr-%d
+ */
+ if (strncasecmp(p, "Attr-", 5) != 0) {
+ fr_strerror_printf("Invalid format in attribute name \"%s\"", attribute);
+ return NULL;
+ }
- memcpy(buffer, attribute, p - attribute);
- buffer[p - attribute] = '\0';
+ attr = strtol(p + 5, &q, 10);
- vendor = dict_vendorbyname(buffer);
- if (vendor == 0) goto error;
+ /*
+ * Invalid, or trailing text after number.
+ */
+ if ((attr == 0) || *q) {
+ fr_strerror_printf("Invalid value in attribute name \"%s\"", attribute);
+ return NULL;
+ }
- p += 6;
- attr = atoi(p);
+ /*
+ * Double-check the size of attr.
+ */
+ if (vendor) {
+ DICT_VENDOR *dv = dict_vendorbyvalue(vendor);
- p += strspn(p, "0123456789");
- if (*p != 0) goto error;
+ if (!dv) {
+ if (attr > 255) {
+ attr_error:
+ fr_strerror_printf("Invalid attribute number in attribute name \"%s\"", attribute);
+ return NULL;
+ }
- if ((attr == 0) || (attr > 65535)) goto error;
+ } else switch (dv->type) {
+ case 1:
+ if (attr > 255) goto attr_error;
+ break;
- attr |= (vendor << 16);
+ case 2:
+ if (attr > 65535) goto attr_error;
+ break;
- } else { /* very much unknown: die */
- error:
- librad_log("Unknown attribute \"%s\"", attribute);
- return NULL;
+ case 4:
+ break;
+
+ default:
+ fr_strerror_printf("Internal sanity check failed");
+ return NULL;
+ }
}
/*
- * We've now parsed the attribute properly, and verified
- * it to have value 'octets'. Let's create it.
+ * We've now parsed the attribute properly, Let's create
+ * it. This next stop also looks the attribute up in the
+ * dictionary, and creates the appropriate type for it.
*/
- if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
- librad_log("out of memory");
+ if ((vp = paircreate(attr, vendor, PW_TYPE_OCTETS)) == NULL) {
+ fr_strerror_printf("out of memory");
return NULL;
}
- memset(vp, 0, sizeof(VALUE_PAIR));
- vp->type = PW_TYPE_OCTETS;
+
+ vp->operator = (operator == 0) ? T_OP_EQ : operator;
+ if (!value) return vp;
+
+ size = strlen(value + 2);
/*
- * It may not be valid hex characters. If not, die.
+ * We may be reading something like Attr-5. i.e.
+ * who-ever wrote the text didn't understand it, but we
+ * do.
*/
- if (pairparsevalue(vp, value) == NULL) {
- pairfree(&vp);
- return NULL;
+ switch (vp->type) {
+ default:
+ if (size == (vp->length * 2)) break;
+ vp->type = PW_TYPE_OCTETS;
+ /* FALL-THROUGH */
+
+ case PW_TYPE_STRING:
+ case PW_TYPE_OCTETS:
+ case PW_TYPE_ABINARY:
+ vp->length = size >> 1;
+ break;
}
- if (VENDOR(attr) == 0) {
- sprintf(vp->name, "Attr-%u", attr);
- } else {
- sprintf(vp->name, "Vendor-%u-Attr-%u",
- VENDOR(attr), attr & 0xffff);
+ if (fr_hex2bin(value + 2, vp->vp_octets, size) != vp->length) {
+ fr_strerror_printf("Invalid hex string");
+ free(vp);
+ return NULL;
}
- vp->attribute = attr;
- vp->operator = (operator == 0) ? T_OP_EQ : operator;
- vp->next = NULL;
-
+ /*
+ * Move contents around based on type. This is
+ * to work around the historical use of "lvalue".
+ */
+ switch (vp->type) {
+ case PW_TYPE_DATE:
+ case PW_TYPE_IPADDR:
+ case PW_TYPE_INTEGER:
+ memcpy(&vp->lvalue, vp->vp_octets, sizeof(vp->lvalue));
+ vp->vp_strvalue[0] = '\0';
+ break;
+
+ default:
+ break;
+ }
+
return vp;
}
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.
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 */
*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;
* It's not found in the dictionary, so we use
* another method to create the attribute.
*/
- if ((da = dict_attrbyname(attribute)) == NULL) {
- return pairmake_any(attribute, value, operator);
+ if ((da = dict_attrbyname(attrname)) == NULL) {
+ return pairmake_any(attrname, value, operator);
}
- if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
- librad_log("out of memory");
+ if ((vp = pairalloc(da)) == NULL) {
+ fr_strerror_printf("out of memory");
return NULL;
}
-
- memset(vp, 0, sizeof(VALUE_PAIR));
- vp->attribute = da->attr;
- vp->type = da->type;
vp->operator = (operator == 0) ? T_OP_EQ : operator;
- strcpy(vp->name, da->name);
- vp->flags = da->flags;
- vp->next = NULL;
/* Check for a tag in the 'Merit' format of:
* :Tag:Value. Print an error if we already found
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] == ':') {
*/
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
}
/*
* Read a valuepair from a buffer, and advance pointer.
* Sets *eol to T_EOL if end of line was encountered.
*/
-VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
+VALUE_PAIR *pairread(const char **ptr, FR_TOKEN *eol)
{
char buf[64];
char attr[64];
- char value[512];
- char *p, *q;
- LRAD_TOKEN token, t, xlat;
+ char value[1024], *q;
+ const char *p;
+ FR_TOKEN token, t, xlat;
VALUE_PAIR *vp;
size_t len;
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;
}
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--;
}
/* 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;
}
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;
}
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);
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;
}
* Read one line of attribute/value pairs. This might contain
* multiple pairs seperated by comma's.
*/
-LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
+FR_TOKEN userparse(const char *buffer, VALUE_PAIR **first_pair)
{
VALUE_PAIR *vp;
- char *p;
- LRAD_TOKEN last_token = T_OP_INVALID;
- LRAD_TOKEN previous_token;
+ const char *p;
+ FR_TOKEN last_token = T_OP_INVALID;
+ FR_TOKEN previous_token;
/*
* We allow an empty line.
VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
{
char buf[8192];
- LRAD_TOKEN last_token = T_EOL;
+ FR_TOKEN last_token = T_EOL;
VALUE_PAIR *vp;
VALUE_PAIR *list;
int error = 0;
last_token = userparse(buf, &vp);
if (!vp) {
if (last_token != T_EOL) {
- librad_perror("%s", errprefix);
+ fr_perror("%s", errprefix);
error = 1;
break;
}
* 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)
{
{
regex_t reg;
char buffer[MAX_STRING_LEN * 4 + 1];
-
+
compare = regcomp(®, one->vp_strvalue,
REG_EXTENDED);
if (compare != 0) {
regerror(compare, ®, 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;
}
default: /* we're OK */
break;
}
-
+
/*
* After doing the previous check for special comparisons,
* do the per-type comparison here.
case PW_TYPE_OCTETS:
{
size_t length;
- const uint8_t *p, *q;
if (one->length < two->length) {
length = one->length;
} else {
length = two->length;
}
-
- p = two->vp_octets;
- q = one->vp_octets;
- while (length) {
- compare = ((int) *p) - ((int) *q);
- if (compare != 0) goto type_switch;
+
+ if (length) {
+ compare = memcmp(two->vp_octets, one->vp_octets,
+ length);
+ if (compare != 0) break;
}
/*
break;
case PW_TYPE_STRING:
- if (one->flags.caseless) {
- compare = strcasecmp(two->vp_strvalue,
- one->vp_strvalue);
- } else {
- compare = strcmp(two->vp_strvalue,
- one->vp_strvalue);
- }
+ compare = strcmp(two->vp_strvalue, one->vp_strvalue);
break;
-
+
case PW_TYPE_BYTE:
case PW_TYPE_SHORT:
case PW_TYPE_INTEGER:
case PW_TYPE_DATE:
- compare = two->lvalue - one->lvalue;
+ compare = two->vp_integer - one->vp_integer;
break;
case PW_TYPE_IPADDR:
compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
sizeof(two->vp_ipv6addr));
break;
-
+
case PW_TYPE_IPV6PREFIX:
compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
sizeof(two->vp_ipv6prefix));
/*
* Now do the operator comparison.
*/
- type_switch:
switch (one->operator) {
case T_OP_CMP_EQ:
return (compare == 0);
-
+
case T_OP_NE:
return (compare != 0);
-
+
case T_OP_LT:
return (compare < 0);
-
+
case T_OP_GT:
return (compare > 0);