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