Formatting
[freeradius.git] / src / lib / value.c
1 /*
2  * valuepair.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                 break;
322
323         case PW_TYPE_IPV4_PREFIX:               /* IPv4 and IPv4 Prefix */
324                 switch (b_type) {
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);
329
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);
334
335                 default:
336                         fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
337                         return -1;
338                 }
339                 break;
340
341         case PW_TYPE_IPV6_ADDR:
342                 switch (b_type) {
343                 case PW_TYPE_IPV6_ADDR:         /* IPv6 and IPv6 */
344                         goto cmp;
345
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);
349                         break;
350
351                 default:
352                         fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
353                         return -1;
354                 }
355                 break;
356
357         case PW_TYPE_IPV6_PREFIX:
358                 switch (b_type) {
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);
363
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);
368
369                 default:
370                         fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
371                         return -1;
372                 }
373                 break;
374
375         default:
376         cmp:
377                 compare = value_data_cmp(a_type, a, a_len,
378                                          b_type, b, b_len);
379                 if (compare < -1) {     /* comparison error */
380                         return -1;
381                 }
382         }
383
384         /*
385          *      Now do the operator comparison.
386          */
387         switch (op) {
388         case T_OP_CMP_EQ:
389                 return (compare == 0);
390
391         case T_OP_NE:
392                 return (compare != 0);
393
394         case T_OP_LT:
395                 return (compare < 0);
396
397         case T_OP_GT:
398                 return (compare > 0);
399
400         case T_OP_LE:
401                 return (compare <= 0);
402
403         case T_OP_GE:
404                 return (compare >= 0);
405
406         default:
407                 return 0;
408         }
409 }
410
411 static char const hextab[] = "0123456789abcdef";
412
413 /** Convert string value to a value_data_t type
414  *
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  * @return length of data written to out or -1 on parse error.
423  */
424 ssize_t value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst,
425                             PW_TYPE *src_type, DICT_ATTR const *src_enumv,
426                             char const *src, ssize_t src_len)
427 {
428         DICT_VALUE      *dval;
429         size_t          len;
430         ssize_t         ret;
431         char            buffer[256];
432
433         if (!src) return -1;
434
435         len = (src_len < 0) ? strlen(src) : (size_t)src_len;
436
437         /*
438          *      Set size for all fixed length attributes.
439          */
440         ret = dict_attr_sizes[*src_type][1];    /* Max length */
441
442         /*
443          *      It's a variable ret src_type so we just alloc a new buffer
444          *      of size len and copy.
445          */
446         switch (*src_type) {
447         case PW_TYPE_STRING:
448         {
449                 size_t          p_len;
450                 char const      *cp;
451                 char            *p;
452                 int             x;
453
454                 /*
455                  *      Do escaping here
456                  */
457                 dst->strvalue = p = talloc_memdup(ctx, src, len + 1);
458                 p[len] = '\0';
459                 talloc_set_type(p, char);
460
461                 cp = src;
462                 p_len = 0;
463                 while (*cp) {
464                         char c = *cp++;
465
466                         if (c == '\\') switch (*cp) {
467                         case 'r':
468                                 c = '\r';
469                                 cp++;
470                                 break;
471                         case 'n':
472                                 c = '\n';
473                                 cp++;
474                                 break;
475                         case 't':
476                                 c = '\t';
477                                 cp++;
478                                 break;
479                         case '"':
480                                 c = '"';
481                                 cp++;
482                                 break;
483                         case '\'':
484                                 c = '\'';
485                                 cp++;
486                                 break;
487                         case '\\':
488                                 c = '\\';
489                                 cp++;
490                                 break;
491                         case '`':
492                                 c = '`';
493                                 cp++;
494                                 break;
495                         case '\0':
496                                 c = '\\'; /* no cp++ */
497                                 break;
498                         default:
499                                 if ((cp[0] >= '0') &&
500                                     (cp[0] <= '9') &&
501                                     (cp[1] >= '0') &&
502                                     (cp[1] <= '9') &&
503                                     (cp[2] >= '0') &&
504                                     (cp[2] <= '9') &&
505                                     (sscanf(cp, "%3o", &x) == 1)) {
506                                         c = x;
507                                         cp += 3;
508
509                                 } else if (cp[0]) {
510                                         /*
511                                          *      \p --> p
512                                          */
513                                         c = *cp++;
514                                 } /* else at EOL \ --> \ */
515                         }
516                         *p++ = c;
517                         p_len++;
518                 }
519                 *p = '\0';
520                 ret = p_len;
521         }
522                 goto finish;
523
524         /* raw octets: 0x01020304... */
525         case PW_TYPE_VSA:
526                 if (strcmp(src, "ANY") == 0) {
527                         ret = 0;
528                         goto finish;
529                 } /* else it's hex */
530
531         case PW_TYPE_OCTETS:
532         {
533                 uint8_t *p;
534
535                 /*
536                  *      No 0x prefix, just copy verbatim.
537                  */
538                 if ((len < 2) || (strncasecmp(src, "0x", 2) != 0)) {
539                         dst->octets = talloc_memdup(ctx, (uint8_t const *)src, len);
540                         talloc_set_type(dst->octets, uint8_t);
541                         ret = len;
542                         goto finish;
543                 }
544
545
546         do_octets:
547                 len -= 2;
548
549                 /*
550                  *      Invalid.
551                  */
552                 if ((len & 0x01) != 0) {
553                         fr_strerror_printf("Length of Hex String is not even, got %zu bytes", ret);
554                         return -1;
555                 }
556
557                 ret = len >> 1;
558                 p = talloc_array(ctx, uint8_t, ret);
559                 if (fr_hex2bin(p, ret, src + 2, len) != (size_t)ret) {
560                         talloc_free(p);
561                         fr_strerror_printf("Invalid hex data");
562                         return -1;
563                 }
564
565                 dst->octets = p;
566         }
567                 goto finish;
568
569         case PW_TYPE_ABINARY:
570 #ifdef WITH_ASCEND_BINARY
571                 if ((len > 1) && (strncasecmp(src, "0x", 2) == 0)) goto do_octets;
572
573                 if (ascend_parse_filter(dst, src, len) < 0 ) {
574                         /* Allow ascend_parse_filter's strerror to bubble up */
575                         return -1;
576                 }
577                 ret = sizeof(dst->filter);
578                 goto finish;
579 #else
580                 /*
581                  *      If Ascend binary is NOT defined,
582                  *      then fall through to raw octets, so that
583                  *      the user can at least make them by hand...
584                  */
585                 goto do_octets;
586 #endif
587
588         /* don't use this! */
589         case PW_TYPE_TLV:
590         {
591                 uint8_t *p;
592
593                 if ((len < 2) || (len & 0x01) || (strncasecmp(src, "0x", 2) != 0)) {
594                         fr_strerror_printf("Invalid TLV specification");
595                         return -1;
596                 }
597                 len -= 2;
598
599                 ret = len >> 1;
600                 p = talloc_array(ctx, uint8_t, ret);
601                 if (!p) {
602                         fr_strerror_printf("No memory");
603                         return -1;
604                 }
605                 if (fr_hex2bin(p, ret, src + 2, len) != (size_t)ret) {
606                         fr_strerror_printf("Invalid hex data in TLV");
607                         return -1;
608                 }
609
610                 dst->tlv = p;
611         }
612                 goto finish;
613
614         case PW_TYPE_IPV4_ADDR:
615         {
616                 fr_ipaddr_t addr;
617
618                 if (fr_pton4(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
619
620                 /*
621                  *      We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
622                  *      print them this way.
623                  */
624                 if (addr.prefix != 32) {
625                         fr_strerror_printf("Invalid IPv4 mask length \"/%i\".  Only \"/32\" permitted "
626                                            "for non-prefix types", addr.prefix);
627                         return -1;
628                 }
629
630                 dst->ipaddr.s_addr = addr.ipaddr.ip4addr.s_addr;
631         }
632                 goto finish;
633
634         case PW_TYPE_IPV4_PREFIX:
635         {
636                 fr_ipaddr_t addr;
637
638                 if (fr_pton4(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
639
640                 dst->ipv4prefix[1] = addr.prefix;
641                 memcpy(dst->ipv4prefix + 2, &addr.ipaddr.ip4addr.s_addr, sizeof(dst->ipv4prefix) - 2);
642         }
643                 goto finish;
644
645         case PW_TYPE_IPV6_ADDR:
646         {
647                 fr_ipaddr_t addr;
648
649                 if (fr_pton6(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
650
651                 /*
652                  *      We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
653                  *      print them this way.
654                  */
655                 if (addr.prefix != 128) {
656                         fr_strerror_printf("Invalid IPv6 mask length \"/%i\".  Only \"/128\" permitted "
657                                            "for non-prefix types", addr.prefix);
658                         return -1;
659                 }
660
661                 memcpy(&dst->ipv6addr, &addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6addr));
662         }
663                 goto finish;
664
665         case PW_TYPE_IPV6_PREFIX:
666         {
667                 fr_ipaddr_t addr;
668
669                 if (fr_pton6(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
670
671                 dst->ipv6prefix[1] = addr.prefix;
672                 memcpy(dst->ipv6prefix + 2, &addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6prefix) - 2);
673         }
674                 goto finish;
675
676         default:
677                 break;
678         }
679
680         /*
681          *      It's a fixed size src_type, copy to a temporary buffer and
682          *      \0 terminate if insize >= 0.
683          */
684         if (src_len > 0) {
685                 if (len >= sizeof(buffer)) {
686                         fr_strerror_printf("Temporary buffer too small");
687                         return -1;
688                 }
689
690                 memcpy(buffer, src, src_len);
691                 buffer[src_len] = '\0';
692                 src = buffer;
693         }
694
695         switch (*src_type) {
696         case PW_TYPE_BYTE:
697         {
698                 char *p;
699                 unsigned int i;
700
701                 /*
702                  *      Note that ALL integers are unsigned!
703                  */
704                 i = fr_strtoul(src, &p);
705
706                 /*
707                  *      Look for the named src for the given
708                  *      attribute.
709                  */
710                 if (src_enumv && *p && !is_whitespace(p)) {
711                         if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
712                                 fr_strerror_printf("Unknown value \"%s\" for attribute '%s'", src, src_enumv->name);
713                                 return -1;
714                         }
715
716                         dst->byte = dval->value;
717                 } else {
718                         if (i > 255) {
719                                 fr_strerror_printf("Byte value \"%s\" is larger than 255", src);
720                                 return -1;
721                         }
722
723                         dst->byte = i;
724                 }
725                 break;
726         }
727
728         case PW_TYPE_SHORT:
729         {
730                 char *p;
731                 unsigned int i;
732
733                 /*
734                  *      Note that ALL integers are unsigned!
735                  */
736                 i = fr_strtoul(src, &p);
737
738                 /*
739                  *      Look for the named src for the given
740                  *      attribute.
741                  */
742                 if (src_enumv && *p && !is_whitespace(p)) {
743                         if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
744                                 fr_strerror_printf("Unknown value \"%s\" for attribute '%s'", src, src_enumv->name);
745                                 return -1;
746                         }
747
748                         dst->ushort = dval->value;
749                 } else {
750                         if (i > 65535) {
751                                 fr_strerror_printf("Short value \"%s\" is larger than 65535", src);
752                                 return -1;
753                         }
754
755                         dst->ushort = i;
756                 }
757                 break;
758         }
759
760         case PW_TYPE_INTEGER:
761         {
762                 char *p;
763                 unsigned int i;
764
765                 /*
766                  *      Note that ALL integers are unsigned!
767                  */
768                 i = fr_strtoul(src, &p);
769
770                 /*
771                  *      Look for the named src for the given
772                  *      attribute.
773                  */
774                 if (src_enumv && *p && !is_whitespace(p)) {
775                         if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
776                                 fr_strerror_printf("Unknown value \"%s\" for attribute \"%s\"", src, src_enumv->name);
777                                 return -1;
778                         }
779
780                         dst->integer = dval->value;
781                 } else {
782                         /*
783                          *      Value is always within the limits
784                          */
785                         dst->integer = i;
786                 }
787         }
788                 break;
789
790         case PW_TYPE_INTEGER64:
791         {
792                 uint64_t i;
793
794                 /*
795                  *      Note that ALL integers are unsigned!
796                  */
797                 if (sscanf(src, "%" PRIu64, &i) != 1) {
798                         fr_strerror_printf("Failed parsing \"%s\" as unsigned 64bit integer", src);
799                         return -1;
800                 }
801                 dst->integer64 = i;
802         }
803                 break;
804
805         case PW_TYPE_DATE:
806         {
807                 /*
808                  *      time_t may be 64 bits, whule vp_date MUST be 32-bits.  We need an
809                  *      intermediary variable to handle the conversions.
810                  */
811                 time_t date;
812
813                 if (fr_get_time(src, &date) < 0) {
814                         fr_strerror_printf("failed to parse time string \"%s\"", src);
815                         return -1;
816                 }
817
818                 dst->date = date;
819         }
820
821                 break;
822
823         case PW_TYPE_IFID:
824                 if (ifid_aton(src, (void *) &dst->ifid) == NULL) {
825                         fr_strerror_printf("Failed to parse interface-id string \"%s\"", src);
826                         return -1;
827                 }
828                 break;
829
830         case PW_TYPE_ETHERNET:
831         {
832                 char const *c1, *c2, *cp;
833                 size_t p_len = 0;
834
835                 /*
836                  *      Convert things which are obviously integers to Ethernet addresses
837                  *
838                  *      We assume the number is the bigendian representation of the
839                  *      ethernet address.
840                  */
841                 if (is_integer(src)) {
842                         uint64_t integer = htonll(atoll(src));
843
844                         memcpy(&dst->ether, &integer, sizeof(dst->ether));
845                         break;
846                 }
847
848                 cp = src;
849                 while (*cp) {
850                         if (cp[1] == ':') {
851                                 c1 = hextab;
852                                 c2 = memchr(hextab, tolower((int) cp[0]), 16);
853                                 cp += 2;
854                         } else if ((cp[1] != '\0') && ((cp[2] == ':') || (cp[2] == '\0'))) {
855                                 c1 = memchr(hextab, tolower((int) cp[0]), 16);
856                                 c2 = memchr(hextab, tolower((int) cp[1]), 16);
857                                 cp += 2;
858                                 if (*cp == ':') cp++;
859                         } else {
860                                 c1 = c2 = NULL;
861                         }
862                         if (!c1 || !c2 || (p_len >= sizeof(dst->ether))) {
863                                 fr_strerror_printf("failed to parse Ethernet address \"%s\"", src);
864                                 return -1;
865                         }
866                         dst->ether[p_len] = ((c1-hextab)<<4) + (c2-hextab);
867                         p_len++;
868                 }
869         }
870                 break;
871
872         /*
873          *      Crazy polymorphic (IPv4/IPv6) attribute src_type for WiMAX.
874          *
875          *      We try and make is saner by replacing the original
876          *      da, with either an IPv4 or IPv6 da src_type.
877          *
878          *      These are not dynamic da, and will have the same vendor
879          *      and attribute as the original.
880          */
881         case PW_TYPE_COMBO_IP_ADDR:
882         {
883                 if (inet_pton(AF_INET6, src, &dst->ipv6addr) > 0) {
884                         *src_type = PW_TYPE_IPV6_ADDR;
885                         ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][1]; /* size of IPv6 address */
886                 } else {
887                         fr_ipaddr_t ipaddr;
888
889                         if (ip_hton(&ipaddr, AF_INET, src, false) < 0) {
890                                 fr_strerror_printf("Failed to find IPv4 address for %s", src);
891                                 return -1;
892                         }
893
894                         *src_type = PW_TYPE_IPV4_ADDR;
895                         dst->ipaddr.s_addr = ipaddr.ipaddr.ip4addr.s_addr;
896                         ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][0]; /* size of IPv4 address */
897                 }
898         }
899                 break;
900
901         case PW_TYPE_SIGNED:
902                 /* Damned code for 1 WiMAX attribute */
903                 dst->sinteger = (int32_t)strtol(src, NULL, 10);
904                 break;
905
906                 /*
907                  *  Anything else.
908                  */
909         default:
910                 fr_strerror_printf("Unknown attribute type %d", *src_type);
911                 return -1;
912         }
913
914 finish:
915         return ret;
916 }
917
918 /** Performs byte order reversal for types that need it
919  *
920  */
921 static void value_data_hton(value_data_t *dst, PW_TYPE type, void const *src, size_t src_len)
922 {
923         /* 8 byte integers */
924         switch (type) {
925         case PW_TYPE_INTEGER64:
926                 dst->integer64 = htonll(*(uint64_t const *)src);
927                 break;
928
929         /* 4 byte integers */
930         case PW_TYPE_INTEGER:
931         case PW_TYPE_DATE:
932         case PW_TYPE_SIGNED:
933                 dst->integer = htonl(*(uint32_t const *)src);
934                 break;
935
936         /* 2 byte integers */
937         case PW_TYPE_SHORT:
938                 dst->ushort = htons(*(uint16_t const *)src);
939                 break;
940
941         case PW_TYPE_OCTETS:
942         case PW_TYPE_STRING:
943                 fr_assert(0);
944
945         default:
946                 memcpy(dst, src, src_len);
947         }
948 }
949
950 /** Convert one type of value_data_t to another
951  *
952  * @note This should be the canonical function used to convert between data types.
953  *
954  * @param ctx to allocate buffers in (usually the same as dst)
955  * @param dst Where to write result of casting.
956  * @param dst_type to cast to.
957  * @param dst_enumv Enumerated values used to converts strings to integers.
958  * @param src_type to cast from.
959  * @param src_enumv Enumerated values used to convert integers to strings.
960  * @param src Input data.
961  * @param src_len Input data len.
962  * @return the length of data in the dst.
963  */
964 ssize_t value_data_cast(TALLOC_CTX *ctx, value_data_t *dst,
965                         PW_TYPE dst_type, DICT_ATTR const *dst_enumv,
966                         PW_TYPE src_type, DICT_ATTR const *src_enumv,
967                         value_data_t const *src, size_t src_len)
968 {
969         if (!fr_assert(dst_type != src_type)) return -1;
970
971         /*
972          *      Converts the src data to octets with no processing.
973          */
974         if (dst_type == PW_TYPE_OCTETS) {
975                 if (src_type == PW_TYPE_STRING) {
976                         dst->octets = talloc_memdup(ctx, src->strvalue, src_len);
977                 } else {
978                         value_data_hton(dst, src_type, src, src_len);
979                         dst->octets = talloc_memdup(ctx, dst, src_len);
980                 }
981                 talloc_set_type(dst->octets, uint8_t);
982                 return talloc_array_length(dst->strvalue);
983         }
984
985         /*
986          *      Serialise a value_data_t
987          */
988         if (dst_type == PW_TYPE_STRING) {
989                 dst->strvalue = vp_data_aprints_value(ctx, src_type, src_enumv, src, src_len, '\0');
990                 return talloc_array_length(dst->strvalue) - 1;
991         }
992
993         /*
994          *      Deserialise a value_data_t
995          */
996         if (src_type == PW_TYPE_STRING) {
997                 return value_data_from_str(ctx, dst, &dst_type, dst_enumv, src->strvalue, src_len);
998         }
999
1000         if ((src_type == PW_TYPE_IFID) &&
1001             (dst_type == PW_TYPE_INTEGER64)) {
1002                 memcpy(&dst->integer64, &src->ifid, sizeof(src->ifid));
1003                 dst->integer64 = htonll(dst->integer64);
1004         fixed_length:
1005                 return dict_attr_sizes[dst_type][0];
1006         }
1007
1008         if ((src_type == PW_TYPE_INTEGER64) &&
1009             (dst_type == PW_TYPE_ETHERNET)) {
1010                 uint8_t array[8];
1011                 uint64_t i;
1012
1013                 i = htonll(src->integer64);
1014                 memcpy(array, &i, 8);
1015
1016                 /*
1017                  *      For OUIs in the DB.
1018                  */
1019                 if ((array[0] != 0) || (array[1] != 0)) return -1;
1020
1021                 memcpy(&dst->ether, &array[2], 6);
1022                 goto fixed_length;
1023         }
1024
1025         /*
1026          *      For integers, we allow the casting of a SMALL type to
1027          *      a larger type, but not vice-versa.
1028          */
1029         if (dst_type == PW_TYPE_INTEGER64) {
1030                 switch (src_type) {
1031                 case PW_TYPE_BYTE:
1032                         dst->integer64 = src->byte;
1033                         break;
1034
1035                 case PW_TYPE_SHORT:
1036                         dst->integer64 = src->ushort;
1037                         break;
1038
1039                 case PW_TYPE_INTEGER:
1040                         dst->integer64 = src->integer;
1041                         break;
1042
1043                 case PW_TYPE_OCTETS:
1044                         goto do_octets;
1045
1046                 default:
1047                 invalid_cast:
1048                         fr_strerror_printf("Invalid cast from %s to %s",
1049                                            fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1050                                            fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1051                         return -1;
1052
1053                 }
1054                 goto fixed_length;
1055         }
1056
1057         /*
1058          *      We can cast LONG integers to SHORTER ones, so long
1059          *      as the long one is on the LHS.
1060          */
1061         if (dst_type == PW_TYPE_INTEGER) {
1062                 switch (src_type) {
1063                 case PW_TYPE_BYTE:
1064                         dst->integer = src->byte;
1065                         break;
1066
1067                 case PW_TYPE_SHORT:
1068                         dst->integer = src->ushort;
1069                         break;
1070
1071                 case PW_TYPE_OCTETS:
1072                         goto do_octets;
1073
1074                 default:
1075                         goto invalid_cast;
1076                 }
1077                 goto fixed_length;
1078         }
1079
1080         if (dst_type == PW_TYPE_SHORT) {
1081                 switch (src_type) {
1082                 case PW_TYPE_BYTE:
1083                         dst->ushort = src->byte;
1084                         break;
1085
1086                 case PW_TYPE_OCTETS:
1087                         goto do_octets;
1088
1089                 default:
1090                         goto invalid_cast;
1091                 }
1092                 goto fixed_length;
1093         }
1094
1095         /*
1096          *      The attribute we've found has to have a size which is
1097          *      compatible with the type of the destination cast.
1098          */
1099         if ((src_len < dict_attr_sizes[dst_type][0]) ||
1100             (src_len > dict_attr_sizes[dst_type][1])) {
1101                 char const *src_type_name;
1102
1103                 src_type_name =  fr_int2str(dict_attr_types, src_type, "<INVALID>");
1104                 fr_strerror_printf("Invalid cast from %s to %s. Length should be between %zu and %zu but is %zu",
1105                                    src_type_name,
1106                                    fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
1107                                    dict_attr_sizes[dst_type][0], dict_attr_sizes[dst_type][1],
1108                                    src_len);
1109                 return -1;
1110         }
1111
1112         if (src_type == PW_TYPE_OCTETS) {
1113         do_octets:
1114                 value_data_hton(dst, dst_type, src->octets, src_len);
1115                 return src_len;
1116         }
1117
1118         /*
1119          *      Convert host order to network byte order.
1120          */
1121         if ((dst_type == PW_TYPE_IPV4_ADDR) &&
1122             ((src_type == PW_TYPE_INTEGER) ||
1123              (src_type == PW_TYPE_DATE) ||
1124              (src_type == PW_TYPE_SIGNED))) {
1125                 dst->ipaddr.s_addr = htonl(src->integer);
1126
1127         } else if ((src_type == PW_TYPE_IPV4_ADDR) &&
1128                    ((dst_type == PW_TYPE_INTEGER) ||
1129                     (dst_type == PW_TYPE_DATE) ||
1130                     (dst_type == PW_TYPE_SIGNED))) {
1131                 dst->integer = htonl(src->ipaddr.s_addr);
1132
1133         } else {                /* they're of the same byte order */
1134                 memcpy(&dst, &src, src_len);
1135         }
1136
1137         return src_len;
1138 }
1139
1140