1 /*
2 * value.c Functions to handle value_data_t
3 *
4 * Version: $Id: 05d42e269a476576bdce1501894e0e4a6d67dae8 $
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: 05d42e269a476576bdce1501894e0e4a6d67dae8 $")
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 */
value_data_cmp(PW_TYPE a_type,value_data_t const * a,size_t a_len,PW_TYPE b_type,value_data_t const * b,size_t b_len)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 */
value_data_cidr_cmp_op(FR_TOKEN op,int bytes,uint8_t a_net,uint8_t const * a,uint8_t b_net,uint8_t const * b)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 */
value_data_cmp_op(FR_TOKEN op,PW_TYPE a_type,value_data_t const * a,size_t a_len,PW_TYPE b_type,value_data_t const * b,size_t b_len)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 */
value_data_from_str(TALLOC_CTX * ctx,value_data_t * dst,PW_TYPE * src_type,DICT_ATTR const * src_enumv,char const * src,ssize_t src_len,char quote)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 struct tm tm = { 0 };
867 char *end;
868
869 /*
870 * Try to parse dates via locale-specific names,
871 * using the same format string as strftime(),
872 * below.
873 *
874 * If that fails (e.g. unix dates as integer),
875 * then we fall back to our parsing routine,
876 * which is much more forgiving.
877 */
878 end = strptime(src, "%b %e %Y %H:%M:%S %Z", &tm);
879 if (end && (*end == '\0')) {
880 date = mktime(&tm);
881
882 } else if (fr_get_time(src, &date) < 0) {
883 fr_strerror_printf("failed to parse time string \"%s\"", src);
884 return -1;
885 }
886
887 dst->date = date;
888 }
889
890 break;
891
892 case PW_TYPE_IFID:
893 if (ifid_aton(src, (void *) dst->ifid) == NULL) {
894 fr_strerror_printf("Failed to parse interface-id string \"%s\"", src);
895 return -1;
896 }
897 break;
898
899 case PW_TYPE_ETHERNET:
900 {
901 char const *c1, *c2, *cp;
902 size_t p_len = 0;
903
904 /*
905 * Convert things which are obviously integers to Ethernet addresses
906 *
907 * We assume the number is the bigendian representation of the
908 * ethernet address.
909 */
910 if (is_integer(src)) {
911 uint64_t integer = htonll(atoll(src));
912
913 memcpy(dst->ether, &integer, sizeof(dst->ether));
914 break;
915 }
916
917 cp = src;
918 while (*cp) {
919 if (cp[1] == ':') {
920 c1 = hextab;
921 c2 = memchr(hextab, tolower((int) cp[0]), 16);
922 cp += 2;
923 } else if ((cp[1] != '\0') && ((cp[2] == ':') || (cp[2] == '\0'))) {
924 c1 = memchr(hextab, tolower((int) cp[0]), 16);
925 c2 = memchr(hextab, tolower((int) cp[1]), 16);
926 cp += 2;
927 if (*cp == ':') cp++;
928 } else {
929 c1 = c2 = NULL;
930 }
931 if (!c1 || !c2 || (p_len >= sizeof(dst->ether))) {
932 fr_strerror_printf("failed to parse Ethernet address \"%s\"", src);
933 return -1;
934 }
935 dst->ether[p_len] = ((c1-hextab)<<4) + (c2-hextab);
936 p_len++;
937 }
938 }
939 break;
940
941 /*
942 * Crazy polymorphic (IPv4/IPv6) attribute src_type for WiMAX.
943 *
944 * We try and make is saner by replacing the original
945 * da, with either an IPv4 or IPv6 da src_type.
946 *
947 * These are not dynamic da, and will have the same vendor
948 * and attribute as the original.
949 */
950 case PW_TYPE_COMBO_IP_ADDR:
951 {
952 if (inet_pton(AF_INET6, src, &dst->ipv6addr) > 0) {
953 *src_type = PW_TYPE_IPV6_ADDR;
954 ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][1]; /* size of IPv6 address */
955 } else {
956 fr_ipaddr_t ipaddr;
957
958 if (ip_hton(&ipaddr, AF_INET, src, false) < 0) {
959 fr_strerror_printf("Failed to find IPv4 address for %s", src);
960 return -1;
961 }
962
963 *src_type = PW_TYPE_IPV4_ADDR;
964 dst->ipaddr.s_addr = ipaddr.ipaddr.ip4addr.s_addr;
965 ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][0]; /* size of IPv4 address */
966 }
967 }
968 break;
969
970 case PW_TYPE_SIGNED:
971 /* Damned code for 1 WiMAX attribute */
972 dst->sinteger = (int32_t)strtol(src, NULL, 10);
973 break;
974
975 /*
976 * Anything else.
977 */
978 default:
979 fr_strerror_printf("Unknown attribute type %d", *src_type);
980 return -1;
981 }
982
983 finish:
984 return ret;
985 }
986
987 /** Performs byte order reversal for types that need it
988 *
989 */
value_data_hton(value_data_t * dst,PW_TYPE dst_type,void const * src,size_t src_len)990 static ssize_t value_data_hton(value_data_t *dst, PW_TYPE dst_type, void const *src, size_t src_len)
991 {
992 size_t dst_len;
993 uint8_t *dst_ptr;
994
995 /* 8 byte integers */
996 switch (dst_type) {
997 case PW_TYPE_INTEGER64:
998 dst_len = sizeof(dst->integer64);
999
1000 if (src_len < dst_len) {
1001 too_small:
1002 fr_strerror_printf("Source is too small to cast to destination type");
1003 return -1;
1004 }
1005
1006 dst->integer64 = htonll(*(uint64_t const *)src);
1007 break;
1008
1009 /* 4 byte integers */
1010 case PW_TYPE_INTEGER:
1011 case PW_TYPE_DATE:
1012 case PW_TYPE_SIGNED:
1013 dst_len = sizeof(dst->integer);
1014
1015 if (src_len < dst_len) goto too_small;
1016
1017 dst->integer = htonl(*(uint32_t const *)src);
1018 break;
1019
1020 /* 2 byte integers */
1021 case PW_TYPE_SHORT:
1022 dst_len = sizeof(dst->ushort);
1023
1024 if (src_len < dst_len) goto too_small;
1025
1026 dst->ushort = htons(*(uint16_t const *)src);
1027 break;
1028
1029 /* 1 byte integer */
1030 case PW_TYPE_BYTE:
1031 dst_len = sizeof(dst->byte);
1032
1033 if (src_len < dst_len) goto too_small;
1034
1035 dst->byte = *(uint8_t const *)src;
1036 break;
1037
1038 case PW_TYPE_IPV4_ADDR:
1039 dst_len = 4;
1040 dst_ptr = (uint8_t *) &dst->ipaddr.s_addr;
1041
1042 copy:
1043 /*
1044 * Not enough information, die.
1045 */
1046 if (src_len < dst_len) goto too_small;
1047
1048 /*
1049 * Copy only as much as we need from the source.
1050 */
1051 memcpy(dst_ptr, src, dst_len);
1052 break;
1053
1054 case PW_TYPE_ABINARY:
1055 dst_len = sizeof(dst->filter);
1056 dst_ptr = (uint8_t *) dst->filter;
1057
1058 /*
1059 * Too little data is OK here.
1060 */
1061 if (src_len < dst_len) {
1062 memcpy(dst_ptr, src, src_len);
1063 memset(dst_ptr + src_len, 0, dst_len - src_len);
1064 break;
1065 }
1066 goto copy;
1067
1068 case PW_TYPE_IFID:
1069 dst_len = sizeof(dst->ifid);
1070 dst_ptr = (uint8_t *) dst->ifid;
1071 goto copy;
1072
1073 case PW_TYPE_IPV6_ADDR:
1074 dst_len = sizeof(dst->ipv6addr);
1075 dst_ptr = (uint8_t *) dst->ipv6addr.s6_addr;
1076 goto copy;
1077
1078 case PW_TYPE_IPV4_PREFIX:
1079 dst_len = sizeof(dst->ipv4prefix);
1080 dst_ptr = (uint8_t *) dst->ipv4prefix;
1081
1082 if (src_len < dst_len) goto too_small;
1083 if ((((uint8_t const *)src)[1] & 0x3f) > 32) return -1;
1084 goto copy;
1085
1086 case PW_TYPE_IPV6_PREFIX:
1087 dst_len = sizeof(dst->ipv6prefix);
1088 dst_ptr = (uint8_t *) dst->ipv6prefix;
1089
1090 /*
1091 * Smaller IPv6 prefixes are OK, too, so long as
1092 * they're not too short.
1093 */
1094 if (src_len < 2) goto too_small;
1095
1096 /*
1097 * Prefix is too long.
1098 */
1099 if (((uint8_t const *)src)[1] > 128) return -1;
1100
1101 if (src_len < dst_len) {
1102 memcpy(dst_ptr, src, src_len);
1103 memset(dst_ptr + src_len, 0, dst_len - src_len);
1104 break;
1105 }
1106
1107 goto copy;
1108
1109 case PW_TYPE_ETHERNET:
1110 dst_len = sizeof(dst->ether);
1111 dst_ptr = (uint8_t *) dst->ether;
1112 goto copy;
1113
1114 default:
1115 fr_strerror_printf("Invalid cast to %s",
1116 fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1117 return -1; /* can't do it */
1118 }
1119
1120 return dst_len;
1121 }
1122
1123 /** Convert one type of value_data_t to another
1124 *
1125 * @note This should be the canonical function used to convert between data types.
1126 *
1127 * @param ctx to allocate buffers in (usually the same as dst)
1128 * @param dst Where to write result of casting.
1129 * @param dst_type to cast to.
1130 * @param dst_enumv Enumerated values used to converts strings to integers.
1131 * @param src_type to cast from.
1132 * @param src_enumv Enumerated values used to convert integers to strings.
1133 * @param src Input data.
1134 * @param src_len Input data len.
1135 * @return the length of data in the dst or -1 on error.
1136 */
value_data_cast(TALLOC_CTX * ctx,value_data_t * dst,PW_TYPE dst_type,DICT_ATTR const * dst_enumv,PW_TYPE src_type,DICT_ATTR const * src_enumv,value_data_t const * src,size_t src_len)1137 ssize_t value_data_cast(TALLOC_CTX *ctx, value_data_t *dst,
1138 PW_TYPE dst_type, DICT_ATTR const *dst_enumv,
1139 PW_TYPE src_type, DICT_ATTR const *src_enumv,
1140 value_data_t const *src, size_t src_len)
1141 {
1142 ssize_t dst_len;
1143
1144 if (!fr_assert(dst_type != src_type)) {
1145 fr_strerror_printf("Types do not match");
1146 return -1;
1147 }
1148
1149 /*
1150 * Deserialise a value_data_t
1151 */
1152 if (src_type == PW_TYPE_STRING) {
1153 return value_data_from_str(ctx, dst, &dst_type, dst_enumv, src->strvalue, src_len, '\0');
1154 }
1155
1156 /*
1157 * Converts the src data to octets with no processing.
1158 */
1159 if (dst_type == PW_TYPE_OCTETS) {
1160 dst_len = value_data_hton(dst, src_type, src, src_len);
1161 if (dst_len < 0) return -1;
1162
1163 dst->octets = talloc_memdup(ctx, dst, dst_len);
1164 talloc_set_type(dst->octets, uint8_t);
1165 return dst_len;
1166 }
1167
1168 /*
1169 * Serialise a value_data_t
1170 */
1171 if (dst_type == PW_TYPE_STRING) {
1172 dst->strvalue = value_data_aprints(ctx, src_type, src_enumv, src, src_len, '\0');
1173 return talloc_array_length(dst->strvalue) - 1;
1174 }
1175
1176 if ((src_type == PW_TYPE_IFID) &&
1177 (dst_type == PW_TYPE_INTEGER64)) {
1178 memcpy(&dst->integer64, src->ifid, sizeof(src->ifid));
1179 dst->integer64 = htonll(dst->integer64);
1180 fixed_length:
1181 return dict_attr_sizes[dst_type][0];
1182 }
1183
1184 if ((src_type == PW_TYPE_INTEGER64) &&
1185 (dst_type == PW_TYPE_ETHERNET)) {
1186 uint8_t array[8];
1187 uint64_t i;
1188
1189 i = htonll(src->integer64);
1190 memcpy(array, &i, 8);
1191
1192 /*
1193 * For OUIs in the DB.
1194 */
1195 if ((array[0] != 0) || (array[1] != 0)) return -1;
1196
1197 memcpy(dst->ether, &array[2], 6);
1198 goto fixed_length;
1199 }
1200
1201 /*
1202 * For integers, we allow the casting of a SMALL type to
1203 * a larger type, but not vice-versa.
1204 */
1205 if (dst_type == PW_TYPE_INTEGER64) {
1206 switch (src_type) {
1207 case PW_TYPE_BYTE:
1208 dst->integer64 = src->byte;
1209 break;
1210
1211 case PW_TYPE_SHORT:
1212 dst->integer64 = src->ushort;
1213 break;
1214
1215 case PW_TYPE_INTEGER:
1216 dst->integer64 = src->integer;
1217 break;
1218
1219 case PW_TYPE_DATE:
1220 dst->integer64 = src->date;
1221 break;
1222
1223 case PW_TYPE_OCTETS:
1224 goto do_octets;
1225
1226 default:
1227 invalid_cast:
1228 fr_strerror_printf("Invalid cast from %s to %s",
1229 fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1230 fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1231 return -1;
1232
1233 }
1234 goto fixed_length;
1235 }
1236
1237 /*
1238 * We can cast LONG integers to SHORTER ones, so long
1239 * as the long one is on the LHS.
1240 */
1241 if (dst_type == PW_TYPE_INTEGER) {
1242 switch (src_type) {
1243 case PW_TYPE_BYTE:
1244 dst->integer = src->byte;
1245 break;
1246
1247 case PW_TYPE_SHORT:
1248 dst->integer = src->ushort;
1249 break;
1250
1251 case PW_TYPE_DATE:
1252 dst->integer = src->date;
1253 break;
1254
1255 case PW_TYPE_IPV4_ADDR:
1256 dst->integer = ntohl(src->ipaddr.s_addr);
1257 break;
1258
1259 case PW_TYPE_OCTETS:
1260 goto do_octets;
1261
1262 default:
1263 goto invalid_cast;
1264 }
1265 goto fixed_length;
1266 }
1267
1268 if (dst_type == PW_TYPE_SHORT) {
1269 switch (src_type) {
1270 case PW_TYPE_BYTE:
1271 dst->ushort = src->byte;
1272 break;
1273
1274 case PW_TYPE_OCTETS:
1275 goto do_octets;
1276
1277 default:
1278 goto invalid_cast;
1279 }
1280 goto fixed_length;
1281 }
1282
1283 /*
1284 * We can cast integers less that < INT_MAX to signed
1285 */
1286 if (dst_type == PW_TYPE_SIGNED) {
1287 switch (src_type) {
1288 case PW_TYPE_BYTE:
1289 dst->sinteger = src->byte;
1290 break;
1291
1292 case PW_TYPE_SHORT:
1293 dst->sinteger = src->ushort;
1294 break;
1295
1296 case PW_TYPE_INTEGER:
1297 if (src->integer > INT_MAX) {
1298 fr_strerror_printf("Invalid cast: From integer to signed. integer value %u is larger "
1299 "than max signed int and would overflow", src->integer);
1300 return -1;
1301 }
1302 dst->sinteger = (int)src->integer;
1303 break;
1304
1305 case PW_TYPE_INTEGER64:
1306 if (src->integer > INT_MAX) {
1307 fr_strerror_printf("Invalid cast: From integer64 to signed. integer64 value %" PRIu64
1308 " is larger than max signed int and would overflow", src->integer64);
1309 return -1;
1310 }
1311 dst->sinteger = (int)src->integer64;
1312 break;
1313
1314 case PW_TYPE_OCTETS:
1315 goto do_octets;
1316
1317 default:
1318 goto invalid_cast;
1319 }
1320 goto fixed_length;
1321 }
1322 /*
1323 * Conversions between IPv4 addresses, IPv6 addresses, IPv4 prefixes and IPv6 prefixes
1324 *
1325 * For prefix to ipaddress conversions, we assume that the host portion has already
1326 * been zeroed out.
1327 *
1328 * We allow casts from v6 to v4 if the v6 address has the correct mapping prefix.
1329 *
1330 * We only allow casts from prefixes to addresses if the prefix is the the length of
1331 * the address, e.g. 32 for ipv4 128 for ipv6.
1332 */
1333 {
1334 /*
1335 * 10 bytes of 0x00 2 bytes of 0xff
1336 */
1337 static uint8_t const v4_v6_map[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1338 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
1339
1340 switch (dst_type) {
1341 case PW_TYPE_IPV4_ADDR:
1342 switch (src_type) {
1343 case PW_TYPE_IPV6_ADDR:
1344 if (memcmp(src->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
1345 bad_v6_prefix_map:
1346 fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
1347 fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1348 fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1349 return -1;
1350 }
1351
1352 memcpy(&dst->ipaddr, &src->ipv6addr.s6_addr[sizeof(v4_v6_map)],
1353 sizeof(dst->ipaddr));
1354 goto fixed_length;
1355
1356 case PW_TYPE_IPV4_PREFIX:
1357 if (src->ipv4prefix[1] != 32) {
1358 bad_v4_prefix_len:
1359 fr_strerror_printf("Invalid cast from %s to %s. Only /32 prefixes may be "
1360 "cast to IP address types",
1361 fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1362 fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1363 return -1;
1364 }
1365
1366 memcpy(&dst->ipaddr, &src->ipv4prefix[2], sizeof(dst->ipaddr));
1367 goto fixed_length;
1368
1369 case PW_TYPE_IPV6_PREFIX:
1370 if (src->ipv6prefix[1] != 128) {
1371 bad_v6_prefix_len:
1372 fr_strerror_printf("Invalid cast from %s to %s. Only /128 prefixes may be "
1373 "cast to IP address types",
1374 fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1375 fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1376 return -1;
1377 }
1378 if (memcmp(&src->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
1379 goto bad_v6_prefix_map;
1380 }
1381 memcpy(&dst->ipaddr, &src->ipv6prefix[2 + sizeof(v4_v6_map)],
1382 sizeof(dst->ipaddr));
1383 goto fixed_length;
1384
1385 default:
1386 break;
1387 }
1388 break;
1389
1390 case PW_TYPE_IPV6_ADDR:
1391 switch (src_type) {
1392 case PW_TYPE_IPV4_ADDR:
1393 /* Add the v4/v6 mapping prefix */
1394 memcpy(dst->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map));
1395 memcpy(&dst->ipv6addr.s6_addr[sizeof(v4_v6_map)], &src->ipaddr,
1396 sizeof(dst->ipv6addr.s6_addr) - sizeof(v4_v6_map));
1397
1398 goto fixed_length;
1399
1400 case PW_TYPE_IPV4_PREFIX:
1401 if (src->ipv4prefix[1] != 32) goto bad_v4_prefix_len;
1402
1403 /* Add the v4/v6 mapping prefix */
1404 memcpy(dst->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map));
1405 memcpy(&dst->ipv6addr.s6_addr[sizeof(v4_v6_map)], &src->ipv4prefix[2],
1406 sizeof(dst->ipv6addr.s6_addr) - sizeof(v4_v6_map));
1407 goto fixed_length;
1408
1409 case PW_TYPE_IPV6_PREFIX:
1410 if (src->ipv4prefix[1] != 128) goto bad_v6_prefix_len;
1411
1412 memcpy(dst->ipv6addr.s6_addr, &src->ipv6prefix[2], sizeof(dst->ipv6addr.s6_addr));
1413 goto fixed_length;
1414
1415 default:
1416 break;
1417 }
1418 break;
1419
1420 case PW_TYPE_IPV4_PREFIX:
1421 switch (src_type) {
1422 case PW_TYPE_IPV4_ADDR:
1423 memcpy(&dst->ipv4prefix[2], &src->ipaddr, sizeof(dst->ipv4prefix) - 2);
1424 dst->ipv4prefix[0] = 0;
1425 dst->ipv4prefix[1] = 32;
1426 goto fixed_length;
1427
1428 case PW_TYPE_IPV6_ADDR:
1429 if (memcmp(src->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
1430 goto bad_v6_prefix_map;
1431 }
1432 memcpy(&dst->ipv4prefix[2], &src->ipv6addr.s6_addr[sizeof(v4_v6_map)],
1433 sizeof(dst->ipv4prefix) - 2);
1434 dst->ipv4prefix[0] = 0;
1435 dst->ipv4prefix[1] = 32;
1436 goto fixed_length;
1437
1438 case PW_TYPE_IPV6_PREFIX:
1439 if (memcmp(&src->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
1440 goto bad_v6_prefix_map;
1441 }
1442
1443 /*
1444 * Prefix must be >= 96 bits. If it's < 96 bytes and the
1445 * above check passed, the v6 address wasn't masked
1446 * correctly when it was packet into a value_data_t.
1447 */
1448 if (!fr_assert(src->ipv6prefix[1] >= (sizeof(v4_v6_map) * 8))) return -1;
1449
1450 memcpy(&dst->ipv4prefix[2], &src->ipv6prefix[2 + sizeof(v4_v6_map)],
1451 sizeof(dst->ipv4prefix) - 2);
1452 dst->ipv4prefix[0] = 0;
1453 dst->ipv4prefix[1] = src->ipv6prefix[1] - (sizeof(v4_v6_map) * 8);
1454 goto fixed_length;
1455
1456 default:
1457 break;
1458 }
1459 break;
1460
1461 case PW_TYPE_IPV6_PREFIX:
1462 switch (src_type) {
1463 case PW_TYPE_IPV4_ADDR:
1464 /* Add the v4/v6 mapping prefix */
1465 memcpy(&dst->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
1466 memcpy(&dst->ipv6prefix[2 + sizeof(v4_v6_map)], &src->ipaddr,
1467 (sizeof(dst->ipv6prefix) - 2) - sizeof(v4_v6_map));
1468 dst->ipv6prefix[0] = 0;
1469 dst->ipv6prefix[1] = 128;
1470 goto fixed_length;
1471
1472 case PW_TYPE_IPV4_PREFIX:
1473 /* Add the v4/v6 mapping prefix */
1474 memcpy(&dst->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
1475 memcpy(&dst->ipv6prefix[2 + sizeof(v4_v6_map)], &src->ipv4prefix[2],
1476 (sizeof(dst->ipv6prefix) - 2) - sizeof(v4_v6_map));
1477 dst->ipv6prefix[0] = 0;
1478 dst->ipv6prefix[1] = (sizeof(v4_v6_map) * 8) + src->ipv4prefix[1];
1479 goto fixed_length;
1480
1481 case PW_TYPE_IPV6_ADDR:
1482 memcpy(&dst->ipv6prefix[2], &src->ipv6addr, sizeof(dst->ipv6prefix) - 2);
1483 dst->ipv6prefix[0] = 0;
1484 dst->ipv6prefix[1] = 128;
1485 goto fixed_length;
1486
1487 default:
1488 break;
1489 }
1490
1491 break;
1492
1493 default:
1494 break;
1495 }
1496 }
1497
1498 /*
1499 * The attribute we've found has to have a size which is
1500 * compatible with the type of the destination cast.
1501 */
1502 if ((src_len < dict_attr_sizes[dst_type][0]) ||
1503 (src_len > dict_attr_sizes[dst_type][1])) {
1504 char const *src_type_name;
1505
1506 src_type_name = fr_int2str(dict_attr_types, src_type, "<INVALID>");
1507 fr_strerror_printf("Invalid cast from %s to %s. Length should be between %zu and %zu but is %zu",
1508 src_type_name,
1509 fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
1510 dict_attr_sizes[dst_type][0], dict_attr_sizes[dst_type][1],
1511 src_len);
1512 return -1;
1513 }
1514
1515 if (src_type == PW_TYPE_OCTETS) {
1516 do_octets:
1517 return value_data_hton(dst, dst_type, src->octets, src_len);
1518 }
1519
1520 /*
1521 * Convert host order to network byte order.
1522 */
1523 if ((dst_type == PW_TYPE_IPV4_ADDR) &&
1524 ((src_type == PW_TYPE_INTEGER) ||
1525 (src_type == PW_TYPE_DATE) ||
1526 (src_type == PW_TYPE_SIGNED))) {
1527 dst->ipaddr.s_addr = htonl(src->integer);
1528
1529 } else if ((src_type == PW_TYPE_IPV4_ADDR) &&
1530 ((dst_type == PW_TYPE_INTEGER) ||
1531 (dst_type == PW_TYPE_DATE) ||
1532 (dst_type == PW_TYPE_SIGNED))) {
1533 dst->integer = htonl(src->ipaddr.s_addr);
1534
1535 } else { /* they're of the same byte order */
1536 memcpy(&dst, &src, src_len);
1537 }
1538
1539 return src_len;
1540 }
1541
1542 /** Copy value data verbatim duplicating any buffers
1543 *
1544 * @param ctx To allocate buffers in.
1545 * @param dst Where to copy value_data to.
1546 * @param src_type Type of src.
1547 * @param src Where to copy value_data from.
1548 * @param src_len Where
1549 */
value_data_copy(TALLOC_CTX * ctx,value_data_t * dst,PW_TYPE src_type,const value_data_t * src,size_t src_len)1550 ssize_t value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE src_type,
1551 const value_data_t *src, size_t src_len)
1552 {
1553 switch (src_type) {
1554 default:
1555 memcpy(dst, src, sizeof(*src));
1556 break;
1557
1558 case PW_TYPE_STRING:
1559 dst->strvalue = talloc_bstrndup(ctx, src->strvalue, src_len);
1560 if (!dst->strvalue) return -1;
1561 break;
1562
1563 case PW_TYPE_OCTETS:
1564 dst->octets = talloc_memdup(ctx, src->octets, src_len);
1565 talloc_set_type(dst->strvalue, uint8_t);
1566 if (!dst->octets) return -1;
1567 break;
1568 }
1569
1570 return src_len;
1571 }
1572
1573
1574
1575 /** Print one attribute value to a string
1576 *
1577 */
value_data_aprints(TALLOC_CTX * ctx,PW_TYPE type,DICT_ATTR const * enumv,value_data_t const * data,size_t inlen,char quote)1578 char *value_data_aprints(TALLOC_CTX *ctx,
1579 PW_TYPE type, DICT_ATTR const *enumv, value_data_t const *data,
1580 size_t inlen, char quote)
1581 {
1582 char *p = NULL;
1583 unsigned int i;
1584
1585 switch (type) {
1586 case PW_TYPE_STRING:
1587 {
1588 size_t len, ret;
1589
1590 if (!quote) {
1591 p = talloc_bstrndup(ctx, data->strvalue, inlen);
1592 if (!p) return NULL;
1593 talloc_set_type(p, char);
1594 return p;
1595 }
1596
1597 /* Gets us the size of the buffer we need to alloc */
1598 len = fr_prints_len(data->strvalue, inlen, quote);
1599 p = talloc_array(ctx, char, len);
1600 if (!p) return NULL;
1601
1602 ret = fr_prints(p, len, data->strvalue, inlen, quote);
1603 if (!fr_assert(ret == (len - 1))) {
1604 talloc_free(p);
1605 return NULL;
1606 }
1607 break;
1608 }
1609
1610 case PW_TYPE_INTEGER:
1611 i = data->integer;
1612 goto print_int;
1613
1614 case PW_TYPE_SHORT:
1615 i = data->ushort;
1616 goto print_int;
1617
1618 case PW_TYPE_BYTE:
1619 i = data->byte;
1620
1621 print_int:
1622 {
1623 DICT_VALUE const *dv;
1624
1625 if (enumv && (dv = dict_valbyattr(enumv->attr, enumv->vendor, i))) {
1626 p = talloc_typed_strdup(ctx, dv->name);
1627 } else {
1628 p = talloc_typed_asprintf(ctx, "%u", i);
1629 }
1630 }
1631 break;
1632
1633 case PW_TYPE_SIGNED:
1634 p = talloc_typed_asprintf(ctx, "%d", data->sinteger);
1635 break;
1636
1637 case PW_TYPE_INTEGER64:
1638 p = talloc_typed_asprintf(ctx, "%" PRIu64 , data->integer64);
1639 break;
1640
1641 case PW_TYPE_ETHERNET:
1642 p = talloc_typed_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
1643 data->ether[0], data->ether[1],
1644 data->ether[2], data->ether[3],
1645 data->ether[4], data->ether[5]);
1646 break;
1647
1648 case PW_TYPE_ABINARY:
1649 #ifdef WITH_ASCEND_BINARY
1650 p = talloc_array(ctx, char, 128);
1651 if (!p) return NULL;
1652 print_abinary(p, 128, (uint8_t const *) &data->filter, inlen, 0);
1653 break;
1654 #else
1655 /* FALL THROUGH */
1656 #endif
1657
1658 case PW_TYPE_OCTETS:
1659 p = talloc_array(ctx, char, 2 + 1 + inlen * 2);
1660 if (!p) return NULL;
1661 p[0] = '0';
1662 p[1] = 'x';
1663
1664 fr_bin2hex(p + 2, data->octets, inlen);
1665 p[2 + (inlen * 2)] = '\0';
1666 break;
1667
1668 case PW_TYPE_DATE:
1669 {
1670 time_t t;
1671 struct tm s_tm;
1672
1673 t = data->date;
1674
1675 p = talloc_zero_array(ctx, char, 64);
1676 strftime(p, 63, "%b %e %Y %H:%M:%S %Z",
1677 localtime_r(&t, &s_tm));
1678 break;
1679 }
1680
1681 /*
1682 * We need to use the proper inet_ntop functions for IP
1683 * addresses, else the output might not match output of
1684 * other functions, which makes testing difficult.
1685 *
1686 * An example is tunnelled ipv4 in ipv6 addresses.
1687 */
1688 case PW_TYPE_IPV4_ADDR:
1689 case PW_TYPE_IPV4_PREFIX:
1690 {
1691 char buff[INET_ADDRSTRLEN + 4]; // + /prefix
1692
1693 buff[0] = '\0';
1694 value_data_prints(buff, sizeof(buff), type, enumv, data, inlen, '\0');
1695
1696 p = talloc_typed_strdup(ctx, buff);
1697 }
1698 break;
1699
1700 case PW_TYPE_IPV6_ADDR:
1701 case PW_TYPE_IPV6_PREFIX:
1702 {
1703 char buff[INET6_ADDRSTRLEN + 4]; // + /prefix
1704
1705 buff[0] = '\0';
1706 value_data_prints(buff, sizeof(buff), type, enumv, data, inlen, '\0');
1707
1708 p = talloc_typed_strdup(ctx, buff);
1709 }
1710 break;
1711
1712 case PW_TYPE_IFID:
1713 p = talloc_typed_asprintf(ctx, "%x:%x:%x:%x",
1714 (data->ifid[0] << 8) | data->ifid[1],
1715 (data->ifid[2] << 8) | data->ifid[3],
1716 (data->ifid[4] << 8) | data->ifid[5],
1717 (data->ifid[6] << 8) | data->ifid[7]);
1718 break;
1719
1720 case PW_TYPE_BOOLEAN:
1721 p = talloc_typed_strdup(ctx, data->byte ? "yes" : "no");
1722 break;
1723
1724 /*
1725 * Don't add default here
1726 */
1727 case PW_TYPE_INVALID:
1728 case PW_TYPE_COMBO_IP_ADDR:
1729 case PW_TYPE_COMBO_IP_PREFIX:
1730 case PW_TYPE_TLV:
1731 case PW_TYPE_EXTENDED:
1732 case PW_TYPE_LONG_EXTENDED:
1733 case PW_TYPE_EVS:
1734 case PW_TYPE_VSA:
1735 case PW_TYPE_TIMEVAL:
1736 case PW_TYPE_MAX:
1737 fr_assert(0);
1738 return NULL;
1739 }
1740
1741 return p;
1742 }
1743
1744
1745 /** Print the value of an attribute to a string
1746 *
1747 * @note return value should be checked with is_truncated.
1748 * @note Will always \0 terminate unless outlen == 0.
1749 *
1750 * @param out Where to write the printed version of the attribute value.
1751 * @param outlen Length of the output buffer.
1752 * @param type of data being printed.
1753 * @param enumv Enumerated string values for integer types.
1754 * @param data to print.
1755 * @param inlen Length of data.
1756 * @param quote char to escape in string output.
1757 * @return the number of bytes written to the out buffer, or a number >= outlen if truncation has occurred.
1758 */
value_data_prints(char * out,size_t outlen,PW_TYPE type,DICT_ATTR const * enumv,value_data_t const * data,ssize_t inlen,char quote)1759 size_t value_data_prints(char *out, size_t outlen,
1760 PW_TYPE type, DICT_ATTR const *enumv, value_data_t const *data,
1761 ssize_t inlen, char quote)
1762 {
1763 DICT_VALUE *v;
1764 char buf[1024]; /* Interim buffer to use with poorly behaved printing functions */
1765 char const *a = NULL;
1766 char *p = out;
1767 time_t t;
1768 struct tm s_tm;
1769 unsigned int i;
1770
1771 size_t len = 0, freespace = outlen;
1772
1773 if (!data) return 0;
1774 if (outlen == 0) return inlen;
1775
1776 *out = '\0';
1777
1778 p = out;
1779
1780 switch (type) {
1781 case PW_TYPE_STRING:
1782
1783 /*
1784 * Ensure that WE add the quotation marks around the string.
1785 */
1786 if (quote) {
1787 if (freespace < 3) return inlen + 2;
1788
1789 *p++ = quote;
1790 freespace--;
1791
1792 len = fr_prints(p, freespace, data->strvalue, inlen, quote);
1793 /* always terminate the quoted string with another quote */
1794 if (len >= (freespace - 1)) {
1795 /* Use out not p as we're operating on the entire buffer */
1796 out[outlen - 2] = (char) quote;
1797 out[outlen - 1] = '\0';
1798 return len + 2;
1799 }
1800 p += len;
1801 freespace -= len;
1802
1803 *p++ = (char) quote;
1804 freespace--;
1805 *p = '\0';
1806
1807 return len + 2;
1808 }
1809
1810 return fr_prints(out, outlen, data->strvalue, inlen, quote);
1811
1812 case PW_TYPE_INTEGER:
1813 i = data->integer;
1814 goto print_int;
1815
1816 case PW_TYPE_SHORT:
1817 i = data->ushort;
1818 goto print_int;
1819
1820 case PW_TYPE_BYTE:
1821 i = data->byte;
1822
1823 print_int:
1824 /* Normal, non-tagged attribute */
1825 if (enumv && (v = dict_valbyattr(enumv->attr, enumv->vendor, i)) != NULL) {
1826 a = v->name;
1827 len = strlen(a);
1828 } else {
1829 /* should never be truncated */
1830 len = snprintf(buf, sizeof(buf), "%u", i);
1831 a = buf;
1832 }
1833 break;
1834
1835 case PW_TYPE_INTEGER64:
1836 return snprintf(out, outlen, "%" PRIu64, data->integer64);
1837
1838 case PW_TYPE_DATE:
1839 t = data->date;
1840 if (quote > 0) {
1841 len = strftime(buf, sizeof(buf) - 1, "%%%b %e %Y %H:%M:%S %Z%%", localtime_r(&t, &s_tm));
1842 buf[0] = (char) quote;
1843 buf[len - 1] = (char) quote;
1844 buf[len] = '\0';
1845 } else {
1846 len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z", localtime_r(&t, &s_tm));
1847 }
1848 a = buf;
1849 break;
1850
1851 case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
1852 len = snprintf(buf, sizeof(buf), "%d", data->sinteger);
1853 a = buf;
1854 break;
1855
1856 case PW_TYPE_IPV4_ADDR:
1857 a = inet_ntop(AF_INET, &(data->ipaddr), buf, sizeof(buf));
1858 len = strlen(buf);
1859 break;
1860
1861 case PW_TYPE_ABINARY:
1862 #ifdef WITH_ASCEND_BINARY
1863 print_abinary(buf, sizeof(buf), (uint8_t const *) data->filter, inlen, quote);
1864 a = buf;
1865 len = strlen(buf);
1866 break;
1867 #else
1868 /* FALL THROUGH */
1869 #endif
1870 case PW_TYPE_OCTETS:
1871 case PW_TYPE_TLV:
1872 {
1873 size_t binlen;
1874 size_t hexlen;
1875
1876 binlen = inlen;
1877 hexlen = (binlen * 2) + 2; /* NOT accounting for trailing NUL */
1878
1879 /*
1880 * If the buffer is too small, put something into
1881 * it, and return how much we should have written
1882 *
1883 * 0 + x + H + H + NUL = 5
1884 */
1885 if (freespace < 5) {
1886 switch (freespace) {
1887 case '4':
1888 case '3':
1889 out[0] = '0';
1890 out[1] = 'x';
1891 out[2] = '\0';
1892 return hexlen;
1893
1894 case 2:
1895 *out = '0';
1896 out++;
1897 /* FALL-THROUGH */
1898
1899 case 1:
1900 *out = '\0';
1901 break;
1902
1903 case 0:
1904 break;
1905 }
1906
1907 return hexlen;
1908 }
1909
1910 /*
1911 * The output buffer is at least 5 bytes, we haev
1912 * room for '0xHH' plus a trailing NUL byte.
1913 */
1914 out[0] = '0';
1915 out[1] = 'x';
1916
1917 /*
1918 * Get maximum number of bytes we can encode
1919 * given freespace, ensuring we account for '0',
1920 * 'x', and the trailing NUL in the buffer.
1921 *
1922 * Note that we can't have "freespace = 0" after
1923 * this, as 'freespace' has to be at least 5.
1924 */
1925 freespace -= 3;
1926 freespace /= 2;
1927 if (binlen > freespace) {
1928 binlen = freespace;
1929 }
1930
1931 fr_bin2hex(out + 2, data->octets, binlen);
1932 return hexlen;
1933 }
1934
1935 case PW_TYPE_IFID:
1936 a = ifid_ntoa(buf, sizeof(buf), data->ifid);
1937 len = strlen(buf);
1938 break;
1939
1940 case PW_TYPE_IPV6_ADDR:
1941 a = inet_ntop(AF_INET6, &data->ipv6addr, buf, sizeof(buf));
1942 len = strlen(buf);
1943 break;
1944
1945 case PW_TYPE_IPV6_PREFIX:
1946 {
1947 struct in6_addr addr;
1948
1949 /*
1950 * Alignment issues.
1951 */
1952 memcpy(&addr, &(data->ipv6prefix[2]), sizeof(addr));
1953
1954 a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
1955 if (a) {
1956 p = buf;
1957
1958 len = strlen(buf);
1959 p += len;
1960 len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) data->ipv6prefix[1]);
1961 }
1962 }
1963 break;
1964
1965 case PW_TYPE_IPV4_PREFIX:
1966 {
1967 struct in_addr addr;
1968
1969 /*
1970 * Alignment issues.
1971 */
1972 memcpy(&addr, &(data->ipv4prefix[2]), sizeof(addr));
1973
1974 a = inet_ntop(AF_INET, &addr, buf, sizeof(buf));
1975 if (a) {
1976 p = buf;
1977
1978 len = strlen(buf);
1979 p += len;
1980 len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) (data->ipv4prefix[1] & 0x3f));
1981 }
1982 }
1983 break;
1984
1985 case PW_TYPE_ETHERNET:
1986 return snprintf(out, outlen, "%02x:%02x:%02x:%02x:%02x:%02x",
1987 data->ether[0], data->ether[1],
1988 data->ether[2], data->ether[3],
1989 data->ether[4], data->ether[5]);
1990
1991 /*
1992 * Don't add default here
1993 */
1994 case PW_TYPE_INVALID:
1995 case PW_TYPE_COMBO_IP_ADDR:
1996 case PW_TYPE_COMBO_IP_PREFIX:
1997 case PW_TYPE_EXTENDED:
1998 case PW_TYPE_LONG_EXTENDED:
1999 case PW_TYPE_EVS:
2000 case PW_TYPE_VSA:
2001 case PW_TYPE_TIMEVAL:
2002 case PW_TYPE_BOOLEAN:
2003 case PW_TYPE_MAX:
2004 fr_assert(0);
2005 *out = '\0';
2006 return 0;
2007 }
2008
2009 if (a) strlcpy(out, a, outlen);
2010
2011 return len; /* Return the number of bytes we would of written (for truncation detection) */
2012 }
2013
2014