fix printing of long hex values
[freeradius.git] / src / lib / value.c
1 /*
2  * value.c      Functions to handle value_data_t
3  *
4  * Version:     $Id$
5  *
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.
10  *
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.
15  *
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
19  *
20  * Copyright 2014 The FreeRADIUS server project
21  */
22
23 RCSID("$Id$")
24
25 #include <freeradius-devel/libradius.h>
26 #include <ctype.h>
27
28 /** Compare two values
29  *
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.
37  */
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)
40 {
41         int compare = 0;
42
43         if (a_type != b_type) {
44                 fr_strerror_printf("Can't compare values of different types");
45                 return -2;
46         }
47
48         /*
49          *      After doing the previous check for special comparisons,
50          *      do the per-type comparison here.
51          */
52         switch (a_type) {
53         case PW_TYPE_ABINARY:
54         case PW_TYPE_OCTETS:
55         case PW_TYPE_STRING:    /* We use memcmp to be \0 safe */
56         {
57                 size_t length;
58
59                 if (a_len < b_len) {
60                         length = a_len;
61                 } else {
62                         length = b_len;
63                 }
64
65                 if (length) {
66                         compare = memcmp(a->octets, b->octets, length);
67                         if (compare != 0) break;
68                 }
69
70                 /*
71                  *      Contents are the same.  The return code
72                  *      is therefore the difference in lengths.
73                  *
74                  *      i.e. "0x00" is smaller than "0x0000"
75                  */
76                 compare = a_len - b_len;
77         }
78                 break;
79
80                 /*
81                  *      Short-hand for simplicity.
82                  */
83 #define CHECK(_type) if (a->_type < b->_type)   { compare = -1; \
84                 } else if (a->_type > b->_type) { compare = +1; }
85
86         case PW_TYPE_BOOLEAN:   /* this isn't a RADIUS type, and shouldn't really ever be used */
87         case PW_TYPE_BYTE:
88                 CHECK(byte);
89                 break;
90
91
92         case PW_TYPE_SHORT:
93                 CHECK(ushort);
94                 break;
95
96         case PW_TYPE_DATE:
97                 CHECK(date);
98                 break;
99
100         case PW_TYPE_INTEGER:
101                 CHECK(integer);
102                 break;
103
104         case PW_TYPE_SIGNED:
105                 CHECK(sinteger);
106                 break;
107
108         case PW_TYPE_INTEGER64:
109                 CHECK(integer64);
110                 break;
111
112         case PW_TYPE_ETHERNET:
113                 compare = memcmp(a->ether, b->ether, sizeof(a->ether));
114                 break;
115
116         case PW_TYPE_IPV4_ADDR: {
117                         uint32_t a_int, b_int;
118
119                         a_int = ntohl(a->ipaddr.s_addr);
120                         b_int = ntohl(b->ipaddr.s_addr);
121                         if (a_int < b_int) {
122                                 compare = -1;
123                         } else if (a_int > b_int) {
124                                 compare = +1;
125                         }
126                 }
127                 break;
128
129         case PW_TYPE_IPV6_ADDR:
130                 compare = memcmp(&a->ipv6addr, &b->ipv6addr, sizeof(a->ipv6addr));
131                 break;
132
133         case PW_TYPE_IPV6_PREFIX:
134                 compare = memcmp(a->ipv6prefix, b->ipv6prefix, sizeof(a->ipv6prefix));
135                 break;
136
137         case PW_TYPE_IPV4_PREFIX:
138                 compare = memcmp(a->ipv4prefix, b->ipv4prefix, sizeof(a->ipv4prefix));
139                 break;
140
141         case PW_TYPE_IFID:
142                 compare = memcmp(a->ifid, b->ifid, sizeof(a->ifid));
143                 break;
144
145         /*
146          *      Na of the types below should be in the REQUEST
147          */
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 */
151         case PW_TYPE_TLV:
152         case PW_TYPE_EXTENDED:
153         case PW_TYPE_LONG_EXTENDED:
154         case PW_TYPE_EVS:
155         case PW_TYPE_VSA:
156         case PW_TYPE_TIMEVAL:
157         case PW_TYPE_MAX:
158                 fr_assert(0);   /* unknown type */
159                 return -2;
160
161         /*
162          *      Do NOT add a default here, as new types are added
163          *      static analysis will warn us they're not handled
164          */
165         }
166
167         if (compare > 0) {
168                 return 1;
169         } else if (compare < 0) {
170                 return -1;
171         }
172         return 0;
173 }
174
175 /*
176  *      We leverage the fact that IPv4 and IPv6 prefixes both
177  *      have the same format:
178  *
179  *      reserved, prefix-len, data...
180  */
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)
184 {
185         int i, common;
186         uint32_t mask;
187
188         /*
189          *      Handle the case of netmasks being identical.
190          */
191         if (a_net == b_net) {
192                 int compare;
193
194                 compare = memcmp(a, b, bytes);
195
196                 /*
197                  *      If they're identical return true for
198                  *      identical.
199                  */
200                 if ((compare == 0) &&
201                     ((op == T_OP_CMP_EQ) ||
202                      (op == T_OP_LE) ||
203                      (op == T_OP_GE))) {
204                         return true;
205                 }
206
207                 /*
208                  *      Everything else returns false.
209                  *
210                  *      10/8 == 24/8  --> false
211                  *      10/8 <= 24/8  --> false
212                  *      10/8 >= 24/8  --> false
213                  */
214                 return false;
215         }
216
217         /*
218          *      Netmasks are different.  That limits the
219          *      possible results, based on the operator.
220          */
221         switch (op) {
222         case T_OP_CMP_EQ:
223                 return false;
224
225         case T_OP_NE:
226                 return true;
227
228         case T_OP_LE:
229         case T_OP_LT:   /* 192/8 < 192.168/16 --> false */
230                 if (a_net < b_net) {
231                         return false;
232                 }
233                 break;
234
235         case T_OP_GE:
236         case T_OP_GT:   /* 192/16 > 192.168/8 --> false */
237                 if (a_net > b_net) {
238                         return false;
239                 }
240                 break;
241
242         default:
243                 return false;
244         }
245
246         if (a_net < b_net) {
247                 common = a_net;
248         } else {
249                 common = b_net;
250         }
251
252         /*
253          *      Do the check byte by byte.  If the bytes are
254          *      identical, it MAY be a match.  If they're different,
255          *      it is NOT a match.
256          */
257         i = 0;
258         while (i < bytes) {
259                 /*
260                  *      All leading bytes are identical.
261                  */
262                 if (common == 0) return true;
263
264                 /*
265                  *      Doing bitmasks takes more work.
266                  */
267                 if (common < 8) break;
268
269                 if (a[i] != b[i]) return false;
270
271                 common -= 8;
272                 i++;
273                 continue;
274         }
275
276         mask = 1;
277         mask <<= (8 - common);
278         mask--;
279         mask = ~mask;
280
281         if ((a[i] & mask) == ((b[i] & mask))) {
282                 return true;
283         }
284
285         return false;
286 }
287
288 /** Compare two attributes using an operator
289  *
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.
298  */
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)
302 {
303         int compare = 0;
304
305         if (!a || !b) return -1;
306
307         switch (a_type) {
308         case PW_TYPE_IPV4_ADDR:
309                 switch (b_type) {
310                 case PW_TYPE_IPV4_ADDR:         /* IPv4 and IPv4 */
311                         goto cmp;
312
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]);
316
317                 default:
318                         fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
319                         return -1;
320                 }
321
322         case PW_TYPE_IPV4_PREFIX:               /* IPv4 and IPv4 Prefix */
323                 switch (b_type) {
324                 case PW_TYPE_IPV4_ADDR:
325                         return value_data_cidr_cmp_op(op, 4, a->ipv4prefix[1],
326                                                     (uint8_t const *) &a->ipv4prefix[2],
327                                                     32, (uint8_t const *) &b->ipaddr);
328
329                 case PW_TYPE_IPV4_PREFIX:       /* IPv4 Prefix and IPv4 Prefix */
330                         return value_data_cidr_cmp_op(op, 4, a->ipv4prefix[1],
331                                                     (uint8_t const *) &a->ipv4prefix[2],
332                                                     b->ipv4prefix[1], (uint8_t const *) &b->ipv4prefix[2]);
333
334                 default:
335                         fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
336                         return -1;
337                 }
338
339         case PW_TYPE_IPV6_ADDR:
340                 switch (b_type) {
341                 case PW_TYPE_IPV6_ADDR:         /* IPv6 and IPv6 */
342                         goto cmp;
343
344                 case PW_TYPE_IPV6_PREFIX:       /* IPv6 and IPv6 Preifx */
345                         return value_data_cidr_cmp_op(op, 16, 128, (uint8_t const *) &a->ipv6addr,
346                                                       b->ipv6prefix[1], (uint8_t const *) &b->ipv6prefix[2]);
347
348                 default:
349                         fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
350                         return -1;
351                 }
352
353         case PW_TYPE_IPV6_PREFIX:
354                 switch (b_type) {
355                 case PW_TYPE_IPV6_ADDR:         /* IPv6 Prefix and IPv6 */
356                         return value_data_cidr_cmp_op(op, 16, a->ipv6prefix[1],
357                                                       (uint8_t const *) &a->ipv6prefix[2],
358                                                       128, (uint8_t const *) &b->ipv6addr);
359
360                 case PW_TYPE_IPV6_PREFIX:       /* IPv6 Prefix and IPv6 */
361                         return value_data_cidr_cmp_op(op, 16, a->ipv6prefix[1],
362                                                       (uint8_t const *) &a->ipv6prefix[2],
363                                                       b->ipv6prefix[1], (uint8_t const *) &b->ipv6prefix[2]);
364
365                 default:
366                         fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
367                         return -1;
368                 }
369
370         default:
371         cmp:
372                 compare = value_data_cmp(a_type, a, a_len,
373                                          b_type, b, b_len);
374                 if (compare < -1) {     /* comparison error */
375                         return -1;
376                 }
377         }
378
379         /*
380          *      Now do the operator comparison.
381          */
382         switch (op) {
383         case T_OP_CMP_EQ:
384                 return (compare == 0);
385
386         case T_OP_NE:
387                 return (compare != 0);
388
389         case T_OP_LT:
390                 return (compare < 0);
391
392         case T_OP_GT:
393                 return (compare > 0);
394
395         case T_OP_LE:
396                 return (compare <= 0);
397
398         case T_OP_GE:
399                 return (compare >= 0);
400
401         default:
402                 return 0;
403         }
404 }
405
406 static char const hextab[] = "0123456789abcdef";
407
408 /** Convert string value to a value_data_t type
409  *
410  * @param[in] ctx to alloc strings in.
411  * @param[out] dst where to write parsed value.
412  * @param[in,out] src_type of value data to create/type of value created.
413  * @param[in] src_enumv DICT_ATTR with string aliases for integer values.
414  * @param[in] src String to convert. Binary safe for variable length values if len is provided.
415  * @param[in] src_len may be < 0 in which case strlen(len) is used to determine length, else src_len
416  *        should be the length of the string or sub string to parse.
417  * @param[in] quote quotation character used to drive de-escaping
418  * @return length of data written to out or -1 on parse error.
419  */
420 ssize_t value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst,
421                             PW_TYPE *src_type, DICT_ATTR const *src_enumv,
422                             char const *src, ssize_t src_len, char quote)
423 {
424         DICT_VALUE      *dval;
425         size_t          len;
426         ssize_t         ret;
427         char            buffer[256];
428
429         if (!src) return -1;
430
431         len = (src_len < 0) ? strlen(src) : (size_t)src_len;
432
433         /*
434          *      Set size for all fixed length attributes.
435          */
436         ret = dict_attr_sizes[*src_type][1];    /* Max length */
437
438         /*
439          *      It's a variable ret src_type so we just alloc a new buffer
440          *      of size len and copy.
441          */
442         switch (*src_type) {
443         case PW_TYPE_STRING:
444         {
445                 char            *p, *buff;
446                 char const      *q;
447                 int             x;
448
449                 buff = p = talloc_bstrndup(ctx, src, len);
450
451                 /*
452                  *      No de-quoting.  Just copy the string.
453                  */
454                 if (!quote) {
455                         ret = len;
456                         dst->strvalue = buff;
457                         goto finish;
458                 }
459
460                 /*
461                  *      Do escaping for single quoted strings.  Only
462                  *      single quotes get escaped.  Everything else is
463                  *      left as-is.
464                  */
465                 if (quote == '\'') {
466                         q = p;
467
468                         while (q < (buff + len)) {
469                                 /*
470                                  *      The quotation character is escaped.
471                                  */
472                                 if ((q[0] == '\\') &&
473                                     (q[1] == quote)) {
474                                         *(p++) = quote;
475                                         q += 2;
476                                         continue;
477                                 }
478
479                                 /*
480                                  *      Two backslashes get mangled to one.
481                                  */
482                                 if ((q[0] == '\\') &&
483                                     (q[1] == '\\')) {
484                                         *(p++) = '\\';
485                                         q += 2;
486                                         continue;
487                                 }
488
489                                 /*
490                                  *      Not escaped, just copy it over.
491                                  */
492                                 *(p++) = *(q++);
493                         }
494
495                         *p = '\0';
496                         ret = p - buff;
497
498                         /* Shrink the buffer to the correct size */
499                         dst->strvalue = talloc_realloc(ctx, buff, char, ret + 1);
500                         goto finish;
501                 }
502
503                 /*
504                  *      It's "string" or `string`, do all standard
505                  *      escaping.
506                  */
507                 q = p;
508                 while (q < (buff + len)) {
509                         char c = *q++;
510
511                         if ((c == '\\') && (q >= (buff + len))) {
512                                 fr_strerror_printf("Invalid escape at end of string");
513                                 talloc_free(buff);
514                                 return -1;
515                         }
516
517                         /*
518                          *      Fix up \X -> ... the binary form of it.
519                          */
520                         if (c == '\\') {
521                                 switch (*q) {
522                                 case 'r':
523                                         c = '\r';
524                                         q++;
525                                         break;
526
527                                 case 'n':
528                                         c = '\n';
529                                         q++;
530                                         break;
531
532                                 case 't':
533                                         c = '\t';
534                                         q++;
535                                         break;
536
537                                 case '\\':
538                                         c = '\\';
539                                         q++;
540                                         break;
541
542                                 default:
543                                         /*
544                                          *      \" --> ", but only inside of double quoted strings, etc.
545                                          */
546                                         if (*q == quote) {
547                                                 c = quote;
548                                                 q++;
549                                                 break;
550                                         }
551
552                                         /*
553                                          *      \000 --> binary zero character
554                                          */
555                                         if ((q[0] >= '0') &&
556                                             (q[0] <= '9') &&
557                                             (q[1] >= '0') &&
558                                             (q[1] <= '9') &&
559                                             (q[2] >= '0') &&
560                                             (q[2] <= '9') &&
561                                             (sscanf(q, "%3o", &x) == 1)) {
562                                                 c = x;
563                                                 q += 3;
564                                         }
565
566                                         /*
567                                          *      Else It's not a recognised escape sequence DON'T
568                                          *      consume the backslash. This is identical
569                                          *      behaviour to bash and most other things that
570                                          *      use backslash escaping.
571                                          */
572                                 }
573                         }
574
575                         *p++ = c;
576                 }
577
578                 *p = '\0';
579                 ret = p - buff;
580                 dst->strvalue = talloc_realloc(ctx, buff, char, ret + 1);
581         }
582                 goto finish;
583
584         case PW_TYPE_VSA:
585                 fr_strerror_printf("Must use 'Attr-26 = ...' instead of 'Vendor-Specific = ...'");
586                 return -1;
587
588         /* raw octets: 0x01020304... */
589 #ifndef WITH_ASCEND_BINARY
590         do_octets:
591 #endif
592         case PW_TYPE_OCTETS:
593         {
594                 uint8_t *p;
595
596                 /*
597                  *      No 0x prefix, just copy verbatim.
598                  */
599                 if ((len < 2) || (strncasecmp(src, "0x", 2) != 0)) {
600                         dst->octets = talloc_memdup(ctx, (uint8_t const *)src, len);
601                         talloc_set_type(dst->octets, uint8_t);
602                         ret = len;
603                         goto finish;
604                 }
605
606                 len -= 2;
607
608                 /*
609                  *      Invalid.
610                  */
611                 if ((len & 0x01) != 0) {
612                         fr_strerror_printf("Length of Hex String is not even, got %zu bytes", len);
613                         return -1;
614                 }
615
616                 ret = len >> 1;
617                 p = talloc_array(ctx, uint8_t, ret);
618                 if (fr_hex2bin(p, ret, src + 2, len) != (size_t)ret) {
619                         talloc_free(p);
620                         fr_strerror_printf("Invalid hex data");
621                         return -1;
622                 }
623
624                 dst->octets = p;
625         }
626                 goto finish;
627
628         case PW_TYPE_ABINARY:
629 #ifdef WITH_ASCEND_BINARY
630                 if ((len > 1) && (strncasecmp(src, "0x", 2) == 0)) {
631                         ssize_t bin;
632
633                         if (len > ((sizeof(dst->filter) + 1) * 2)) {
634                                 fr_strerror_printf("Hex data is too large for ascend filter");
635                                 return -1;
636                         }
637
638                         bin = fr_hex2bin((uint8_t *) &dst->filter, ret, src + 2, len - 2);
639                         if (bin < ret) {
640                                 memset(((uint8_t *) &dst->filter) + bin, 0, ret - bin);
641                         }
642                 } else {
643                         if (ascend_parse_filter(dst, src, len) < 0 ) {
644                                 /* Allow ascend_parse_filter's strerror to bubble up */
645                                 return -1;
646                         }
647                 }
648
649                 ret = sizeof(dst->filter);
650                 goto finish;
651 #else
652                 /*
653                  *      If Ascend binary is NOT defined,
654                  *      then fall through to raw octets, so that
655                  *      the user can at least make them by hand...
656                  */
657                 goto do_octets;
658 #endif
659
660         /* don't use this! */
661         case PW_TYPE_TLV:
662                 fr_strerror_printf("Cannot parse TLV");
663                 return -1;
664
665         case PW_TYPE_IPV4_ADDR:
666         {
667                 fr_ipaddr_t addr;
668
669                 if (fr_pton4(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
670
671                 /*
672                  *      We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
673                  *      print them this way.
674                  */
675                 if (addr.prefix != 32) {
676                         fr_strerror_printf("Invalid IPv4 mask length \"/%i\".  Only \"/32\" permitted "
677                                            "for non-prefix types", addr.prefix);
678                         return -1;
679                 }
680
681                 dst->ipaddr.s_addr = addr.ipaddr.ip4addr.s_addr;
682         }
683                 goto finish;
684
685         case PW_TYPE_IPV4_PREFIX:
686         {
687                 fr_ipaddr_t addr;
688
689                 if (fr_pton4(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
690
691                 dst->ipv4prefix[1] = addr.prefix;
692                 memcpy(&dst->ipv4prefix[2], &addr.ipaddr.ip4addr.s_addr, sizeof(dst->ipv4prefix) - 2);
693         }
694                 goto finish;
695
696         case PW_TYPE_IPV6_ADDR:
697         {
698                 fr_ipaddr_t addr;
699
700                 if (fr_pton6(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
701
702                 /*
703                  *      We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
704                  *      print them this way.
705                  */
706                 if (addr.prefix != 128) {
707                         fr_strerror_printf("Invalid IPv6 mask length \"/%i\".  Only \"/128\" permitted "
708                                            "for non-prefix types", addr.prefix);
709                         return -1;
710                 }
711
712                 memcpy(&dst->ipv6addr, addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6addr));
713         }
714                 goto finish;
715
716         case PW_TYPE_IPV6_PREFIX:
717         {
718                 fr_ipaddr_t addr;
719
720                 if (fr_pton6(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
721
722                 dst->ipv6prefix[1] = addr.prefix;
723                 memcpy(&dst->ipv6prefix[2], addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6prefix) - 2);
724         }
725                 goto finish;
726
727         default:
728                 break;
729         }
730
731         /*
732          *      It's a fixed size src_type, copy to a temporary buffer and
733          *      \0 terminate if insize >= 0.
734          */
735         if (src_len > 0) {
736                 if (len >= sizeof(buffer)) {
737                         fr_strerror_printf("Temporary buffer too small");
738                         return -1;
739                 }
740
741                 memcpy(buffer, src, src_len);
742                 buffer[src_len] = '\0';
743                 src = buffer;
744         }
745
746         switch (*src_type) {
747         case PW_TYPE_BYTE:
748         {
749                 char *p;
750                 unsigned int i;
751
752                 /*
753                  *      Note that ALL integers are unsigned!
754                  */
755                 i = fr_strtoul(src, &p);
756
757                 /*
758                  *      Look for the named src for the given
759                  *      attribute.
760                  */
761                 if (src_enumv && *p && !is_whitespace(p)) {
762                         if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
763                                 fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
764                                                    src, src_enumv->name);
765                                 return -1;
766                         }
767
768                         dst->byte = dval->value;
769                 } else {
770                         if (i > 255) {
771                                 fr_strerror_printf("Byte value \"%s\" is larger than 255", src);
772                                 return -1;
773                         }
774
775                         dst->byte = i;
776                 }
777                 break;
778         }
779
780         case PW_TYPE_SHORT:
781         {
782                 char *p;
783                 unsigned int i;
784
785                 /*
786                  *      Note that ALL integers are unsigned!
787                  */
788                 i = fr_strtoul(src, &p);
789
790                 /*
791                  *      Look for the named src for the given
792                  *      attribute.
793                  */
794                 if (src_enumv && *p && !is_whitespace(p)) {
795                         if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
796                                 fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
797                                                    src, src_enumv->name);
798                                 return -1;
799                         }
800
801                         dst->ushort = dval->value;
802                 } else {
803                         if (i > 65535) {
804                                 fr_strerror_printf("Short value \"%s\" is larger than 65535", src);
805                                 return -1;
806                         }
807
808                         dst->ushort = i;
809                 }
810                 break;
811         }
812
813         case PW_TYPE_INTEGER:
814         {
815                 char *p;
816                 unsigned int i;
817
818                 /*
819                  *      Note that ALL integers are unsigned!
820                  */
821                 i = fr_strtoul(src, &p);
822
823                 /*
824                  *      Look for the named src for the given
825                  *      attribute.
826                  */
827                 if (src_enumv && *p && !is_whitespace(p)) {
828                         if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
829                                 fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
830                                                    src, src_enumv->name);
831                                 return -1;
832                         }
833
834                         dst->integer = dval->value;
835                 } else {
836                         /*
837                          *      Value is always within the limits
838                          */
839                         dst->integer = i;
840                 }
841         }
842                 break;
843
844         case PW_TYPE_INTEGER64:
845         {
846                 uint64_t i;
847
848                 /*
849                  *      Note that ALL integers are unsigned!
850                  */
851                 if (sscanf(src, "%" PRIu64, &i) != 1) {
852                         fr_strerror_printf("Failed parsing \"%s\" as unsigned 64bit integer", src);
853                         return -1;
854                 }
855                 dst->integer64 = i;
856         }
857                 break;
858
859         case PW_TYPE_DATE:
860         {
861                 /*
862                  *      time_t may be 64 bits, whule vp_date MUST be 32-bits.  We need an
863                  *      intermediary variable to handle the conversions.
864                  */
865                 time_t date;
866
867                 if (fr_get_time(src, &date) < 0) {
868                         fr_strerror_printf("failed to parse time string \"%s\"", src);
869                         return -1;
870                 }
871
872                 dst->date = date;
873         }
874
875                 break;
876
877         case PW_TYPE_IFID:
878                 if (ifid_aton(src, (void *) dst->ifid) == NULL) {
879                         fr_strerror_printf("Failed to parse interface-id string \"%s\"", src);
880                         return -1;
881                 }
882                 break;
883
884         case PW_TYPE_ETHERNET:
885         {
886                 char const *c1, *c2, *cp;
887                 size_t p_len = 0;
888
889                 /*
890                  *      Convert things which are obviously integers to Ethernet addresses
891                  *
892                  *      We assume the number is the bigendian representation of the
893                  *      ethernet address.
894                  */
895                 if (is_integer(src)) {
896                         uint64_t integer = htonll(atoll(src));
897
898                         memcpy(dst->ether, &integer, sizeof(dst->ether));
899                         break;
900                 }
901
902                 cp = src;
903                 while (*cp) {
904                         if (cp[1] == ':') {
905                                 c1 = hextab;
906                                 c2 = memchr(hextab, tolower((int) cp[0]), 16);
907                                 cp += 2;
908                         } else if ((cp[1] != '\0') && ((cp[2] == ':') || (cp[2] == '\0'))) {
909                                 c1 = memchr(hextab, tolower((int) cp[0]), 16);
910                                 c2 = memchr(hextab, tolower((int) cp[1]), 16);
911                                 cp += 2;
912                                 if (*cp == ':') cp++;
913                         } else {
914                                 c1 = c2 = NULL;
915                         }
916                         if (!c1 || !c2 || (p_len >= sizeof(dst->ether))) {
917                                 fr_strerror_printf("failed to parse Ethernet address \"%s\"", src);
918                                 return -1;
919                         }
920                         dst->ether[p_len] = ((c1-hextab)<<4) + (c2-hextab);
921                         p_len++;
922                 }
923         }
924                 break;
925
926         /*
927          *      Crazy polymorphic (IPv4/IPv6) attribute src_type for WiMAX.
928          *
929          *      We try and make is saner by replacing the original
930          *      da, with either an IPv4 or IPv6 da src_type.
931          *
932          *      These are not dynamic da, and will have the same vendor
933          *      and attribute as the original.
934          */
935         case PW_TYPE_COMBO_IP_ADDR:
936         {
937                 if (inet_pton(AF_INET6, src, &dst->ipv6addr) > 0) {
938                         *src_type = PW_TYPE_IPV6_ADDR;
939                         ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][1]; /* size of IPv6 address */
940                 } else {
941                         fr_ipaddr_t ipaddr;
942
943                         if (ip_hton(&ipaddr, AF_INET, src, false) < 0) {
944                                 fr_strerror_printf("Failed to find IPv4 address for %s", src);
945                                 return -1;
946                         }
947
948                         *src_type = PW_TYPE_IPV4_ADDR;
949                         dst->ipaddr.s_addr = ipaddr.ipaddr.ip4addr.s_addr;
950                         ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][0]; /* size of IPv4 address */
951                 }
952         }
953                 break;
954
955         case PW_TYPE_SIGNED:
956                 /* Damned code for 1 WiMAX attribute */
957                 dst->sinteger = (int32_t)strtol(src, NULL, 10);
958                 break;
959
960         /*
961          *  Anything else.
962          */
963         default:
964                 fr_strerror_printf("Unknown attribute type %d", *src_type);
965                 return -1;
966         }
967
968 finish:
969         return ret;
970 }
971
972 /** Performs byte order reversal for types that need it
973  *
974  */
975 static void value_data_hton(value_data_t *dst, PW_TYPE type, void const *src, size_t src_len)
976 {
977         /* 8 byte integers */
978         switch (type) {
979         case PW_TYPE_INTEGER64:
980                 dst->integer64 = htonll(*(uint64_t const *)src);
981                 break;
982
983         /* 4 byte integers */
984         case PW_TYPE_INTEGER:
985         case PW_TYPE_DATE:
986         case PW_TYPE_SIGNED:
987                 dst->integer = htonl(*(uint32_t const *)src);
988                 break;
989
990         /* 2 byte integers */
991         case PW_TYPE_SHORT:
992                 dst->ushort = htons(*(uint16_t const *)src);
993                 break;
994
995         case PW_TYPE_OCTETS:
996         case PW_TYPE_STRING:
997                 fr_assert(0);
998                 return;         /* shouldn't happen */
999
1000         default:
1001                 memcpy(dst, src, src_len);
1002         }
1003 }
1004
1005 /** Convert one type of value_data_t to another
1006  *
1007  * @note This should be the canonical function used to convert between data types.
1008  *
1009  * @param ctx to allocate buffers in (usually the same as dst)
1010  * @param dst Where to write result of casting.
1011  * @param dst_type to cast to.
1012  * @param dst_enumv Enumerated values used to converts strings to integers.
1013  * @param src_type to cast from.
1014  * @param src_enumv Enumerated values used to convert integers to strings.
1015  * @param src Input data.
1016  * @param src_len Input data len.
1017  * @return the length of data in the dst or -1 on error.
1018  */
1019 ssize_t value_data_cast(TALLOC_CTX *ctx, value_data_t *dst,
1020                         PW_TYPE dst_type, DICT_ATTR const *dst_enumv,
1021                         PW_TYPE src_type, DICT_ATTR const *src_enumv,
1022                         value_data_t const *src, size_t src_len)
1023 {
1024         if (!fr_assert(dst_type != src_type)) return -1;
1025
1026         /*
1027          *      Deserialise a value_data_t
1028          */
1029         if (src_type == PW_TYPE_STRING) {
1030                 return value_data_from_str(ctx, dst, &dst_type, dst_enumv, src->strvalue, src_len, '\0');
1031         }
1032
1033         /*
1034          *      Converts the src data to octets with no processing.
1035          */
1036         if (dst_type == PW_TYPE_OCTETS) {
1037                 value_data_hton(dst, src_type, src, src_len);
1038                 dst->octets = talloc_memdup(ctx, dst, src_len);
1039                 talloc_set_type(dst->octets, uint8_t);
1040                 return talloc_array_length(dst->strvalue);
1041         }
1042
1043         /*
1044          *      Serialise a value_data_t
1045          */
1046         if (dst_type == PW_TYPE_STRING) {
1047                 dst->strvalue = value_data_aprints(ctx, src_type, src_enumv, src, src_len, '\0');
1048                 return talloc_array_length(dst->strvalue) - 1;
1049         }
1050
1051         if ((src_type == PW_TYPE_IFID) &&
1052             (dst_type == PW_TYPE_INTEGER64)) {
1053                 memcpy(&dst->integer64, src->ifid, sizeof(src->ifid));
1054                 dst->integer64 = htonll(dst->integer64);
1055         fixed_length:
1056                 return dict_attr_sizes[dst_type][0];
1057         }
1058
1059         if ((src_type == PW_TYPE_INTEGER64) &&
1060             (dst_type == PW_TYPE_ETHERNET)) {
1061                 uint8_t array[8];
1062                 uint64_t i;
1063
1064                 i = htonll(src->integer64);
1065                 memcpy(array, &i, 8);
1066
1067                 /*
1068                  *      For OUIs in the DB.
1069                  */
1070                 if ((array[0] != 0) || (array[1] != 0)) return -1;
1071
1072                 memcpy(dst->ether, &array[2], 6);
1073                 goto fixed_length;
1074         }
1075
1076         /*
1077          *      For integers, we allow the casting of a SMALL type to
1078          *      a larger type, but not vice-versa.
1079          */
1080         if (dst_type == PW_TYPE_INTEGER64) {
1081                 switch (src_type) {
1082                 case PW_TYPE_BYTE:
1083                         dst->integer64 = src->byte;
1084                         break;
1085
1086                 case PW_TYPE_SHORT:
1087                         dst->integer64 = src->ushort;
1088                         break;
1089
1090                 case PW_TYPE_INTEGER:
1091                         dst->integer64 = src->integer;
1092                         break;
1093
1094                 case PW_TYPE_DATE:
1095                         dst->integer64 = src->date;
1096                         break;
1097
1098                 case PW_TYPE_OCTETS:
1099                         goto do_octets;
1100
1101                 default:
1102                 invalid_cast:
1103                         fr_strerror_printf("Invalid cast from %s to %s",
1104                                            fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1105                                            fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1106                         return -1;
1107
1108                 }
1109                 goto fixed_length;
1110         }
1111
1112         /*
1113          *      We can cast LONG integers to SHORTER ones, so long
1114          *      as the long one is on the LHS.
1115          */
1116         if (dst_type == PW_TYPE_INTEGER) {
1117                 switch (src_type) {
1118                 case PW_TYPE_BYTE:
1119                         dst->integer = src->byte;
1120                         break;
1121
1122                 case PW_TYPE_SHORT:
1123                         dst->integer = src->ushort;
1124                         break;
1125
1126                 case PW_TYPE_OCTETS:
1127                         goto do_octets;
1128
1129                 default:
1130                         goto invalid_cast;
1131                 }
1132                 goto fixed_length;
1133         }
1134
1135         if (dst_type == PW_TYPE_SHORT) {
1136                 switch (src_type) {
1137                 case PW_TYPE_BYTE:
1138                         dst->ushort = src->byte;
1139                         break;
1140
1141                 case PW_TYPE_OCTETS:
1142                         goto do_octets;
1143
1144                 default:
1145                         goto invalid_cast;
1146                 }
1147                 goto fixed_length;
1148         }
1149
1150         /*
1151          *      We can cast integers less that < INT_MAX to signed
1152          */
1153         if (dst_type == PW_TYPE_SIGNED) {
1154                 switch (src_type) {
1155                 case PW_TYPE_BYTE:
1156                         dst->sinteger = src->byte;
1157                         break;
1158
1159                 case PW_TYPE_SHORT:
1160                         dst->sinteger = src->ushort;
1161                         break;
1162
1163                 case PW_TYPE_INTEGER:
1164                         if (src->integer > INT_MAX) {
1165                                 fr_strerror_printf("Invalid cast: From integer to signed.  integer value %u is larger "
1166                                                    "than max signed int and would overflow", src->integer);
1167                                 return -1;
1168                         }
1169                         dst->sinteger = (int)src->integer;
1170                         break;
1171
1172                 case PW_TYPE_INTEGER64:
1173                         if (src->integer > INT_MAX) {
1174                                 fr_strerror_printf("Invalid cast: From integer64 to signed.  integer64 value %" PRIu64
1175                                                    " is larger than max signed int and would overflow", src->integer64);
1176                                 return -1;
1177                         }
1178                         dst->sinteger = (int)src->integer64;
1179                         break;
1180
1181                 case PW_TYPE_OCTETS:
1182                         goto do_octets;
1183
1184                 default:
1185                         goto invalid_cast;
1186                 }
1187                 goto fixed_length;
1188         }
1189         /*
1190          *      Conversions between IPv4 addresses, IPv6 addresses, IPv4 prefixes and IPv6 prefixes
1191          *
1192          *      For prefix to ipaddress conversions, we assume that the host portion has already
1193          *      been zeroed out.
1194          *
1195          *      We allow casts from v6 to v4 if the v6 address has the correct mapping prefix.
1196          *
1197          *      We only allow casts from prefixes to addresses if the prefix is the the length of
1198          *      the address, e.g. 32 for ipv4 128 for ipv6.
1199          */
1200         {
1201                 /*
1202                  *      10 bytes of 0x00 2 bytes of 0xff
1203                  */
1204                 static uint8_t const v4_v6_map[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1205                                                      0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
1206
1207                 switch (dst_type) {
1208                 case PW_TYPE_IPV4_ADDR:
1209                         switch (src_type) {
1210                         case PW_TYPE_IPV6_ADDR:
1211                                 if (memcmp(src->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
1212                                 bad_v6_prefix_map:
1213                                         fr_strerror_printf("Invalid cast from %s to %s.  No IPv4-IPv6 mapping prefix",
1214                                                            fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1215                                                            fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1216                                         return -1;
1217                                 }
1218
1219                                 memcpy(&dst->ipaddr, &src->ipv6addr.s6_addr[sizeof(v4_v6_map)],
1220                                        sizeof(dst->ipaddr));
1221                                 goto fixed_length;
1222
1223                         case PW_TYPE_IPV4_PREFIX:
1224                                 if (src->ipv4prefix[1] != 32) {
1225                                 bad_v4_prefix_len:
1226                                         fr_strerror_printf("Invalid cast from %s to %s.  Only /32 prefixes may be "
1227                                                            "cast to IP address types",
1228                                                            fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1229                                                            fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1230                                         return -1;
1231                                 }
1232
1233                                 memcpy(&dst->ipaddr, &src->ipv4prefix[2], sizeof(dst->ipaddr));
1234                                 goto fixed_length;
1235
1236                         case PW_TYPE_IPV6_PREFIX:
1237                                 if (src->ipv6prefix[1] != 128) {
1238                                 bad_v6_prefix_len:
1239                                         fr_strerror_printf("Invalid cast from %s to %s.  Only /128 prefixes may be "
1240                                                            "cast to IP address types",
1241                                                            fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1242                                                            fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1243                                         return -1;
1244                                 }
1245                                 if (memcmp(&src->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
1246                                         goto bad_v6_prefix_map;
1247                                 }
1248                                 memcpy(&dst->ipaddr, &src->ipv6prefix[2 + sizeof(v4_v6_map)],
1249                                        sizeof(dst->ipaddr));
1250                                 goto fixed_length;
1251
1252                         default:
1253                                 break;
1254                         }
1255                         break;
1256
1257                 case PW_TYPE_IPV6_ADDR:
1258                         switch (src_type) {
1259                         case PW_TYPE_IPV4_ADDR:
1260                                 /* Add the v4/v6 mapping prefix */
1261                                 memcpy(dst->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map));
1262                                 memcpy(&dst->ipv6addr.s6_addr[sizeof(v4_v6_map)], &src->ipaddr,
1263                                        sizeof(dst->ipv6addr.s6_addr) - sizeof(v4_v6_map));
1264
1265                                 goto fixed_length;
1266
1267                         case PW_TYPE_IPV4_PREFIX:
1268                                 if (src->ipv4prefix[1] != 32) goto bad_v4_prefix_len;
1269
1270                                 /* Add the v4/v6 mapping prefix */
1271                                 memcpy(dst->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map));
1272                                 memcpy(&dst->ipv6addr.s6_addr[sizeof(v4_v6_map)], &src->ipv4prefix[2],
1273                                        sizeof(dst->ipv6addr.s6_addr) - sizeof(v4_v6_map));
1274                                 goto fixed_length;
1275
1276                         case PW_TYPE_IPV6_PREFIX:
1277                                 if (src->ipv4prefix[1] != 128) goto bad_v6_prefix_len;
1278
1279                                 memcpy(dst->ipv6addr.s6_addr, &src->ipv6prefix[2], sizeof(dst->ipv6addr.s6_addr));
1280                                 goto fixed_length;
1281
1282                         default:
1283                                 break;
1284                         }
1285                         break;
1286
1287                 case PW_TYPE_IPV4_PREFIX:
1288                         switch (src_type) {
1289                         case PW_TYPE_IPV4_ADDR:
1290                                 memcpy(&dst->ipv4prefix[2], &src->ipaddr, sizeof(dst->ipv4prefix) - 2);
1291                                 dst->ipv4prefix[0] = 0;
1292                                 dst->ipv4prefix[1] = 32;
1293                                 goto fixed_length;
1294
1295                         case PW_TYPE_IPV6_ADDR:
1296                                 if (memcmp(src->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
1297                                         goto bad_v6_prefix_map;
1298                                 }
1299                                 memcpy(&dst->ipv4prefix[2], &src->ipv6addr.s6_addr[sizeof(v4_v6_map)],
1300                                        sizeof(dst->ipv4prefix) - 2);
1301                                 dst->ipv4prefix[0] = 0;
1302                                 dst->ipv4prefix[1] = 32;
1303                                 goto fixed_length;
1304
1305                         case PW_TYPE_IPV6_PREFIX:
1306                                 if (memcmp(&src->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
1307                                         goto bad_v6_prefix_map;
1308                                 }
1309
1310                                 /*
1311                                  *      Prefix must be >= 96 bits. If it's < 96 bytes and the
1312                                  *      above check passed, the v6 address wasn't masked
1313                                  *      correctly when it was packet into a value_data_t.
1314                                  */
1315                                 if (!fr_assert(src->ipv6prefix[1] >= (sizeof(v4_v6_map) * 8))) return -1;
1316
1317                                 memcpy(&dst->ipv4prefix[2], &src->ipv6prefix[2 + sizeof(v4_v6_map)],
1318                                        sizeof(dst->ipv4prefix) - 2);
1319                                 dst->ipv4prefix[0] = 0;
1320                                 dst->ipv4prefix[1] = src->ipv6prefix[1] - (sizeof(v4_v6_map) * 8);
1321                                 goto fixed_length;
1322
1323                         default:
1324                                 break;
1325                         }
1326                         break;
1327
1328                 case PW_TYPE_IPV6_PREFIX:
1329                         switch (src_type) {
1330                         case PW_TYPE_IPV4_ADDR:
1331                                 /* Add the v4/v6 mapping prefix */
1332                                 memcpy(&dst->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
1333                                 memcpy(&dst->ipv6prefix[2 + sizeof(v4_v6_map)], &src->ipaddr,
1334                                        (sizeof(dst->ipv6prefix) - 2) - sizeof(v4_v6_map));
1335                                 dst->ipv6prefix[0] = 0;
1336                                 dst->ipv6prefix[1] = 128;
1337                                 goto fixed_length;
1338
1339                         case PW_TYPE_IPV4_PREFIX:
1340                                 /* Add the v4/v6 mapping prefix */
1341                                 memcpy(&dst->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
1342                                 memcpy(&dst->ipv6prefix[2 + sizeof(v4_v6_map)], &src->ipv4prefix[2],
1343                                        (sizeof(dst->ipv6prefix) - 2) - sizeof(v4_v6_map));
1344                                 dst->ipv6prefix[0] = 0;
1345                                 dst->ipv6prefix[1] = (sizeof(v4_v6_map) * 8) + src->ipv4prefix[1];
1346                                 goto fixed_length;
1347
1348                         case PW_TYPE_IPV6_ADDR:
1349                                 memcpy(&dst->ipv6prefix[2], &src->ipv6addr, sizeof(dst->ipv6prefix) - 2);
1350                                 dst->ipv6prefix[0] = 0;
1351                                 dst->ipv6prefix[1] = 128;
1352                                 goto fixed_length;
1353
1354                         default:
1355                                 break;
1356                         }
1357
1358                         break;
1359
1360                 default:
1361                         break;
1362                 }
1363         }
1364
1365         /*
1366          *      The attribute we've found has to have a size which is
1367          *      compatible with the type of the destination cast.
1368          */
1369         if ((src_len < dict_attr_sizes[dst_type][0]) ||
1370             (src_len > dict_attr_sizes[dst_type][1])) {
1371                 char const *src_type_name;
1372
1373                 src_type_name =  fr_int2str(dict_attr_types, src_type, "<INVALID>");
1374                 fr_strerror_printf("Invalid cast from %s to %s. Length should be between %zu and %zu but is %zu",
1375                                    src_type_name,
1376                                    fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
1377                                    dict_attr_sizes[dst_type][0], dict_attr_sizes[dst_type][1],
1378                                    src_len);
1379                 return -1;
1380         }
1381
1382         if (src_type == PW_TYPE_OCTETS) {
1383         do_octets:
1384                 value_data_hton(dst, dst_type, src->octets, src_len);
1385                 return src_len;
1386         }
1387
1388         /*
1389          *      Convert host order to network byte order.
1390          */
1391         if ((dst_type == PW_TYPE_IPV4_ADDR) &&
1392             ((src_type == PW_TYPE_INTEGER) ||
1393              (src_type == PW_TYPE_DATE) ||
1394              (src_type == PW_TYPE_SIGNED))) {
1395                 dst->ipaddr.s_addr = htonl(src->integer);
1396
1397         } else if ((src_type == PW_TYPE_IPV4_ADDR) &&
1398                    ((dst_type == PW_TYPE_INTEGER) ||
1399                     (dst_type == PW_TYPE_DATE) ||
1400                     (dst_type == PW_TYPE_SIGNED))) {
1401                 dst->integer = htonl(src->ipaddr.s_addr);
1402
1403         } else {                /* they're of the same byte order */
1404                 memcpy(&dst, &src, src_len);
1405         }
1406
1407         return src_len;
1408 }
1409
1410 /** Copy value data verbatim duplicating any buffers
1411  *
1412  * @param ctx To allocate buffers in.
1413  * @param dst Where to copy value_data to.
1414  * @param src_type Type of src.
1415  * @param src Where to copy value_data from.
1416  * @param src_len Where
1417  */
1418 ssize_t value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE src_type,
1419                         const value_data_t *src, size_t src_len)
1420 {
1421         switch (src_type) {
1422         default:
1423                 memcpy(dst, src, sizeof(*src));
1424                 break;
1425
1426         case PW_TYPE_STRING:
1427                 dst->strvalue = talloc_bstrndup(ctx, src->strvalue, src_len);
1428                 if (!dst->strvalue) return -1;
1429                 break;
1430
1431         case PW_TYPE_OCTETS:
1432                 dst->octets = talloc_memdup(ctx, src->octets, src_len);
1433                 talloc_set_type(dst->strvalue, uint8_t);
1434                 if (!dst->octets) return -1;
1435                 break;
1436         }
1437
1438         return src_len;
1439 }
1440
1441
1442
1443 /** Print one attribute value to a string
1444  *
1445  */
1446 char *value_data_aprints(TALLOC_CTX *ctx,
1447                          PW_TYPE type, DICT_ATTR const *enumv, value_data_t const *data,
1448                          size_t inlen, char quote)
1449 {
1450         char *p = NULL;
1451         unsigned int i;
1452
1453         switch (type) {
1454         case PW_TYPE_STRING:
1455         {
1456                 size_t len, ret;
1457
1458                 if (!quote) {
1459                         p = talloc_bstrndup(ctx, data->strvalue, inlen);
1460                         if (!p) return NULL;
1461                         talloc_set_type(p, char);
1462                         return p;
1463                 }
1464
1465                 /* Gets us the size of the buffer we need to alloc */
1466                 len = fr_prints_len(data->strvalue, inlen, quote);
1467                 p = talloc_array(ctx, char, len);
1468                 if (!p) return NULL;
1469
1470                 ret = fr_prints(p, len, data->strvalue, inlen, quote);
1471                 if (!fr_assert(ret == (len - 1))) {
1472                         talloc_free(p);
1473                         return NULL;
1474                 }
1475                 break;
1476         }
1477
1478         case PW_TYPE_INTEGER:
1479                 i = data->integer;
1480                 goto print_int;
1481
1482         case PW_TYPE_SHORT:
1483                 i = data->ushort;
1484                 goto print_int;
1485
1486         case PW_TYPE_BYTE:
1487                 i = data->byte;
1488
1489         print_int:
1490         {
1491                 DICT_VALUE const *dv;
1492
1493                 if (enumv && (dv = dict_valbyattr(enumv->attr, enumv->vendor, i))) {
1494                         p = talloc_typed_strdup(ctx, dv->name);
1495                 } else {
1496                         p = talloc_typed_asprintf(ctx, "%u", i);
1497                 }
1498         }
1499                 break;
1500
1501         case PW_TYPE_SIGNED:
1502                 p = talloc_typed_asprintf(ctx, "%d", data->sinteger);
1503                 break;
1504
1505         case PW_TYPE_INTEGER64:
1506                 p = talloc_typed_asprintf(ctx, "%" PRIu64 , data->integer64);
1507                 break;
1508
1509         case PW_TYPE_ETHERNET:
1510                 p = talloc_typed_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
1511                                           data->ether[0], data->ether[1],
1512                                           data->ether[2], data->ether[3],
1513                                           data->ether[4], data->ether[5]);
1514                 break;
1515
1516         case PW_TYPE_ABINARY:
1517 #ifdef WITH_ASCEND_BINARY
1518                 p = talloc_array(ctx, char, 128);
1519                 if (!p) return NULL;
1520                 print_abinary(p, 128, (uint8_t const *) &data->filter, inlen, 0);
1521                 break;
1522 #else
1523                   /* FALL THROUGH */
1524 #endif
1525
1526         case PW_TYPE_OCTETS:
1527                 p = talloc_array(ctx, char, 2 + 1 + inlen * 2);
1528                 if (!p) return NULL;
1529                 p[0] = '0';
1530                 p[1] = 'x';
1531
1532                 fr_bin2hex(p + 2, data->octets, inlen);
1533                 p[2 + (inlen * 2)] = '\0';
1534                 break;
1535
1536         case PW_TYPE_DATE:
1537         {
1538                 time_t t;
1539                 struct tm s_tm;
1540
1541                 t = data->date;
1542
1543                 p = talloc_array(ctx, char, 64);
1544                 strftime(p, 64, "%b %e %Y %H:%M:%S %Z",
1545                          localtime_r(&t, &s_tm));
1546                 break;
1547         }
1548
1549         /*
1550          *      We need to use the proper inet_ntop functions for IP
1551          *      addresses, else the output might not match output of
1552          *      other functions, which makes testing difficult.
1553          *
1554          *      An example is tunnelled ipv4 in ipv6 addresses.
1555          */
1556         case PW_TYPE_IPV4_ADDR:
1557         case PW_TYPE_IPV4_PREFIX:
1558         {
1559                 char buff[INET_ADDRSTRLEN  + 4]; // + /prefix
1560
1561                 buff[0] = '\0';
1562                 value_data_prints(buff, sizeof(buff), type, enumv, data, inlen, '\0');
1563
1564                 p = talloc_typed_strdup(ctx, buff);
1565         }
1566         break;
1567
1568         case PW_TYPE_IPV6_ADDR:
1569         case PW_TYPE_IPV6_PREFIX:
1570         {
1571                 char buff[INET6_ADDRSTRLEN + 4]; // + /prefix
1572
1573                 buff[0] = '\0';
1574                 value_data_prints(buff, sizeof(buff), type, enumv, data, inlen, '\0');
1575
1576                 p = talloc_typed_strdup(ctx, buff);
1577         }
1578         break;
1579
1580         case PW_TYPE_IFID:
1581                 p = talloc_typed_asprintf(ctx, "%x:%x:%x:%x",
1582                                           (data->ifid[0] << 8) | data->ifid[1],
1583                                           (data->ifid[2] << 8) | data->ifid[3],
1584                                           (data->ifid[4] << 8) | data->ifid[5],
1585                                           (data->ifid[6] << 8) | data->ifid[7]);
1586                 break;
1587
1588         case PW_TYPE_BOOLEAN:
1589                 p = talloc_typed_strdup(ctx, data->byte ? "yes" : "no");
1590                 break;
1591
1592         /*
1593          *      Don't add default here
1594          */
1595         case PW_TYPE_INVALID:
1596         case PW_TYPE_COMBO_IP_ADDR:
1597         case PW_TYPE_COMBO_IP_PREFIX:
1598         case PW_TYPE_TLV:
1599         case PW_TYPE_EXTENDED:
1600         case PW_TYPE_LONG_EXTENDED:
1601         case PW_TYPE_EVS:
1602         case PW_TYPE_VSA:
1603         case PW_TYPE_TIMEVAL:
1604         case PW_TYPE_MAX:
1605                 fr_assert(0);
1606                 return NULL;
1607         }
1608
1609         return p;
1610 }
1611
1612
1613 /** Print the value of an attribute to a string
1614  *
1615  * @note return value should be checked with is_truncated.
1616  * @note Will always \0 terminate unless outlen == 0.
1617  *
1618  * @param out Where to write the printed version of the attribute value.
1619  * @param outlen Length of the output buffer.
1620  * @param type of data being printed.
1621  * @param enumv Enumerated string values for integer types.
1622  * @param data to print.
1623  * @param inlen Length of data.
1624  * @param quote char to escape in string output.
1625  * @return  the number of bytes written to the out buffer, or a number >= outlen if truncation has occurred.
1626  */
1627 size_t value_data_prints(char *out, size_t outlen,
1628                          PW_TYPE type, DICT_ATTR const *enumv, value_data_t const *data,
1629                          ssize_t inlen, char quote)
1630 {
1631         DICT_VALUE      *v;
1632         char            buf[1024];      /* Interim buffer to use with poorly behaved printing functions */
1633         char const      *a = NULL;
1634         char            *p = out;
1635         time_t          t;
1636         struct tm       s_tm;
1637         unsigned int    i;
1638
1639         size_t          len = 0, freespace = outlen;
1640
1641         if (!data) return 0;
1642         if (outlen == 0) return inlen;
1643
1644         *out = '\0';
1645
1646         p = out;
1647
1648         switch (type) {
1649         case PW_TYPE_STRING:
1650
1651                 /*
1652                  *      Ensure that WE add the quotation marks around the string.
1653                  */
1654                 if (quote) {
1655                         if (freespace < 3) return inlen + 2;
1656
1657                         *p++ = quote;
1658                         freespace--;
1659
1660                         len = fr_prints(p, freespace, data->strvalue, inlen, quote);
1661                         /* always terminate the quoted string with another quote */
1662                         if (len >= (freespace - 1)) {
1663                                 /* Use out not p as we're operating on the entire buffer */
1664                                 out[outlen - 2] = (char) quote;
1665                                 out[outlen - 1] = '\0';
1666                                 return len + 2;
1667                         }
1668                         p += len;
1669                         freespace -= len;
1670
1671                         *p++ = (char) quote;
1672                         freespace--;
1673                         *p = '\0';
1674
1675                         return len + 2;
1676                 }
1677
1678                 return fr_prints(out, outlen, data->strvalue, inlen, quote);
1679
1680         case PW_TYPE_INTEGER:
1681                 i = data->integer;
1682                 goto print_int;
1683
1684         case PW_TYPE_SHORT:
1685                 i = data->ushort;
1686                 goto print_int;
1687
1688         case PW_TYPE_BYTE:
1689                 i = data->byte;
1690
1691 print_int:
1692                 /* Normal, non-tagged attribute */
1693                 if (enumv && (v = dict_valbyattr(enumv->attr, enumv->vendor, i)) != NULL) {
1694                         a = v->name;
1695                         len = strlen(a);
1696                 } else {
1697                         /* should never be truncated */
1698                         len = snprintf(buf, sizeof(buf), "%u", i);
1699                         a = buf;
1700                 }
1701                 break;
1702
1703         case PW_TYPE_INTEGER64:
1704                 return snprintf(out, outlen, "%" PRIu64, data->integer64);
1705
1706         case PW_TYPE_DATE:
1707                 t = data->date;
1708                 if (quote > 0) {
1709                         len = strftime(buf, sizeof(buf) - 1, "%%%b %e %Y %H:%M:%S %Z%%", localtime_r(&t, &s_tm));
1710                         buf[0] = (char) quote;
1711                         buf[len - 1] = (char) quote;
1712                         buf[len] = '\0';
1713                 } else {
1714                         len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z", localtime_r(&t, &s_tm));
1715                 }
1716                 a = buf;
1717                 break;
1718
1719         case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
1720                 len = snprintf(buf, sizeof(buf), "%d", data->sinteger);
1721                 a = buf;
1722                 break;
1723
1724         case PW_TYPE_IPV4_ADDR:
1725                 a = inet_ntop(AF_INET, &(data->ipaddr), buf, sizeof(buf));
1726                 len = strlen(buf);
1727                 break;
1728
1729         case PW_TYPE_ABINARY:
1730 #ifdef WITH_ASCEND_BINARY
1731                 print_abinary(buf, sizeof(buf), (uint8_t const *) data->filter, inlen, quote);
1732                 a = buf;
1733                 len = strlen(buf);
1734                 break;
1735 #else
1736         /* FALL THROUGH */
1737 #endif
1738         case PW_TYPE_OCTETS:
1739         case PW_TYPE_TLV:
1740         {
1741                 size_t binlen;
1742                 size_t hexlen;
1743
1744                 binlen = inlen;
1745                 hexlen = (binlen * 2) + 2; /* NOT accounting for trailing NUL */
1746
1747                 /*
1748                  *      If the buffer is too small, put something into
1749                  *      it, and return how much we should have written
1750                  *
1751                  *      0 + x + H + H + NUL = 5
1752                  */
1753                 if (freespace < 5) {
1754                         switch (freespace) {
1755                         case '4':
1756                         case '3':
1757                                 out[0] = '0';
1758                                 out[1] = 'x';
1759                                 out[2] = '\0';
1760                                 return hexlen;
1761
1762                         case 2:
1763                                 *out = '0';
1764                                 out++;
1765                                 /* FALL-THROUGH */
1766
1767                         case 1:
1768                                 *out = '\0';
1769                                 break;
1770
1771                         case 0:
1772                                 break;
1773                         }
1774
1775                         return hexlen;
1776                 }
1777
1778                 /*
1779                  *      The output buffer is at least 5 bytes, we haev
1780                  *      room for '0xHH' plus a trailing NUL byte.
1781                  */
1782                 out[0] = '0';
1783                 out[1] = 'x';
1784
1785                 /*
1786                  *      Get maximum number of bytes we can encode
1787                  *      given freespace, ensuring we account for '0',
1788                  *      'x', and the trailing NUL in the buffer.
1789                  *
1790                  *      Note that we can't have "freespace = 0" after
1791                  *      this, as 'freespace' has to be at least 5.
1792                  */
1793                 freespace -= 3;
1794                 freespace /= 2;
1795                 if (binlen > freespace) {
1796                         binlen = freespace;
1797                 }
1798
1799                 fr_bin2hex(out + 2, data->octets, binlen);
1800                 return hexlen;
1801         }
1802
1803         case PW_TYPE_IFID:
1804                 a = ifid_ntoa(buf, sizeof(buf), data->ifid);
1805                 len = strlen(buf);
1806                 break;
1807
1808         case PW_TYPE_IPV6_ADDR:
1809                 a = inet_ntop(AF_INET6, &data->ipv6addr, buf, sizeof(buf));
1810                 len = strlen(buf);
1811                 break;
1812
1813         case PW_TYPE_IPV6_PREFIX:
1814         {
1815                 struct in6_addr addr;
1816
1817                 /*
1818                  *      Alignment issues.
1819                  */
1820                 memcpy(&addr, &(data->ipv6prefix[2]), sizeof(addr));
1821
1822                 a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
1823                 if (a) {
1824                         p = buf;
1825
1826                         len = strlen(buf);
1827                         p += len;
1828                         len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) data->ipv6prefix[1]);
1829                 }
1830         }
1831                 break;
1832
1833         case PW_TYPE_IPV4_PREFIX:
1834         {
1835                 struct in_addr addr;
1836
1837                 /*
1838                  *      Alignment issues.
1839                  */
1840                 memcpy(&addr, &(data->ipv4prefix[2]), sizeof(addr));
1841
1842                 a = inet_ntop(AF_INET, &addr, buf, sizeof(buf));
1843                 if (a) {
1844                         p = buf;
1845
1846                         len = strlen(buf);
1847                         p += len;
1848                         len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) (data->ipv4prefix[1] & 0x3f));
1849                 }
1850         }
1851                 break;
1852
1853         case PW_TYPE_ETHERNET:
1854                 return snprintf(out, outlen, "%02x:%02x:%02x:%02x:%02x:%02x",
1855                                 data->ether[0], data->ether[1],
1856                                 data->ether[2], data->ether[3],
1857                                 data->ether[4], data->ether[5]);
1858
1859         /*
1860          *      Don't add default here
1861          */
1862         case PW_TYPE_INVALID:
1863         case PW_TYPE_COMBO_IP_ADDR:
1864         case PW_TYPE_COMBO_IP_PREFIX:
1865         case PW_TYPE_EXTENDED:
1866         case PW_TYPE_LONG_EXTENDED:
1867         case PW_TYPE_EVS:
1868         case PW_TYPE_VSA:
1869         case PW_TYPE_TIMEVAL:
1870         case PW_TYPE_BOOLEAN:
1871         case PW_TYPE_MAX:
1872                 fr_assert(0);
1873                 *out = '\0';
1874                 return 0;
1875         }
1876
1877         if (a) strlcpy(out, a, outlen);
1878
1879         return len;     /* Return the number of bytes we would of written (for truncation detection) */
1880 }
1881