2 * valuepair.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 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2014 The FreeRADIUS server project
25 #include <freeradius-devel/libradius.h>
28 /** Compare two values
30 * @param[in] a_type of data to compare.
31 * @param[in] a_len of data to compare.
32 * @param[in] a Value to compare.
33 * @param[in] b_type of data to compare.
34 * @param[in] b_len of data to compare.
35 * @param[in] b Value to compare.
36 * @return -1 if a is less than b, 0 if both are equal, 1 if a is more than b, < -1 on error.
38 int value_data_cmp(PW_TYPE a_type, value_data_t const *a, size_t a_len,
39 PW_TYPE b_type, value_data_t const *b, size_t b_len)
43 if (a_type != b_type) {
44 fr_strerror_printf("Can't compare values of different types");
49 * After doing the previous check for special comparisons,
50 * do the per-type comparison here.
55 case PW_TYPE_STRING: /* We use memcmp to be \0 safe */
66 compare = memcmp(a->octets, b->octets, length);
67 if (compare != 0) break;
71 * Contents are the same. The return code
72 * is therefore the difference in lengths.
74 * i.e. "0x00" is smaller than "0x0000"
76 compare = a_len - b_len;
81 * Short-hand for simplicity.
83 #define CHECK(_type) if (a->_type < b->_type) { compare = -1; \
84 } else if (a->_type > b->_type) { compare = +1; }
86 case PW_TYPE_BOOLEAN: /* this isn't a RADIUS type, and shouldn't really ever be used */
100 case PW_TYPE_INTEGER:
108 case PW_TYPE_INTEGER64:
112 case PW_TYPE_ETHERNET:
113 compare = memcmp(&a->ether, &b->ether, sizeof(a->ether));
116 case PW_TYPE_IPV4_ADDR: {
117 uint32_t a_int, b_int;
119 a_int = ntohl(a->ipaddr.s_addr);
120 b_int = ntohl(b->ipaddr.s_addr);
123 } else if (a_int > b_int) {
129 case PW_TYPE_IPV6_ADDR:
130 compare = memcmp(&a->ipv6addr, &b->ipv6addr, sizeof(a->ipv6addr));
133 case PW_TYPE_IPV6_PREFIX:
134 compare = memcmp(&a->ipv6prefix, &b->ipv6prefix, sizeof(a->ipv6prefix));
137 case PW_TYPE_IPV4_PREFIX:
138 compare = memcmp(&a->ipv4prefix, &b->ipv4prefix, sizeof(a->ipv4prefix));
142 compare = memcmp(&a->ifid, &b->ifid, sizeof(a->ifid));
146 * Na of the types below should be in the REQUEST
148 case PW_TYPE_INVALID: /* We should never see these */
149 case PW_TYPE_COMBO_IP_ADDR: /* This should have been converted into IPADDR/IPV6ADDR */
150 case PW_TYPE_COMBO_IP_PREFIX: /* This should have been converted into IPADDR/IPV6ADDR */
152 case PW_TYPE_EXTENDED:
153 case PW_TYPE_LONG_EXTENDED:
156 case PW_TYPE_TIMEVAL:
158 fr_assert(0); /* unknown type */
162 * Do NOT add a default here, as new types are added
163 * static analysis will warn us they're not handled
169 } else if (compare < 0) {
176 * We leverage the fact that IPv4 and IPv6 prefixes both
177 * have the same format:
179 * reserved, prefix-len, data...
181 static int value_data_cidr_cmp_op(FR_TOKEN op, int bytes,
182 uint8_t a_net, uint8_t const *a,
183 uint8_t b_net, uint8_t const *b)
189 * Handle the case of netmasks being identical.
191 if (a_net == b_net) {
194 compare = memcmp(a, b, bytes);
197 * If they're identical return true for
200 if ((compare == 0) &&
201 ((op == T_OP_CMP_EQ) ||
208 * Everything else returns false.
210 * 10/8 == 24/8 --> false
211 * 10/8 <= 24/8 --> false
212 * 10/8 >= 24/8 --> false
218 * Netmasks are different. That limits the
219 * possible results, based on the operator.
229 case T_OP_LT: /* 192/8 < 192.168/16 --> false */
236 case T_OP_GT: /* 192/16 > 192.168/8 --> false */
253 * Do the check byte by byte. If the bytes are
254 * identical, it MAY be a match. If they're different,
260 * All leading bytes are identical.
262 if (common == 0) return true;
265 * Doing bitmasks takes more work.
267 if (common < 8) break;
269 if (a[i] != b[i]) return false;
277 mask <<= (8 - common);
281 if ((a[i] & mask) == ((b[i] & mask))) {
288 /** Compare two attributes using an operator
290 * @param[in] op to use in comparison.
291 * @param[in] a_type of data to compare.
292 * @param[in] a_len of data to compare.
293 * @param[in] a Value to compare.
294 * @param[in] b_type of data to compare.
295 * @param[in] b_len of data to compare.
296 * @param[in] b Value to compare.
297 * @return 1 if true, 0 if false, -1 on error.
299 int value_data_cmp_op(FR_TOKEN op,
300 PW_TYPE a_type, value_data_t const *a, size_t a_len,
301 PW_TYPE b_type, value_data_t const *b, size_t b_len)
305 if (!a || !b) return -1;
308 case PW_TYPE_IPV4_ADDR:
310 case PW_TYPE_IPV4_ADDR: /* IPv4 and IPv4 */
313 case PW_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
314 return value_data_cidr_cmp_op(op, 4, 32, (uint8_t const *) &a->ipaddr,
315 b->ipv4prefix[1], (uint8_t const *) &b->ipv4prefix + 2);
318 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");
341 case PW_TYPE_IPV6_ADDR:
343 case PW_TYPE_IPV6_ADDR: /* IPv6 and IPv6 */
346 case PW_TYPE_IPV6_PREFIX: /* IPv6 and IPv6 Preifx */
347 return value_data_cidr_cmp_op(op, 16, 128, (uint8_t const *) &a->ipv6addr,
348 b->ipv6prefix[1], (uint8_t const *) &b->ipv6prefix + 2);
352 fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
357 case PW_TYPE_IPV6_PREFIX:
359 case PW_TYPE_IPV6_ADDR: /* IPv6 Prefix and IPv6 */
360 return value_data_cidr_cmp_op(op, 16, a->ipv6prefix[1],
361 (uint8_t const *) &a->ipv6prefix + 2,
362 128, (uint8_t const *) &b->ipv6addr);
364 case PW_TYPE_IPV6_PREFIX: /* IPv6 Prefix and IPv6 */
365 return value_data_cidr_cmp_op(op, 16, a->ipv6prefix[1],
366 (uint8_t const *) &a->ipv6prefix + 2,
367 b->ipv6prefix[1], (uint8_t const *) &b->ipv6prefix + 2);
370 fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
377 compare = value_data_cmp(a_type, a, a_len,
379 if (compare < -1) { /* comparison error */
385 * Now do the operator comparison.
389 return (compare == 0);
392 return (compare != 0);
395 return (compare < 0);
398 return (compare > 0);
401 return (compare <= 0);
404 return (compare >= 0);
411 static char const hextab[] = "0123456789abcdef";
413 /** Convert string value to a value_data_t type
415 * @param[in] ctx to alloc strings in.
416 * @param[out] dst where to write parsed value.
417 * @param[in,out] src_type of value data to create/type of value created.
418 * @param[in] src_enumv DICT_ATTR with string aliases for integer values.
419 * @param[in] src String to convert. Binary safe for variable length values if len is provided.
420 * @param[in] src_len may be < 0 in which case strlen(len) is used to determine length, else src_len
421 * should be the length of the string or sub string to parse.
422 * @param[in] quote quotation character used to drive de-escaping
423 * @return length of data written to out or -1 on parse error.
425 ssize_t value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst,
426 PW_TYPE *src_type, DICT_ATTR const *src_enumv,
427 char const *src, ssize_t src_len, char quote)
436 len = (src_len < 0) ? strlen(src) : (size_t)src_len;
439 * Set size for all fixed length attributes.
441 ret = dict_attr_sizes[*src_type][1]; /* Max length */
444 * It's a variable ret src_type so we just alloc a new buffer
445 * of size len and copy.
454 dst->strvalue = p = talloc_memdup(ctx, src, len + 1);
456 talloc_set_type(p, char);
459 * No de-quoting. Just copy the string.
467 * Do escaping for single quoted strings. Only
468 * single quotes get escaped. Everything else is
475 * Escape ONLY the quotation character.
476 * Everything else is left as-is.
478 while (q < (dst->strvalue + len)) {
479 if ((q[0] == '\\') &&
487 * Not escaped, just copy it over.
493 ret = p - dst->strvalue;
494 dst->ptr = talloc_realloc(ctx, dst->ptr, char, ret + 1);
499 * It's "string" or `string`, do all standard
503 while (q < (dst->strvalue + len)) {
506 if ((c == '\\') && (q >= (dst->strvalue + len))) {
507 fr_strerror_printf("Invalid escape at end of string");
512 * Fix up \X -> ... the binary form of it.
538 * \" --> ", but only inside of double quoted strings, etc.
547 * \000 --> binary zero character
555 (sscanf(q, "%3o", &x) == 1)) {
561 * Else It's not a recognised escape sequence DON'T
562 * consume the backslash. This is identical
563 * behaviour to bash and most other things that
564 * use backslash escaping.
573 ret = p - dst->strvalue;
574 dst->ptr = talloc_realloc(ctx, dst->ptr, char, ret + 1);
578 /* raw octets: 0x01020304... */
580 if (strcmp(src, "ANY") == 0) {
583 } /* else it's hex */
590 * No 0x prefix, just copy verbatim.
592 if ((len < 2) || (strncasecmp(src, "0x", 2) != 0)) {
593 dst->octets = talloc_memdup(ctx, (uint8_t const *)src, len);
594 talloc_set_type(dst->octets, uint8_t);
605 if ((len & 0x01) != 0) {
606 fr_strerror_printf("Length of Hex String is not even, got %zu bytes", ret);
611 p = talloc_array(ctx, uint8_t, ret);
612 if (fr_hex2bin(p, ret, src + 2, len) != (size_t)ret) {
614 fr_strerror_printf("Invalid hex data");
622 case PW_TYPE_ABINARY:
623 #ifdef WITH_ASCEND_BINARY
624 if ((len > 1) && (strncasecmp(src, "0x", 2) == 0)) goto do_octets;
626 if (ascend_parse_filter(dst, src, len) < 0 ) {
627 /* Allow ascend_parse_filter's strerror to bubble up */
630 ret = sizeof(dst->filter);
634 * If Ascend binary is NOT defined,
635 * then fall through to raw octets, so that
636 * the user can at least make them by hand...
641 /* don't use this! */
646 if ((len < 2) || (len & 0x01) || (strncasecmp(src, "0x", 2) != 0)) {
647 fr_strerror_printf("Invalid TLV specification");
653 p = talloc_array(ctx, uint8_t, ret);
655 fr_strerror_printf("No memory");
658 if (fr_hex2bin(p, ret, src + 2, len) != (size_t)ret) {
659 fr_strerror_printf("Invalid hex data in TLV");
667 case PW_TYPE_IPV4_ADDR:
671 if (fr_pton4(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
674 * We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
675 * print them this way.
677 if (addr.prefix != 32) {
678 fr_strerror_printf("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted "
679 "for non-prefix types", addr.prefix);
683 dst->ipaddr.s_addr = addr.ipaddr.ip4addr.s_addr;
687 case PW_TYPE_IPV4_PREFIX:
691 if (fr_pton4(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
693 dst->ipv4prefix[1] = addr.prefix;
694 memcpy(dst->ipv4prefix + 2, &addr.ipaddr.ip4addr.s_addr, sizeof(dst->ipv4prefix) - 2);
698 case PW_TYPE_IPV6_ADDR:
702 if (fr_pton6(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
705 * We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
706 * print them this way.
708 if (addr.prefix != 128) {
709 fr_strerror_printf("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted "
710 "for non-prefix types", addr.prefix);
714 memcpy(&dst->ipv6addr, &addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6addr));
718 case PW_TYPE_IPV6_PREFIX:
722 if (fr_pton6(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
724 dst->ipv6prefix[1] = addr.prefix;
725 memcpy(dst->ipv6prefix + 2, &addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6prefix) - 2);
734 * It's a fixed size src_type, copy to a temporary buffer and
735 * \0 terminate if insize >= 0.
738 if (len >= sizeof(buffer)) {
739 fr_strerror_printf("Temporary buffer too small");
743 memcpy(buffer, src, src_len);
744 buffer[src_len] = '\0';
755 * Note that ALL integers are unsigned!
757 i = fr_strtoul(src, &p);
760 * Look for the named src for the given
763 if (src_enumv && *p && !is_whitespace(p)) {
764 if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
765 fr_strerror_printf("Unknown or invalid value \"%s\" for attribute '%s'",
766 src, src_enumv->name);
770 dst->byte = dval->value;
773 fr_strerror_printf("Byte value \"%s\" is larger than 255", src);
788 * Note that ALL integers are unsigned!
790 i = fr_strtoul(src, &p);
793 * Look for the named src for the given
796 if (src_enumv && *p && !is_whitespace(p)) {
797 if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
798 fr_strerror_printf("Unknown or invalid value \"%s\" for attribute '%s'",
799 src, src_enumv->name);
803 dst->ushort = dval->value;
806 fr_strerror_printf("Short value \"%s\" is larger than 65535", src);
815 case PW_TYPE_INTEGER:
821 * Note that ALL integers are unsigned!
823 i = fr_strtoul(src, &p);
826 * Look for the named src for the given
829 if (src_enumv && *p && !is_whitespace(p)) {
830 if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
831 fr_strerror_printf("Unknown or invalid value \"%s\" for attribute \"%s\"",
832 src, src_enumv->name);
836 dst->integer = dval->value;
839 * Value is always within the limits
846 case PW_TYPE_INTEGER64:
851 * Note that ALL integers are unsigned!
853 if (sscanf(src, "%" PRIu64, &i) != 1) {
854 fr_strerror_printf("Failed parsing \"%s\" as unsigned 64bit integer", src);
864 * time_t may be 64 bits, whule vp_date MUST be 32-bits. We need an
865 * intermediary variable to handle the conversions.
869 if (fr_get_time(src, &date) < 0) {
870 fr_strerror_printf("failed to parse time string \"%s\"", src);
880 if (ifid_aton(src, (void *) &dst->ifid) == NULL) {
881 fr_strerror_printf("Failed to parse interface-id string \"%s\"", src);
886 case PW_TYPE_ETHERNET:
888 char const *c1, *c2, *cp;
892 * Convert things which are obviously integers to Ethernet addresses
894 * We assume the number is the bigendian representation of the
897 if (is_integer(src)) {
898 uint64_t integer = htonll(atoll(src));
900 memcpy(&dst->ether, &integer, sizeof(dst->ether));
908 c2 = memchr(hextab, tolower((int) cp[0]), 16);
910 } else if ((cp[1] != '\0') && ((cp[2] == ':') || (cp[2] == '\0'))) {
911 c1 = memchr(hextab, tolower((int) cp[0]), 16);
912 c2 = memchr(hextab, tolower((int) cp[1]), 16);
914 if (*cp == ':') cp++;
918 if (!c1 || !c2 || (p_len >= sizeof(dst->ether))) {
919 fr_strerror_printf("failed to parse Ethernet address \"%s\"", src);
922 dst->ether[p_len] = ((c1-hextab)<<4) + (c2-hextab);
929 * Crazy polymorphic (IPv4/IPv6) attribute src_type for WiMAX.
931 * We try and make is saner by replacing the original
932 * da, with either an IPv4 or IPv6 da src_type.
934 * These are not dynamic da, and will have the same vendor
935 * and attribute as the original.
937 case PW_TYPE_COMBO_IP_ADDR:
939 if (inet_pton(AF_INET6, src, &dst->ipv6addr) > 0) {
940 *src_type = PW_TYPE_IPV6_ADDR;
941 ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][1]; /* size of IPv6 address */
945 if (ip_hton(&ipaddr, AF_INET, src, false) < 0) {
946 fr_strerror_printf("Failed to find IPv4 address for %s", src);
950 *src_type = PW_TYPE_IPV4_ADDR;
951 dst->ipaddr.s_addr = ipaddr.ipaddr.ip4addr.s_addr;
952 ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][0]; /* size of IPv4 address */
958 /* Damned code for 1 WiMAX attribute */
959 dst->sinteger = (int32_t)strtol(src, NULL, 10);
966 fr_strerror_printf("Unknown attribute type %d", *src_type);
974 /** Performs byte order reversal for types that need it
977 static void value_data_hton(value_data_t *dst, PW_TYPE type, void const *src, size_t src_len)
979 /* 8 byte integers */
981 case PW_TYPE_INTEGER64:
982 dst->integer64 = htonll(*(uint64_t const *)src);
985 /* 4 byte integers */
986 case PW_TYPE_INTEGER:
989 dst->integer = htonl(*(uint32_t const *)src);
992 /* 2 byte integers */
994 dst->ushort = htons(*(uint16_t const *)src);
1002 memcpy(dst, src, src_len);
1006 /** Convert one type of value_data_t to another
1008 * @note This should be the canonical function used to convert between data types.
1010 * @param ctx to allocate buffers in (usually the same as dst)
1011 * @param dst Where to write result of casting.
1012 * @param dst_type to cast to.
1013 * @param dst_enumv Enumerated values used to converts strings to integers.
1014 * @param src_type to cast from.
1015 * @param src_enumv Enumerated values used to convert integers to strings.
1016 * @param src Input data.
1017 * @param src_len Input data len.
1018 * @return the length of data in the dst.
1020 ssize_t value_data_cast(TALLOC_CTX *ctx, value_data_t *dst,
1021 PW_TYPE dst_type, DICT_ATTR const *dst_enumv,
1022 PW_TYPE src_type, DICT_ATTR const *src_enumv,
1023 value_data_t const *src, size_t src_len)
1025 if (!fr_assert(dst_type != src_type)) return -1;
1028 * Deserialise a value_data_t
1030 if (src_type == PW_TYPE_STRING) {
1031 return value_data_from_str(ctx, dst, &dst_type, dst_enumv, src->strvalue, src_len, '\0');
1035 * Converts the src data to octets with no processing.
1037 if (dst_type == PW_TYPE_OCTETS) {
1038 if (src_type == PW_TYPE_STRING) {
1039 dst->octets = talloc_memdup(ctx, src->strvalue, src_len);
1041 value_data_hton(dst, src_type, src, src_len);
1042 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 = vp_data_aprints_value(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 * The attribute we've found has to have a size which is
1153 * compatible with the type of the destination cast.
1155 if ((src_len < dict_attr_sizes[dst_type][0]) ||
1156 (src_len > dict_attr_sizes[dst_type][1])) {
1157 char const *src_type_name;
1159 src_type_name = fr_int2str(dict_attr_types, src_type, "<INVALID>");
1160 fr_strerror_printf("Invalid cast from %s to %s. Length should be between %zu and %zu but is %zu",
1162 fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
1163 dict_attr_sizes[dst_type][0], dict_attr_sizes[dst_type][1],
1168 if (src_type == PW_TYPE_OCTETS) {
1170 value_data_hton(dst, dst_type, src->octets, src_len);
1175 * Convert host order to network byte order.
1177 if ((dst_type == PW_TYPE_IPV4_ADDR) &&
1178 ((src_type == PW_TYPE_INTEGER) ||
1179 (src_type == PW_TYPE_DATE) ||
1180 (src_type == PW_TYPE_SIGNED))) {
1181 dst->ipaddr.s_addr = htonl(src->integer);
1183 } else if ((src_type == PW_TYPE_IPV4_ADDR) &&
1184 ((dst_type == PW_TYPE_INTEGER) ||
1185 (dst_type == PW_TYPE_DATE) ||
1186 (dst_type == PW_TYPE_SIGNED))) {
1187 dst->integer = htonl(src->ipaddr.s_addr);
1189 } else { /* they're of the same byte order */
1190 memcpy(&dst, &src, src_len);
1196 /** Copy value data verbatim duplicating any buffers
1198 * @param ctx To allocate buffers in.
1199 * @param dst Where to copy value_data to.
1200 * @param src_type Type of src.
1201 * @param src Where to copy value_data from.
1202 * @param src_len Where
1204 ssize_t value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE src_type,
1205 const value_data_t *src, size_t src_len)
1209 memcpy(dst, src, sizeof(*src));
1212 case PW_TYPE_STRING:
1213 dst->strvalue = talloc_memdup(ctx, src->strvalue, src_len + 1);
1214 if (!dst->strvalue) return -1;
1215 talloc_set_type(dst->strvalue, char);
1218 case PW_TYPE_OCTETS:
1219 dst->octets = talloc_memdup(ctx, src->octets, src_len);
1220 talloc_set_type(dst->strvalue, uint8_t);
1221 if (!dst->octets) return -1;