2 * value.c Functions to handle value_data_t
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version. either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * Copyright 2014 The FreeRADIUS server project
26 #include <freeradius-devel/libradius.h>
29 /** Compare two values
31 * @param[in] a_type of data to compare.
32 * @param[in] a_len of data to compare.
33 * @param[in] a Value to compare.
34 * @param[in] b_type of data to compare.
35 * @param[in] b_len of data to compare.
36 * @param[in] b Value to compare.
37 * @return -1 if a is less than b, 0 if both are equal, 1 if a is more than b, < -1 on error.
39 int value_data_cmp(PW_TYPE a_type, value_data_t const *a, size_t a_len,
40 PW_TYPE b_type, value_data_t const *b, size_t b_len)
44 if (a_type != b_type) {
45 fr_strerror_printf("Can't compare values of different types");
50 * After doing the previous check for special comparisons,
51 * do the per-type comparison here.
56 case PW_TYPE_STRING: /* We use memcmp to be \0 safe */
67 compare = memcmp(a->octets, b->octets, length);
68 if (compare != 0) break;
72 * Contents are the same. The return code
73 * is therefore the difference in lengths.
75 * i.e. "0x00" is smaller than "0x0000"
77 compare = a_len - b_len;
82 * Short-hand for simplicity.
84 #define CHECK(_type) if (a->_type < b->_type) { compare = -1; \
85 } else if (a->_type > b->_type) { compare = +1; }
87 case PW_TYPE_BOOLEAN: /* this isn't a RADIUS type, and shouldn't really ever be used */
101 case PW_TYPE_INTEGER:
109 case PW_TYPE_INTEGER64:
113 case PW_TYPE_ETHERNET:
114 compare = memcmp(a->ether, b->ether, sizeof(a->ether));
117 case PW_TYPE_IPV4_ADDR: {
118 uint32_t a_int, b_int;
120 a_int = ntohl(a->ipaddr.s_addr);
121 b_int = ntohl(b->ipaddr.s_addr);
124 } else if (a_int > b_int) {
130 case PW_TYPE_IPV6_ADDR:
131 compare = memcmp(&a->ipv6addr, &b->ipv6addr, sizeof(a->ipv6addr));
134 case PW_TYPE_IPV6_PREFIX:
135 compare = memcmp(a->ipv6prefix, b->ipv6prefix, sizeof(a->ipv6prefix));
138 case PW_TYPE_IPV4_PREFIX:
139 compare = memcmp(a->ipv4prefix, b->ipv4prefix, sizeof(a->ipv4prefix));
143 compare = memcmp(a->ifid, b->ifid, sizeof(a->ifid));
147 * Na of the types below should be in the REQUEST
149 case PW_TYPE_INVALID: /* We should never see these */
150 case PW_TYPE_COMBO_IP_ADDR: /* This should have been converted into IPADDR/IPV6ADDR */
151 case PW_TYPE_COMBO_IP_PREFIX: /* This should have been converted into IPADDR/IPV6ADDR */
153 case PW_TYPE_EXTENDED:
154 case PW_TYPE_LONG_EXTENDED:
157 case PW_TYPE_TIMEVAL:
159 fr_assert(0); /* unknown type */
163 * Do NOT add a default here, as new types are added
164 * static analysis will warn us they're not handled
170 } else if (compare < 0) {
177 * We leverage the fact that IPv4 and IPv6 prefixes both
178 * have the same format:
180 * reserved, prefix-len, data...
182 static int value_data_cidr_cmp_op(FR_TOKEN op, int bytes,
183 uint8_t a_net, uint8_t const *a,
184 uint8_t b_net, uint8_t const *b)
190 * Handle the case of netmasks being identical.
192 if (a_net == b_net) {
195 compare = memcmp(a, b, bytes);
198 * If they're identical return true for
201 if ((compare == 0) &&
202 ((op == T_OP_CMP_EQ) ||
209 * Everything else returns false.
211 * 10/8 == 24/8 --> false
212 * 10/8 <= 24/8 --> false
213 * 10/8 >= 24/8 --> false
219 * Netmasks are different. That limits the
220 * possible results, based on the operator.
230 case T_OP_LT: /* 192/8 < 192.168/16 --> false */
237 case T_OP_GT: /* 192/16 > 192.168/8 --> false */
254 * Do the check byte by byte. If the bytes are
255 * identical, it MAY be a match. If they're different,
261 * All leading bytes are identical.
263 if (common == 0) return true;
266 * Doing bitmasks takes more work.
268 if (common < 8) break;
270 if (a[i] != b[i]) return false;
278 mask <<= (8 - common);
282 if ((a[i] & mask) == ((b[i] & mask))) {
289 /** Compare two attributes using an operator
291 * @param[in] op to use in comparison.
292 * @param[in] a_type of data to compare.
293 * @param[in] a_len of data to compare.
294 * @param[in] a Value to compare.
295 * @param[in] b_type of data to compare.
296 * @param[in] b_len of data to compare.
297 * @param[in] b Value to compare.
298 * @return 1 if true, 0 if false, -1 on error.
300 int value_data_cmp_op(FR_TOKEN op,
301 PW_TYPE a_type, value_data_t const *a, size_t a_len,
302 PW_TYPE b_type, value_data_t const *b, size_t b_len)
306 if (!a || !b) return -1;
309 case PW_TYPE_IPV4_ADDR:
311 case PW_TYPE_IPV4_ADDR: /* IPv4 and IPv4 */
314 case PW_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
315 return value_data_cidr_cmp_op(op, 4, 32, (uint8_t const *) &a->ipaddr,
316 b->ipv4prefix[1], (uint8_t const *) &b->ipv4prefix[2]);
319 fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
323 case PW_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
325 case PW_TYPE_IPV4_ADDR:
326 return value_data_cidr_cmp_op(op, 4, a->ipv4prefix[1],
327 (uint8_t const *) &a->ipv4prefix[2],
328 32, (uint8_t const *) &b->ipaddr);
330 case PW_TYPE_IPV4_PREFIX: /* IPv4 Prefix and IPv4 Prefix */
331 return value_data_cidr_cmp_op(op, 4, a->ipv4prefix[1],
332 (uint8_t const *) &a->ipv4prefix[2],
333 b->ipv4prefix[1], (uint8_t const *) &b->ipv4prefix[2]);
336 fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
340 case PW_TYPE_IPV6_ADDR:
342 case PW_TYPE_IPV6_ADDR: /* IPv6 and IPv6 */
345 case PW_TYPE_IPV6_PREFIX: /* IPv6 and IPv6 Preifx */
346 return value_data_cidr_cmp_op(op, 16, 128, (uint8_t const *) &a->ipv6addr,
347 b->ipv6prefix[1], (uint8_t const *) &b->ipv6prefix[2]);
350 fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
354 case PW_TYPE_IPV6_PREFIX:
356 case PW_TYPE_IPV6_ADDR: /* IPv6 Prefix and IPv6 */
357 return value_data_cidr_cmp_op(op, 16, a->ipv6prefix[1],
358 (uint8_t const *) &a->ipv6prefix[2],
359 128, (uint8_t const *) &b->ipv6addr);
361 case PW_TYPE_IPV6_PREFIX: /* IPv6 Prefix and IPv6 */
362 return value_data_cidr_cmp_op(op, 16, a->ipv6prefix[1],
363 (uint8_t const *) &a->ipv6prefix[2],
364 b->ipv6prefix[1], (uint8_t const *) &b->ipv6prefix[2]);
367 fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
373 compare = value_data_cmp(a_type, a, a_len,
375 if (compare < -1) { /* comparison error */
381 * Now do the operator comparison.
385 return (compare == 0);
388 return (compare != 0);
391 return (compare < 0);
394 return (compare > 0);
397 return (compare <= 0);
400 return (compare >= 0);
407 static char const hextab[] = "0123456789abcdef";
409 /** Convert string value to a value_data_t type
411 * @param[in] ctx to alloc strings in.
412 * @param[out] dst where to write parsed value.
413 * @param[in,out] src_type of value data to create/type of value created.
414 * @param[in] src_enumv DICT_ATTR with string aliases for integer values.
415 * @param[in] src String to convert. Binary safe for variable length values if len is provided.
416 * @param[in] src_len may be < 0 in which case strlen(len) is used to determine length, else src_len
417 * should be the length of the string or sub string to parse.
418 * @param[in] quote quotation character used to drive de-escaping
419 * @return length of data written to out or -1 on parse error.
421 ssize_t value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst,
422 PW_TYPE *src_type, DICT_ATTR const *src_enumv,
423 char const *src, ssize_t src_len, char quote)
432 len = (src_len < 0) ? strlen(src) : (size_t)src_len;
435 * Set size for all fixed length attributes.
437 ret = dict_attr_sizes[*src_type][1]; /* Max length */
440 * It's a variable ret src_type so we just alloc a new buffer
441 * of size len and copy.
450 dst->strvalue = p = talloc_array(ctx, char, len + 1);
455 * No de-quoting. Just copy the string.
463 * Do escaping for single quoted strings. Only
464 * single quotes get escaped. Everything else is
470 while (q < (dst->strvalue + len)) {
472 * The quotation character is escaped.
474 if ((q[0] == '\\') &&
482 * Two backslashes get mangled to one.
484 if ((q[0] == '\\') &&
492 * Not escaped, just copy it over.
498 ret = p - dst->strvalue;
499 dst->ptr = talloc_realloc(ctx, dst->ptr, char, ret + 1);
504 * It's "string" or `string`, do all standard
508 while (q < (dst->strvalue + len)) {
511 if ((c == '\\') && (q >= (dst->strvalue + len))) {
512 fr_strerror_printf("Invalid escape at end of string");
517 * Fix up \X -> ... the binary form of it.
543 * \" --> ", but only inside of double quoted strings, etc.
552 * \000 --> binary zero character
560 (sscanf(q, "%3o", &x) == 1)) {
566 * Else It's not a recognised escape sequence DON'T
567 * consume the backslash. This is identical
568 * behaviour to bash and most other things that
569 * use backslash escaping.
578 ret = p - dst->strvalue;
579 dst->ptr = talloc_realloc(ctx, dst->ptr, char, ret + 1);
584 fr_strerror_printf("Must use 'Attr-26 = ...' instead of 'Vendor-Specific = ...'");
587 /* raw octets: 0x01020304... */
593 * No 0x prefix, just copy verbatim.
595 if ((len < 2) || (strncasecmp(src, "0x", 2) != 0)) {
596 dst->octets = talloc_memdup(ctx, (uint8_t const *)src, len);
597 talloc_set_type(dst->octets, uint8_t);
608 if ((len & 0x01) != 0) {
609 fr_strerror_printf("Length of Hex String is not even, got %zu bytes", ret);
614 p = talloc_array(ctx, uint8_t, ret);
615 if (fr_hex2bin(p, ret, src + 2, len) != (size_t)ret) {
617 fr_strerror_printf("Invalid hex data");
625 case PW_TYPE_ABINARY:
626 #ifdef WITH_ASCEND_BINARY
627 if ((len > 1) && (strncasecmp(src, "0x", 2) == 0)) goto do_octets;
629 if (ascend_parse_filter(dst, src, len) < 0 ) {
630 /* Allow ascend_parse_filter's strerror to bubble up */
633 ret = sizeof(dst->filter);
637 * If Ascend binary is NOT defined,
638 * then fall through to raw octets, so that
639 * the user can at least make them by hand...
644 /* don't use this! */
649 if ((len < 2) || (len & 0x01) || (strncasecmp(src, "0x", 2) != 0)) {
650 fr_strerror_printf("Invalid TLV specification");
656 p = talloc_array(ctx, uint8_t, ret);
658 fr_strerror_printf("No memory");
661 if (fr_hex2bin(p, ret, src + 2, len) != (size_t)ret) {
662 fr_strerror_printf("Invalid hex data in TLV");
670 case PW_TYPE_IPV4_ADDR:
674 if (fr_pton4(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
677 * We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
678 * print them this way.
680 if (addr.prefix != 32) {
681 fr_strerror_printf("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted "
682 "for non-prefix types", addr.prefix);
686 dst->ipaddr.s_addr = addr.ipaddr.ip4addr.s_addr;
690 case PW_TYPE_IPV4_PREFIX:
694 if (fr_pton4(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
696 dst->ipv4prefix[1] = addr.prefix;
697 memcpy(&dst->ipv4prefix[2], &addr.ipaddr.ip4addr.s_addr, sizeof(dst->ipv4prefix) - 2);
701 case PW_TYPE_IPV6_ADDR:
705 if (fr_pton6(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
708 * We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
709 * print them this way.
711 if (addr.prefix != 128) {
712 fr_strerror_printf("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted "
713 "for non-prefix types", addr.prefix);
717 memcpy(&dst->ipv6addr, addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6addr));
721 case PW_TYPE_IPV6_PREFIX:
725 if (fr_pton6(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
727 dst->ipv6prefix[1] = addr.prefix;
728 memcpy(&dst->ipv6prefix[2], addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6prefix) - 2);
737 * It's a fixed size src_type, copy to a temporary buffer and
738 * \0 terminate if insize >= 0.
741 if (len >= sizeof(buffer)) {
742 fr_strerror_printf("Temporary buffer too small");
746 memcpy(buffer, src, src_len);
747 buffer[src_len] = '\0';
758 * Note that ALL integers are unsigned!
760 i = fr_strtoul(src, &p);
763 * Look for the named src for the given
766 if (src_enumv && *p && !is_whitespace(p)) {
767 if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
768 fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
769 src, src_enumv->name);
773 dst->byte = dval->value;
776 fr_strerror_printf("Byte value \"%s\" is larger than 255", src);
791 * Note that ALL integers are unsigned!
793 i = fr_strtoul(src, &p);
796 * Look for the named src for the given
799 if (src_enumv && *p && !is_whitespace(p)) {
800 if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
801 fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
802 src, src_enumv->name);
806 dst->ushort = dval->value;
809 fr_strerror_printf("Short value \"%s\" is larger than 65535", src);
818 case PW_TYPE_INTEGER:
824 * Note that ALL integers are unsigned!
826 i = fr_strtoul(src, &p);
829 * Look for the named src for the given
832 if (src_enumv && *p && !is_whitespace(p)) {
833 if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
834 fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
835 src, src_enumv->name);
839 dst->integer = dval->value;
842 * Value is always within the limits
849 case PW_TYPE_INTEGER64:
854 * Note that ALL integers are unsigned!
856 if (sscanf(src, "%" PRIu64, &i) != 1) {
857 fr_strerror_printf("Failed parsing \"%s\" as unsigned 64bit integer", src);
867 * time_t may be 64 bits, whule vp_date MUST be 32-bits. We need an
868 * intermediary variable to handle the conversions.
872 if (fr_get_time(src, &date) < 0) {
873 fr_strerror_printf("failed to parse time string \"%s\"", src);
883 if (ifid_aton(src, (void *) dst->ifid) == NULL) {
884 fr_strerror_printf("Failed to parse interface-id string \"%s\"", src);
889 case PW_TYPE_ETHERNET:
891 char const *c1, *c2, *cp;
895 * Convert things which are obviously integers to Ethernet addresses
897 * We assume the number is the bigendian representation of the
900 if (is_integer(src)) {
901 uint64_t integer = htonll(atoll(src));
903 memcpy(dst->ether, &integer, sizeof(dst->ether));
911 c2 = memchr(hextab, tolower((int) cp[0]), 16);
913 } else if ((cp[1] != '\0') && ((cp[2] == ':') || (cp[2] == '\0'))) {
914 c1 = memchr(hextab, tolower((int) cp[0]), 16);
915 c2 = memchr(hextab, tolower((int) cp[1]), 16);
917 if (*cp == ':') cp++;
921 if (!c1 || !c2 || (p_len >= sizeof(dst->ether))) {
922 fr_strerror_printf("failed to parse Ethernet address \"%s\"", src);
925 dst->ether[p_len] = ((c1-hextab)<<4) + (c2-hextab);
932 * Crazy polymorphic (IPv4/IPv6) attribute src_type for WiMAX.
934 * We try and make is saner by replacing the original
935 * da, with either an IPv4 or IPv6 da src_type.
937 * These are not dynamic da, and will have the same vendor
938 * and attribute as the original.
940 case PW_TYPE_COMBO_IP_ADDR:
942 if (inet_pton(AF_INET6, src, &dst->ipv6addr) > 0) {
943 *src_type = PW_TYPE_IPV6_ADDR;
944 ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][1]; /* size of IPv6 address */
948 if (ip_hton(&ipaddr, AF_INET, src, false) < 0) {
949 fr_strerror_printf("Failed to find IPv4 address for %s", src);
953 *src_type = PW_TYPE_IPV4_ADDR;
954 dst->ipaddr.s_addr = ipaddr.ipaddr.ip4addr.s_addr;
955 ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][0]; /* size of IPv4 address */
961 /* Damned code for 1 WiMAX attribute */
962 dst->sinteger = (int32_t)strtol(src, NULL, 10);
969 fr_strerror_printf("Unknown attribute type %d", *src_type);
977 /** Performs byte order reversal for types that need it
980 static void value_data_hton(value_data_t *dst, PW_TYPE type, void const *src, size_t src_len)
982 /* 8 byte integers */
984 case PW_TYPE_INTEGER64:
985 dst->integer64 = htonll(*(uint64_t const *)src);
988 /* 4 byte integers */
989 case PW_TYPE_INTEGER:
992 dst->integer = htonl(*(uint32_t const *)src);
995 /* 2 byte integers */
997 dst->ushort = htons(*(uint16_t const *)src);
1000 case PW_TYPE_OCTETS:
1001 case PW_TYPE_STRING:
1003 return; /* shouldn't happen */
1006 memcpy(dst, src, src_len);
1010 /** Convert one type of value_data_t to another
1012 * @note This should be the canonical function used to convert between data types.
1014 * @param ctx to allocate buffers in (usually the same as dst)
1015 * @param dst Where to write result of casting.
1016 * @param dst_type to cast to.
1017 * @param dst_enumv Enumerated values used to converts strings to integers.
1018 * @param src_type to cast from.
1019 * @param src_enumv Enumerated values used to convert integers to strings.
1020 * @param src Input data.
1021 * @param src_len Input data len.
1022 * @return the length of data in the dst or -1 on error.
1024 ssize_t value_data_cast(TALLOC_CTX *ctx, value_data_t *dst,
1025 PW_TYPE dst_type, DICT_ATTR const *dst_enumv,
1026 PW_TYPE src_type, DICT_ATTR const *src_enumv,
1027 value_data_t const *src, size_t src_len)
1029 if (!fr_assert(dst_type != src_type)) return -1;
1032 * Deserialise a value_data_t
1034 if (src_type == PW_TYPE_STRING) {
1035 return value_data_from_str(ctx, dst, &dst_type, dst_enumv, src->strvalue, src_len, '\0');
1039 * Converts the src data to octets with no processing.
1041 if (dst_type == PW_TYPE_OCTETS) {
1042 value_data_hton(dst, src_type, src, src_len);
1043 dst->octets = talloc_memdup(ctx, dst, src_len);
1044 talloc_set_type(dst->octets, uint8_t);
1045 return talloc_array_length(dst->strvalue);
1049 * Serialise a value_data_t
1051 if (dst_type == PW_TYPE_STRING) {
1052 dst->strvalue = value_data_aprints(ctx, src_type, src_enumv, src, src_len, '\0');
1053 return talloc_array_length(dst->strvalue) - 1;
1056 if ((src_type == PW_TYPE_IFID) &&
1057 (dst_type == PW_TYPE_INTEGER64)) {
1058 memcpy(&dst->integer64, src->ifid, sizeof(src->ifid));
1059 dst->integer64 = htonll(dst->integer64);
1061 return dict_attr_sizes[dst_type][0];
1064 if ((src_type == PW_TYPE_INTEGER64) &&
1065 (dst_type == PW_TYPE_ETHERNET)) {
1069 i = htonll(src->integer64);
1070 memcpy(array, &i, 8);
1073 * For OUIs in the DB.
1075 if ((array[0] != 0) || (array[1] != 0)) return -1;
1077 memcpy(dst->ether, &array[2], 6);
1082 * For integers, we allow the casting of a SMALL type to
1083 * a larger type, but not vice-versa.
1085 if (dst_type == PW_TYPE_INTEGER64) {
1088 dst->integer64 = src->byte;
1092 dst->integer64 = src->ushort;
1095 case PW_TYPE_INTEGER:
1096 dst->integer64 = src->integer;
1099 case PW_TYPE_OCTETS:
1104 fr_strerror_printf("Invalid cast from %s to %s",
1105 fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1106 fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1114 * We can cast LONG integers to SHORTER ones, so long
1115 * as the long one is on the LHS.
1117 if (dst_type == PW_TYPE_INTEGER) {
1120 dst->integer = src->byte;
1124 dst->integer = src->ushort;
1127 case PW_TYPE_OCTETS:
1136 if (dst_type == PW_TYPE_SHORT) {
1139 dst->ushort = src->byte;
1142 case PW_TYPE_OCTETS:
1152 * Conversions between IPv4 addresses, IPv6 addresses, IPv4 prefixes and IPv6 prefixes
1154 * For prefix to ipaddress conversions, we assume that the host portion has already
1157 * We allow casts from v6 to v4 if the v6 address has the correct mapping prefix.
1159 * We only allow casts from prefixes to addresses if the prefix is the the length of
1160 * the address, e.g. 32 for ipv4 128 for ipv6.
1164 * 10 bytes of 0x00 2 bytes of 0xff
1166 static uint8_t const v4_v6_map[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1167 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
1170 case PW_TYPE_IPV4_ADDR:
1172 case PW_TYPE_IPV6_ADDR:
1173 if (memcmp(src->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
1175 fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
1176 fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1177 fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1181 memcpy(&dst->ipaddr, &src->ipv6addr.s6_addr[sizeof(v4_v6_map)],
1182 sizeof(dst->ipaddr));
1185 case PW_TYPE_IPV4_PREFIX:
1186 if (src->ipv4prefix[1] != 32) {
1188 fr_strerror_printf("Invalid cast from %s to %s. Only /32 prefixes may be "
1189 "cast to IP address types",
1190 fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1191 fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1195 memcpy(&dst->ipaddr, &src->ipv4prefix[2], sizeof(dst->ipaddr));
1198 case PW_TYPE_IPV6_PREFIX:
1199 if (src->ipv6prefix[1] != 128) {
1201 fr_strerror_printf("Invalid cast from %s to %s. Only /128 prefixes may be "
1202 "cast to IP address types",
1203 fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1204 fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1207 if (memcmp(&src->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
1208 goto bad_v6_prefix_map;
1210 memcpy(&dst->ipaddr, &src->ipv6prefix[2 + sizeof(v4_v6_map)],
1211 sizeof(dst->ipaddr));
1219 case PW_TYPE_IPV6_ADDR:
1221 case PW_TYPE_IPV4_ADDR:
1222 /* Add the v4/v6 mapping prefix */
1223 memcpy(dst->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map));
1224 memcpy(&dst->ipv6addr.s6_addr[sizeof(v4_v6_map)], &src->ipaddr,
1225 sizeof(dst->ipv6addr.s6_addr) - sizeof(v4_v6_map));
1229 case PW_TYPE_IPV4_PREFIX:
1230 if (src->ipv4prefix[1] != 32) goto bad_v4_prefix_len;
1232 /* Add the v4/v6 mapping prefix */
1233 memcpy(dst->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map));
1234 memcpy(&dst->ipv6addr.s6_addr[sizeof(v4_v6_map)], &src->ipv4prefix[2],
1235 sizeof(dst->ipv6addr.s6_addr) - sizeof(v4_v6_map));
1238 case PW_TYPE_IPV6_PREFIX:
1239 if (src->ipv4prefix[1] != 128) goto bad_v6_prefix_len;
1241 memcpy(dst->ipv6addr.s6_addr, &src->ipv6prefix[2], sizeof(dst->ipv6addr.s6_addr));
1249 case PW_TYPE_IPV4_PREFIX:
1251 case PW_TYPE_IPV4_ADDR:
1252 memcpy(&dst->ipv4prefix[2], &src->ipaddr, sizeof(dst->ipv4prefix) - 2);
1253 dst->ipv4prefix[0] = 0;
1254 dst->ipv4prefix[1] = 32;
1257 case PW_TYPE_IPV6_ADDR:
1258 if (memcmp(src->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
1259 goto bad_v6_prefix_map;
1261 memcpy(&dst->ipv4prefix[2], &src->ipv6addr.s6_addr[sizeof(v4_v6_map)],
1262 sizeof(dst->ipv4prefix) - 2);
1263 dst->ipv4prefix[0] = 0;
1264 dst->ipv4prefix[1] = 32;
1267 case PW_TYPE_IPV6_PREFIX:
1268 if (memcmp(&src->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
1269 goto bad_v6_prefix_map;
1273 * Prefix must be >= 96 bits. If it's < 96 bytes and the
1274 * above check passed, the v6 address wasn't masked
1275 * correctly when it was packet into a value_data_t.
1277 if (!fr_assert(src->ipv6prefix[1] >= (sizeof(v4_v6_map) * 8))) return -1;
1279 memcpy(&dst->ipv4prefix[2], &src->ipv6prefix[2 + sizeof(v4_v6_map)],
1280 sizeof(dst->ipv4prefix) - 2);
1281 dst->ipv4prefix[0] = 0;
1282 dst->ipv4prefix[1] = src->ipv6prefix[1] - (sizeof(v4_v6_map) * 8);
1290 case PW_TYPE_IPV6_PREFIX:
1292 case PW_TYPE_IPV4_ADDR:
1293 /* Add the v4/v6 mapping prefix */
1294 memcpy(&dst->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
1295 memcpy(&dst->ipv6prefix[2 + sizeof(v4_v6_map)], &src->ipaddr,
1296 (sizeof(dst->ipv6prefix) - 2) - sizeof(v4_v6_map));
1297 dst->ipv6prefix[0] = 0;
1298 dst->ipv6prefix[1] = 128;
1301 case PW_TYPE_IPV4_PREFIX:
1302 /* Add the v4/v6 mapping prefix */
1303 memcpy(&dst->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
1304 memcpy(&dst->ipv6prefix[2 + sizeof(v4_v6_map)], &src->ipv4prefix[2],
1305 (sizeof(dst->ipv6prefix) - 2) - sizeof(v4_v6_map));
1306 dst->ipv6prefix[0] = 0;
1307 dst->ipv6prefix[1] = (sizeof(v4_v6_map) * 8) + src->ipv4prefix[1];
1310 case PW_TYPE_IPV6_ADDR:
1311 memcpy(&dst->ipv6prefix[2], &src->ipv6addr, sizeof(dst->ipv6prefix) - 2);
1312 dst->ipv6prefix[0] = 0;
1313 dst->ipv6prefix[1] = 128;
1328 * The attribute we've found has to have a size which is
1329 * compatible with the type of the destination cast.
1331 if ((src_len < dict_attr_sizes[dst_type][0]) ||
1332 (src_len > dict_attr_sizes[dst_type][1])) {
1333 char const *src_type_name;
1335 src_type_name = fr_int2str(dict_attr_types, src_type, "<INVALID>");
1336 fr_strerror_printf("Invalid cast from %s to %s. Length should be between %zu and %zu but is %zu",
1338 fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
1339 dict_attr_sizes[dst_type][0], dict_attr_sizes[dst_type][1],
1344 if (src_type == PW_TYPE_OCTETS) {
1346 value_data_hton(dst, dst_type, src->octets, src_len);
1351 * Convert host order to network byte order.
1353 if ((dst_type == PW_TYPE_IPV4_ADDR) &&
1354 ((src_type == PW_TYPE_INTEGER) ||
1355 (src_type == PW_TYPE_DATE) ||
1356 (src_type == PW_TYPE_SIGNED))) {
1357 dst->ipaddr.s_addr = htonl(src->integer);
1359 } else if ((src_type == PW_TYPE_IPV4_ADDR) &&
1360 ((dst_type == PW_TYPE_INTEGER) ||
1361 (dst_type == PW_TYPE_DATE) ||
1362 (dst_type == PW_TYPE_SIGNED))) {
1363 dst->integer = htonl(src->ipaddr.s_addr);
1365 } else { /* they're of the same byte order */
1366 memcpy(&dst, &src, src_len);
1372 /** Copy value data verbatim duplicating any buffers
1374 * @param ctx To allocate buffers in.
1375 * @param dst Where to copy value_data to.
1376 * @param src_type Type of src.
1377 * @param src Where to copy value_data from.
1378 * @param src_len Where
1380 ssize_t value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE src_type,
1381 const value_data_t *src, size_t src_len)
1385 memcpy(dst, src, sizeof(*src));
1388 case PW_TYPE_STRING:
1389 dst->strvalue = talloc_bstrndup(ctx, src->strvalue, src_len);
1390 if (!dst->strvalue) return -1;
1393 case PW_TYPE_OCTETS:
1394 dst->octets = talloc_memdup(ctx, src->octets, src_len);
1395 talloc_set_type(dst->strvalue, uint8_t);
1396 if (!dst->octets) return -1;
1405 /** Print one attribute value to a string
1408 char *value_data_aprints(TALLOC_CTX *ctx,
1409 PW_TYPE type, DICT_ATTR const *enumv, value_data_t const *data,
1410 size_t inlen, char quote)
1416 case PW_TYPE_STRING:
1421 p = talloc_bstrndup(ctx, data->strvalue, inlen);
1422 if (!p) return NULL;
1423 talloc_set_type(p, char);
1427 /* Gets us the size of the buffer we need to alloc */
1428 len = fr_prints_len(data->strvalue, inlen, quote);
1429 p = talloc_array(ctx, char, len);
1430 if (!p) return NULL;
1432 ret = fr_prints(p, len, data->strvalue, inlen, quote);
1433 if (!fr_assert(ret == (len - 1))) {
1440 case PW_TYPE_INTEGER:
1453 DICT_VALUE const *dv;
1455 if (enumv && (dv = dict_valbyattr(enumv->attr, enumv->vendor, i))) {
1456 p = talloc_typed_strdup(ctx, dv->name);
1458 p = talloc_typed_asprintf(ctx, "%u", i);
1463 case PW_TYPE_SIGNED:
1464 p = talloc_typed_asprintf(ctx, "%d", data->sinteger);
1467 case PW_TYPE_INTEGER64:
1468 p = talloc_typed_asprintf(ctx, "%" PRIu64 , data->integer64);
1471 case PW_TYPE_ETHERNET:
1472 p = talloc_typed_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
1473 data->ether[0], data->ether[1],
1474 data->ether[2], data->ether[3],
1475 data->ether[4], data->ether[5]);
1478 case PW_TYPE_ABINARY:
1479 #ifdef WITH_ASCEND_BINARY
1480 p = talloc_array(ctx, char, 128);
1481 if (!p) return NULL;
1482 print_abinary(p, 128, (uint8_t *) &data->filter, inlen, 0);
1488 case PW_TYPE_OCTETS:
1489 p = talloc_array(ctx, char, 2 + 1 + inlen * 2);
1490 if (!p) return NULL;
1494 fr_bin2hex(p + 2, data->octets, inlen);
1504 p = talloc_array(ctx, char, 64);
1505 strftime(p, 64, "%b %e %Y %H:%M:%S %Z",
1506 localtime_r(&t, &s_tm));
1511 * We need to use the proper inet_ntop functions for IP
1512 * addresses, else the output might not match output of
1513 * other functions, which makes testing difficult.
1515 * An example is tunnelled ipv4 in ipv6 addresses.
1517 case PW_TYPE_IPV4_ADDR:
1518 case PW_TYPE_IPV4_PREFIX:
1520 char buff[INET_ADDRSTRLEN + 4]; // + /prefix
1523 value_data_prints(buff, sizeof(buff), type, enumv, data, inlen, '\0');
1525 p = talloc_typed_strdup(ctx, buff);
1529 case PW_TYPE_IPV6_ADDR:
1530 case PW_TYPE_IPV6_PREFIX:
1532 char buff[INET6_ADDRSTRLEN + 4]; // + /prefix
1535 value_data_prints(buff, sizeof(buff), type, enumv, data, inlen, '\0');
1537 p = talloc_typed_strdup(ctx, buff);
1542 p = talloc_typed_asprintf(ctx, "%x:%x:%x:%x",
1543 (data->ifid[0] << 8) | data->ifid[1],
1544 (data->ifid[2] << 8) | data->ifid[3],
1545 (data->ifid[4] << 8) | data->ifid[5],
1546 (data->ifid[6] << 8) | data->ifid[7]);
1549 case PW_TYPE_BOOLEAN:
1550 p = talloc_typed_strdup(ctx, data->byte ? "yes" : "no");
1554 * Don't add default here
1556 case PW_TYPE_INVALID:
1557 case PW_TYPE_COMBO_IP_ADDR:
1558 case PW_TYPE_COMBO_IP_PREFIX:
1560 case PW_TYPE_EXTENDED:
1561 case PW_TYPE_LONG_EXTENDED:
1564 case PW_TYPE_TIMEVAL:
1574 /** Print the value of an attribute to a string
1576 * @note return value should be checked with is_truncated.
1577 * @note Will always \0 terminate unless outlen == 0.
1579 * @param out Where to write the printed version of the attribute value.
1580 * @param outlen Length of the output buffer.
1581 * @param type of data being printed.
1582 * @param enumv Enumerated string values for integer types.
1583 * @param data to print.
1584 * @param inlen Length of data.
1585 * @param quote char to escape in string output.
1586 * @return the number of bytes written to the out buffer, or a number >= outlen if truncation has occurred.
1588 size_t value_data_prints(char *out, size_t outlen,
1589 PW_TYPE type, DICT_ATTR const *enumv, value_data_t const *data,
1590 ssize_t inlen, char quote)
1593 char buf[1024]; /* Interim buffer to use with poorly behaved printing functions */
1594 char const *a = NULL;
1599 size_t len = 0, freespace = outlen;
1601 if (!data) return 0;
1602 if (outlen == 0) return inlen;
1607 case PW_TYPE_STRING:
1610 * Ensure that WE add the quotation marks around the string.
1613 if (freespace < 3) return inlen + 2;
1618 len = fr_prints(out, freespace, data->strvalue, inlen, quote);
1619 /* always terminate the quoted string with another quote */
1620 if (len >= (freespace - 1)) {
1621 out[outlen - 2] = (char) quote;
1622 out[outlen - 1] = '\0';
1628 *out++ = (char) quote;
1635 return fr_prints(out, outlen, data->strvalue, inlen, quote);
1637 case PW_TYPE_INTEGER:
1649 /* Normal, non-tagged attribute */
1650 if (enumv && (v = dict_valbyattr(enumv->attr, enumv->vendor, i)) != NULL) {
1654 /* should never be truncated */
1655 len = snprintf(buf, sizeof(buf), "%u", i);
1660 case PW_TYPE_INTEGER64:
1661 return snprintf(out, outlen, "%" PRIu64, data->integer64);
1666 len = strftime(buf, sizeof(buf) - 1, "%%%b %e %Y %H:%M:%S %Z%%", localtime_r(&t, &s_tm));
1667 buf[0] = (char) quote;
1668 buf[len - 1] = (char) quote;
1671 len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z", localtime_r(&t, &s_tm));
1676 case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
1677 len = snprintf(buf, sizeof(buf), "%d", data->sinteger);
1681 case PW_TYPE_IPV4_ADDR:
1682 a = inet_ntop(AF_INET, &(data->ipaddr), buf, sizeof(buf));
1686 case PW_TYPE_ABINARY:
1687 #ifdef WITH_ASCEND_BINARY
1688 print_abinary(buf, sizeof(buf), (uint8_t const *) data->filter, len, quote);
1695 case PW_TYPE_OCTETS:
1700 /* Return the number of bytes we would have written */
1701 len = (inlen * 2) + 2;
1702 if (freespace <= 1) {
1709 if (freespace <= 1) {
1716 if (freespace <= 2) {
1721 /* Get maximum number of bytes we can encode given freespace */
1722 max = ((freespace % 2) ? freespace - 1 : freespace - 2) / 2;
1723 fr_bin2hex(out, data->octets, ((size_t)inlen > max) ? max : (size_t)inlen);
1728 a = ifid_ntoa(buf, sizeof(buf), data->ifid);
1732 case PW_TYPE_IPV6_ADDR:
1733 a = inet_ntop(AF_INET6, &data->ipv6addr, buf, sizeof(buf));
1737 case PW_TYPE_IPV6_PREFIX:
1739 struct in6_addr addr;
1744 memcpy(&addr, &(data->ipv6prefix[2]), sizeof(addr));
1746 a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
1752 len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) data->ipv6prefix[1]);
1757 case PW_TYPE_IPV4_PREFIX:
1759 struct in_addr addr;
1764 memcpy(&addr, &(data->ipv4prefix[2]), sizeof(addr));
1766 a = inet_ntop(AF_INET, &addr, buf, sizeof(buf));
1772 len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) (data->ipv4prefix[1] & 0x3f));
1777 case PW_TYPE_ETHERNET:
1778 return snprintf(out, outlen, "%02x:%02x:%02x:%02x:%02x:%02x",
1779 data->ether[0], data->ether[1],
1780 data->ether[2], data->ether[3],
1781 data->ether[4], data->ether[5]);
1784 * Don't add default here
1786 case PW_TYPE_INVALID:
1787 case PW_TYPE_COMBO_IP_ADDR:
1788 case PW_TYPE_COMBO_IP_PREFIX:
1789 case PW_TYPE_EXTENDED:
1790 case PW_TYPE_LONG_EXTENDED:
1793 case PW_TYPE_TIMEVAL:
1794 case PW_TYPE_BOOLEAN:
1801 if (a) strlcpy(out, a, outlen);
1803 return len; /* Return the number of bytes we would of written (for truncation detection) */