# endif
#endif
-#define attribute_eq(_x, _y) ((_x && _y) && (_x->da == _y->da) && (_x->tag == _y->tag))
+
/** Free a VALUE_PAIR
*
vp_cursor_t cursor;
VALUE_PAIR *i;
+ /* List head may be NULL if it contains no VPs */
+ if (!vp) return NULL;
+
VERIFY_LIST(vp);
for (i = fr_cursor_init(&cursor, &vp);
return;
}
- if (TAG_EQ(filter->tag, list->tag)) {
+ if (!TAG_EQ(filter->tag, list->tag)) {
fr_strerror_printf("Attribute \"%s\" tag \"%i\" didn't match filter tag \"%i\"",
list->da->name, list->tag, filter->tag);
return;
check = fr_cursor_init(&filter_cursor, &filter);
match = fr_cursor_init(&list_cursor, &list);
-
- while (true) {
- if (!match && !check) goto mismatch;
+ while (match || check) {
+ /*
+ * Lists are of different lengths
+ */
+ if ((!match && check) || (check && !match)) goto mismatch;
/*
* The lists are sorted, so if the first
* attributes aren't of the same type, then we're
* done.
*/
- if (!attribute_eq(check, match)) goto mismatch;
+ if (!ATTRIBUTE_EQ(check, match)) goto mismatch;
/*
* They're of the same type, but don't have the
* Note that the RFCs say that for attributes of
* the same type, order is important.
*/
- if (!paircmp(check, match)) goto mismatch;
+ if (paircmp(check, match) != 1) goto mismatch;
check = fr_cursor_next(&filter_cursor);
match = fr_cursor_next(&list_cursor);
-
- /*
- * One list ended earlier than the others, they
- * didn't match.
- */
- if (!match || !check) break;
}
return true;
/*
* Were processing check attributes of a new type.
*/
- if (!attribute_eq(last_check, check)) {
+ if (!ATTRIBUTE_EQ(last_check, check)) {
/*
* Record the start of the matching attributes in the pair list
* For every other operator we require the match to be present
* Now iterate over all attributes of the same type.
*/
for (match = fr_cursor_first(&list_cursor);
- attribute_eq(match, check);
+ ATTRIBUTE_EQ(match, check);
match = fr_cursor_next(&list_cursor)) {
/*
* This attribute passed the filter
return n;
}
-/** Copy data from one VP to another
- *
- * Allocate a new pair using da, and copy over the value from the specified
- * vp.
- *
- * @todo Should be able to do type conversions.
- *
- * @param[in] ctx for talloc
- * @param[in] da of new attribute to alloc.
- * @param[in] vp to copy data from.
- * @return the new valuepair.
- */
-VALUE_PAIR *paircopyvpdata(TALLOC_CTX *ctx, DICT_ATTR const *da, VALUE_PAIR const *vp)
-{
- VALUE_PAIR *n;
-
- if (!vp) return NULL;
-
- VERIFY_VP(vp);
-
- /*
- * The types have to be identical, OR the "from" VP has
- * to be octets.
- */
- if (da->type != vp->da->type) {
- int length;
- uint8_t *p;
- VALUE_PAIR const **pvp;
-
- if (vp->da->type == PW_TYPE_OCTETS) {
- /*
- * Decode the data. It may be wrong!
- */
- if (rad_data2vp(da->attr, da->vendor, vp->vp_octets, vp->length, &n) < 0) {
- return NULL;
- }
-
- n->type = VT_DATA;
- return n;
- }
-
- /*
- * Else the destination type is octets
- */
- switch (vp->da->type) {
- default:
- return NULL; /* can't do it */
-
- case PW_TYPE_INTEGER:
- case PW_TYPE_IPADDR:
- case PW_TYPE_DATE:
- case PW_TYPE_IFID:
- case PW_TYPE_IPV6ADDR:
- case PW_TYPE_IPV6PREFIX:
- case PW_TYPE_BYTE:
- case PW_TYPE_SHORT:
- case PW_TYPE_ETHERNET:
- case PW_TYPE_SIGNED:
- case PW_TYPE_INTEGER64:
- case PW_TYPE_IPV4PREFIX:
- break;
- }
-
- n = pairalloc(ctx, da);
- if (!n) return NULL;
-
- p = talloc_array(n, uint8_t, dict_attr_sizes[vp->da->type][1] + 2);
-
- pvp = &vp;
- length = rad_vp2attr(NULL, NULL, NULL, pvp, p, dict_attr_sizes[vp->da->type][1]);
- if (length < 0) {
- pairfree(&n);
- return NULL;
- }
-
- pairmemcpy(n, p + 2, length - 2);
- talloc_free(p);
- return n;
- }
-
- n = pairalloc(ctx, da);
- if (!n) return NULL;
-
- memcpy(n, vp, sizeof(*n));
- n->da = da;
-
- if (n->type == VT_XLAT) {
- n->value.xlat = talloc_typed_strdup(n, n->value.xlat);
- }
-
- if (n->data.ptr) switch (n->da->type) {
- case PW_TYPE_TLV:
- case PW_TYPE_OCTETS:
- n->vp_octets = talloc_memdup(n, vp->vp_octets, n->length);
- talloc_set_type(n->vp_octets, uint8_t);
- break;
-
- case PW_TYPE_STRING:
- n->vp_strvalue = talloc_memdup(n, vp->vp_strvalue, n->length + 1); /* NULL byte */
- talloc_set_type(n->vp_strvalue, char);
- break;
-
- default:
- break;
- }
-
- n->next = NULL;
-
- return n;
-}
-
-
/** Copy a pairlist.
*
* Copy all pairs from 'from' regardless of tag, attribute or vendor.
* Move pairs of a matching attribute number, vendor number and tag from the
* the input list to the output list.
*
+ * @note pairs which are moved have their parent changed to ctx.
+ *
* @note pairfree should be called on the head of the old list to free unmoved
attributes (if they're no longer needed).
*
* @param[in] ctx for talloc
* @param[in,out] to destination list.
* @param[in,out] from source list.
- * @param[in] attr to match, if PW_VENDOR_SPECIFIC and vendor 0, only VSAs will
- * be copied. If 0 and 0, all attributes will match
+ * @param[in] attr to match. If attribute PW_VENDOR_SPECIFIC and vendor 0,
+ * will match (and therefore copy) only VSAs.
+ * If attribute 0 and vendor 0 will match (and therefore copy) all
+ * attributes.
* @param[in] vendor to match.
* @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
*/
}
}
-static char const *hextab = "0123456789abcdef";
+static char const hextab[] = "0123456789abcdef";
/** Convert string value to native attribute value
*
*/
int pairparsevalue(VALUE_PAIR *vp, char const *value, size_t inlen)
{
- char const *cs;
DICT_VALUE *dval;
size_t len;
char buffer[256];
vp->length = len >> 1;
p = talloc_array(vp, uint8_t, vp->length);
- if (fr_hex2bin(p, value + 2, len) != vp->length) {
+ if (fr_hex2bin(p, vp->length, value + 2, len) != vp->length) {
talloc_free(p);
fr_strerror_printf("Invalid hex data");
return -1;
fr_strerror_printf("No memory");
return -1;
}
- if (fr_hex2bin(p, value + 2, len) != vp->length) {
+ if (fr_hex2bin(p, vp->length, value + 2, len) != vp->length) {
fr_strerror_printf("Invalid hex data in TLV");
return -1;
}
}
goto finish;
+ case PW_TYPE_IPV4_ADDR:
+ {
+ fr_ipaddr_t addr;
+
+ if (fr_pton4(&addr, value, inlen, fr_hostname_lookups, false) < 0) return -1;
+
+ /*
+ * We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
+ * print them this way.
+ */
+ if (addr.prefix != 32) {
+ fr_strerror_printf("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted "
+ "for non-prefix types", addr.prefix);
+ return -1;
+ }
+
+ vp->vp_ipaddr = addr.ipaddr.ip4addr.s_addr;
+ vp->length = sizeof(vp->vp_ipaddr);
+ }
+ goto finish;
+
+ case PW_TYPE_IPV4_PREFIX:
+ {
+ fr_ipaddr_t addr;
+
+ if (fr_pton4(&addr, value, inlen, fr_hostname_lookups, false) < 0) return -1;
+
+ vp->vp_ipv4prefix[1] = addr.prefix;
+ memcpy(vp->vp_ipv4prefix + 2, &addr.ipaddr.ip4addr.s_addr, sizeof(vp->vp_ipv4prefix) - 2);
+ vp->length = sizeof(vp->vp_ipv4prefix);
+ }
+ goto finish;
+
+ case PW_TYPE_IPV6_ADDR:
+ {
+ fr_ipaddr_t addr;
+
+ if (fr_pton6(&addr, value, inlen, fr_hostname_lookups, false) < 0) return -1;
+
+ /*
+ * We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
+ * print them this way.
+ */
+ if (addr.prefix != 128) {
+ fr_strerror_printf("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted "
+ "for non-prefix types", addr.prefix);
+ return -1;
+ }
+
+ memcpy(&vp->vp_ipv6addr, &addr.ipaddr.ip6addr.s6_addr, sizeof(vp->vp_ipv6addr));
+ vp->length = sizeof(vp->vp_ipv6addr);
+ }
+ goto finish;
+
+ case PW_TYPE_IPV6_PREFIX:
+ {
+ fr_ipaddr_t addr;
+
+ if (fr_pton6(&addr, value, inlen, fr_hostname_lookups, false) < 0) return -1;
+
+ vp->vp_ipv6prefix[1] = addr.prefix;
+ memcpy(vp->vp_ipv6prefix + 2, &addr.ipaddr.ip6addr.s6_addr, sizeof(vp->vp_ipv6prefix) - 2);
+ vp->length = sizeof(vp->vp_ipv6prefix);
+ }
+ goto finish;
+
default:
break;
}
}
switch(vp->da->type) {
- case PW_TYPE_IPADDR:
- {
- char const *p;
- fr_ipaddr_t ipaddr;
- char ipv4[16];
- /*
- * FIXME: complain if hostname
- * cannot be resolved, or resolve later!
- */
- p = NULL;
-
- /*
- * Convert things which are obviously integers to IP addresses
- *
- * We assume the number is the bigendian representation of the
- * IP address.
- */
- if (is_integer(value)) {
- vp->vp_ipaddr = htonl(atol(value));
- break;
- }
-
- /*
- * Certain applications/databases print IPv4 addresses with a
- * /32 suffix. Strip it off if the mask is 32, else error out.
- */
- p = strchr(value, '/');
- if (p) {
- if ((p[1] != '3') || (p[2] != '2') || (p[3] != '\0')) {
- fr_strerror_printf("Invalid IP address suffix \"%s\". Only '/32' permitted "
- "for non-prefix types", p);
- return -1;
- }
-
- strlcpy(ipv4, value, sizeof(ipv4));
- ipv4[p - value] = '\0';
- cs = ipv4;
- } else {
- cs = value;
- }
-
- if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
- fr_strerror_printf("Failed to find IP address for %s", cs);
- return -1;
- }
-
- vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
- vp->length = 4;
- }
- break;
-
case PW_TYPE_BYTE:
{
char *p;
vp->length = 8;
break;
- case PW_TYPE_IPV6ADDR:
- {
- fr_ipaddr_t ipaddr;
-
- if (ip_hton(value, AF_INET6, &ipaddr) < 0) {
- fr_strerror_printf("failed to parse IPv6 address "
- "string \"%s\": %s", value, fr_strerror());
- return -1;
- }
- vp->vp_ipv6addr = ipaddr.ipaddr.ip6addr;
- vp->length = 16; /* length of IPv6 address */
- }
- break;
-
- case PW_TYPE_IPV6PREFIX:
- {
- char const *p;
- unsigned int prefix;
- char *eptr;
-
- p = strchr(value, '/');
- if (!p || ((p - value) >= 256)) {
- fr_strerror_printf("invalid IPv6 prefix string \"%s\"", value);
- return -1;
- }
-
- /*
- * Copy string to temporary buffer if we didn't do it earlier
- */
- if (inlen == 0) memcpy(buffer, value, p - value);
- buffer[p - value] = '\0';
-
- if (inet_pton(AF_INET6, buffer, vp->vp_ipv6prefix + 2) <= 0) {
- fr_strerror_printf("failed to parse IPv6 address string \"%s\"", value);
- return -1;
- }
-
- prefix = strtoul(p + 1, &eptr, 10);
- if ((prefix > 128) || *eptr) {
- fr_strerror_printf("failed to parse IPv6 address string \"%s\"", value);
- return -1;
- }
- vp->vp_ipv6prefix[1] = prefix;
-
- if (prefix < 128) {
- struct in6_addr addr;
-
- addr = fr_ipaddr_mask6((struct in6_addr *)(&vp->vp_ipv6prefix[2]), prefix);
- memcpy(vp->vp_ipv6prefix + 2, &addr, sizeof(addr));
- }
- vp->length = 16 + 2;
- }
- break;
-
- case PW_TYPE_IPV4PREFIX:
- {
- char *p;
- unsigned int prefix;
- char *eptr;
-
- p = strchr(value, '/');
-
- /*
- * 192.0.2.2 is parsed as if it was /32
- */
- if (!p) {
- vp->vp_ipv4prefix[1] = 32;
-
- if (inet_pton(AF_INET, value, vp->vp_ipv4prefix + 2) <= 0) {
- fr_strerror_printf("failed to parse IPv4 address string \"%s\"", value);
- return -1;
- }
- vp->length = sizeof(vp->vp_ipv4prefix);
- break;
- }
-
- /*
- * Otherwise parse the prefix
- */
- if ((size_t)(p - value) >= sizeof(buffer)) {
- fr_strerror_printf("invalid IPv4 prefix string \"%s\"", value);
- return -1;
- }
-
- /*
- * Copy string to temporary buffer if we didn't do it earlier
- */
- if (inlen == 0) memcpy(buffer, value, p - value);
- buffer[p - value] = '\0';
-
- if (inet_pton(AF_INET, buffer, vp->vp_ipv4prefix + 2) <= 0) {
- fr_strerror_printf("failed to parse IPv4 address string \"%s\"", value);
- return -1;
- }
-
- prefix = strtoul(p + 1, &eptr, 10);
- if ((prefix > 32) || *eptr) {
- fr_strerror_printf("failed to parse IPv4 address string \"%s\"", value);
- return -1;
- }
- vp->vp_ipv4prefix[1] = prefix;
-
- if (prefix < 32) {
- struct in_addr addr;
-
- addr = fr_ipaddr_mask((struct in_addr *)(&vp->vp_ipv4prefix[2]), prefix);
- memcpy(vp->vp_ipv4prefix + 2, &addr, sizeof(addr));
- }
-
- vp->length = sizeof(vp->vp_ipv4prefix);
- }
- break;
-
case PW_TYPE_ETHERNET:
{
char const *c1, *c2, *cp;
* These are not dynamic da, and will have the same vendor
* and attribute as the original.
*/
- case PW_TYPE_COMBO_IP:
+ case PW_TYPE_IP_ADDR:
{
DICT_ATTR const *da;
if (inet_pton(AF_INET6, value, &vp->vp_ipv6addr) > 0) {
- da = dict_attrbytype(vp->da->attr, vp->da->vendor, PW_TYPE_IPV6ADDR);
+ da = dict_attrbytype(vp->da->attr, vp->da->vendor, PW_TYPE_IPV6_ADDR);
if (!da) {
fr_strerror_printf("Cannot find ipv6addr for %s", vp->da->name);
return -1;
fr_ipaddr_t ipaddr;
da = dict_attrbytype(vp->da->attr, vp->da->vendor,
- PW_TYPE_IPADDR);
+ PW_TYPE_IPV4_ADDR);
if (!da) {
fr_strerror_printf("Cannot find ipaddr for %s", vp->da->name);
return -1;
}
- if (ip_hton(value, AF_INET, &ipaddr) < 0) {
+ if (ip_hton(&ipaddr, AF_INET, value, false) < 0) {
fr_strerror_printf("Failed to find IPv4 address for %s", value);
return -1;
}
vp->length = size >> 1;
data = talloc_array(vp, uint8_t, vp->length);
- if (fr_hex2bin(data, value + 2, size) != vp->length) {
+ if (fr_hex2bin(data, vp->length, value + 2, size) != vp->length) {
fr_strerror_printf("Invalid hex string");
talloc_free(vp);
return NULL;
compare = memcmp(&one->vp_ether, &two->vp_ether, sizeof(one->vp_ether));
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
compare = (int64_t) ntohl(one->vp_ipaddr) - (int64_t) ntohl(two->vp_ipaddr);
break;
- case PW_TYPE_IPV6ADDR:
+ case PW_TYPE_IPV6_ADDR:
compare = memcmp(&one->vp_ipv6addr, &two->vp_ipv6addr, sizeof(one->vp_ipv6addr));
break;
- case PW_TYPE_IPV6PREFIX:
+ case PW_TYPE_IPV6_PREFIX:
compare = memcmp(&one->vp_ipv6prefix, &two->vp_ipv6prefix, sizeof(one->vp_ipv6prefix));
break;
- case PW_TYPE_IPV4PREFIX:
+ case PW_TYPE_IPV4_PREFIX:
compare = memcmp(&one->vp_ipv4prefix, &two->vp_ipv4prefix, sizeof(one->vp_ipv4prefix));
break;
* None of the types below should be in the REQUEST
*/
case PW_TYPE_INVALID: /* We should never see these */
- case PW_TYPE_COMBO_IP: /* This should of been converted into IPADDR/IPV6ADDR */
+ case PW_TYPE_IP_ADDR: /* This should of been converted into IPADDR/IPV6ADDR */
+ case PW_TYPE_IP_PREFIX: /* This should of been converted into IPADDR/IPV6ADDR */
case PW_TYPE_TLV:
case PW_TYPE_EXTENDED:
case PW_TYPE_LONG_EXTENDED:
if (!a || !b) return -1;
switch (a->da->type) {
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
switch (b->da->type) {
- case PW_TYPE_IPADDR: /* IPv4 and IPv4 */
+ case PW_TYPE_IPV4_ADDR: /* IPv4 and IPv4 */
goto cmp;
- case PW_TYPE_IPV4PREFIX: /* IPv4 and IPv4 Prefix */
+ case PW_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
return paircmp_op_cidr(op, 4, 32, (uint8_t const *) &a->vp_ipaddr,
b->vp_ipv4prefix[1], (uint8_t const *) &b->vp_ipv4prefix + 2);
}
break;
- case PW_TYPE_IPV4PREFIX: /* IPv4 and IPv4 Prefix */
+ case PW_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
switch (b->da->type) {
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
return paircmp_op_cidr(op, 4, a->vp_ipv4prefix[1],
(uint8_t const *) &a->vp_ipv4prefix + 2,
32, (uint8_t const *) &b->vp_ipaddr);
- case PW_TYPE_IPV4PREFIX: /* IPv4 Prefix and IPv4 Prefix */
+ case PW_TYPE_IPV4_PREFIX: /* IPv4 Prefix and IPv4 Prefix */
return paircmp_op_cidr(op, 4, a->vp_ipv4prefix[1],
(uint8_t const *) &a->vp_ipv4prefix + 2,
b->vp_ipv4prefix[1], (uint8_t const *) &b->vp_ipv4prefix + 2);
}
break;
- case PW_TYPE_IPV6ADDR:
+ case PW_TYPE_IPV6_ADDR:
switch (b->da->type) {
- case PW_TYPE_IPV6ADDR: /* IPv6 and IPv6 */
+ case PW_TYPE_IPV6_ADDR: /* IPv6 and IPv6 */
goto cmp;
- case PW_TYPE_IPV6PREFIX: /* IPv6 and IPv6 Preifx */
+ case PW_TYPE_IPV6_PREFIX: /* IPv6 and IPv6 Preifx */
return paircmp_op_cidr(op, 16, 128, (uint8_t const *) &a->vp_ipv6addr,
b->vp_ipv6prefix[1], (uint8_t const *) &b->vp_ipv6prefix + 2);
break;
}
break;
- case PW_TYPE_IPV6PREFIX:
+ case PW_TYPE_IPV6_PREFIX:
switch (b->da->type) {
- case PW_TYPE_IPV6ADDR: /* IPv6 Prefix and IPv6 */
+ case PW_TYPE_IPV6_ADDR: /* IPv6 Prefix and IPv6 */
return paircmp_op_cidr(op, 16, a->vp_ipv6prefix[1],
(uint8_t const *) &a->vp_ipv6prefix + 2,
128, (uint8_t const *) &b->vp_ipv6addr);
- case PW_TYPE_IPV6PREFIX: /* IPv6 Prefix and IPv6 */
+ case PW_TYPE_IPV6_PREFIX: /* IPv6 Prefix and IPv6 */
return paircmp_op_cidr(op, 16, a->vp_ipv6prefix[1],
(uint8_t const *) &a->vp_ipv6prefix + 2,
b->vp_ipv6prefix[1], (uint8_t const *) &b->vp_ipv6prefix + 2);
pairtypeset(vp);
}
+/** Copy data from one VP to another
+ *
+ * Allocate a new pair using da, and copy over the value from the specified vp.
+ *
+ * @todo Should be able to do type conversions.
+ *
+ * @param[in,out] vp to update.
+ * @param[in] da Type of data represented by data.
+ * @param[in] data to copy.
+ * @param[in] len of data to copy.
+ */
+int pairdatacpy(VALUE_PAIR *vp, DICT_ATTR const *da, value_data_t const *data, size_t len)
+{
+ void *old;
+ VERIFY_VP(vp);
+
+ /*
+ * The da->types have to be identical, OR the "from" da->type has
+ * to be octets.
+ */
+ if (vp->da->type != da->type) {
+ /*
+ * Decode the octets buffer using the RADIUS decoder.
+ */
+ if (da->type == PW_TYPE_OCTETS) {
+ if (data2vp(vp, NULL, NULL, NULL, vp->da, data->octets, len, len, &vp) < 0) return -1;
+ vp->type = VT_DATA;
+ return 0;
+ }
+
+ /*
+ * Else if the destination da->type is octets
+ */
+ if (vp->da->type == PW_TYPE_OCTETS) {
+ int ret;
+ uint8_t *buff;
+ VALUE_PAIR const *pvp = vp;
+
+ buff = talloc_array(vp, uint8_t, dict_attr_sizes[da->type][1] + 2);
+
+ ret = rad_vp2rfc(NULL, NULL, NULL, &pvp, buff, dict_attr_sizes[da->type][1]);
+ if (ret < 0) return -1;
+
+ pairmemcpy(vp, buff + 2, ret - 2);
+ talloc_free(buff);
+
+ return 0;
+ }
+
+ /*
+ * Fixme...
+ */
+ fr_strerror_printf("Data conversion not supported");
+ return -1;
+ }
+
+ /*
+ * Clear existing value if there is one
+ */
+ memcpy(&old, &vp->data.ptr, sizeof(old));
+ talloc_free(old);
+
+ switch (vp->da->type) {
+ case PW_TYPE_TLV:
+ case PW_TYPE_OCTETS:
+ pairmemcpy(vp, data->octets, len);
+ break;
+
+ case PW_TYPE_STRING:
+ pairstrncpy(vp, data->strvalue, len);
+ break;
+
+ default:
+ memcpy(&vp->data, data, sizeof(vp->data));
+ break;
+ }
+ vp->length = len;
+
+ return 0;
+}
+
/** Print data into an "string" data type.
*
* @param[in,out] vp to update