The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
value.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Boxed value structures and functions to manipulate them
18 *
19 * @file src/lib/util/value.c
20 *
21 * There are three notional data formats used in the server:
22 *
23 * - #fr_value_box_t are the INTERNAL format. This is usually close to the in-memory representation
24 * of the data, though uint32s and IPs are always converted to/from octets with BIG ENDIAN
25 * uint8 ordering for consistency.
26 * - #fr_value_box_cast is used to convert (cast) #fr_value_box_t between INTERNAL formats.
27 * - #fr_value_box_strdup* is used to ingest nul terminated strings into the INTERNAL format.
28 * - #fr_value_box_memdup* is used to ingest binary data into the INTERNAL format.
29 *
30 * - NETWORK format is the format we send/receive on the wire. It is not a perfect representation
31 * of data packing for all protocols, so you will likely need to overload conversion for some types.
32 * - fr_value_box_to_network is used to convert INTERNAL format data to generic NETWORK format data.
33 * For uint32s, IP addresses etc... This means BIG ENDIAN uint8 ordering.
34 * - fr_value_box_from_network is used to convert packet buffer fragments in NETWORK format to
35 * INTERNAL format.
36 *
37 * - PRESENTATION format is what we print to the screen, and what we get from the user, databases
38 * and configuration files.
39 * - #fr_value_box_aprint is used to convert from INTERNAL to PRESENTATION format.
40 * - #fr_value_box_from_substr is used to convert from PRESENTATION to INTERNAL format.
41 *
42 * @copyright 2014-2017 The FreeRADIUS server project
43 * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
44 */
45RCSID("$Id: ff4f46a2b7786977e7565a7d2c3c6688541a2806 $")
46
47#define _VALUE_PRIVATE
48#include <freeradius-devel/util/value.h>
49#undef _VALUE_PRIVATE
50
51#include <freeradius-devel/util/atexit.h>
52#include <freeradius-devel/util/base16.h>
53#include <freeradius-devel/util/dcursor.h>
54#include <freeradius-devel/util/size.h>
55#include <freeradius-devel/util/time.h>
56
57#include <math.h>
58
59/** Sanity checks
60 *
61 * There should never be an instance where these fail.
62 */
63static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_ip.addr.v4.s_addr) == 4,
64 "in_addr.s_addr has unexpected length");
65static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_ip.addr.v6.s6_addr) == 16,
66 "in6_addr.s6_addr has unexpected length");
67static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_ifid) == 8,
68 "vb_ifid has unexpected length");
69static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_ether) == 6,
70 "vb_ether has unexpected length");
71
72static_assert(SIZEOF_MEMBER(fr_value_box_t, datum.boolean) == 1,
73 "datum.boolean has unexpected length");
74static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_uint8) == 1,
75 "vb_uint8 has unexpected length");
76static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_uint16) == 2,
77 "vb_uint16 has unexpected length");
78static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_uint32) == 4,
79 "vb_uint32 has unexpected length");
80static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_uint64) == 8,
81 "vb_uint64 has unexpected length");
82
83static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_int8) == 1,
84 "vb_int16 has unexpected length");
85static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_int16) == 2,
86 "vb_int16 has unexpected length");
87static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_int32) == 4,
88 "vb_int32 has unexpected length");
89static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_int64) == 8,
90 "vb_int64 has unexpected length");
91
92static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_float32) == 4,
93 "vb_float32 has unexpected length");
94static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_float64) == 8,
95 "vb_float64 has unexpected length");
96
97/** How many bytes on-the-wire would a #fr_value_box_t value consume
98 *
99 * This is for the generic NETWORK format. For field sizes in the in-memory
100 * structure use #fr_value_box_field_sizes.
101 *
102 * @note Don't use this array directly when determining the length
103 * that would be consumed by the on-the-wire representation.
104 * Use #fr_value_box_network_length instead, as that deals with variable
105 * length attributes too.
106 */
107#define network_min_size(_x) (fr_value_box_network_sizes[_x][0])
108#define network_max_size(_x) (fr_value_box_network_sizes[_x][1])
109static size_t const fr_value_box_network_sizes[FR_TYPE_MAX + 1][2] = {
110 [FR_TYPE_NULL] = {~0, 0},
111
112 [FR_TYPE_STRING] = {0, ~0},
113 [FR_TYPE_OCTETS] = {0, ~0},
114
115 [FR_TYPE_IPV4_ADDR] = {4, 4},
116 [FR_TYPE_IPV4_PREFIX] = {5, 5},
117 [FR_TYPE_IPV6_ADDR] = {16, 17},
118 [FR_TYPE_IPV6_PREFIX] = {17, 18},
119 [FR_TYPE_COMBO_IP_ADDR] = {4, 17},
120 [FR_TYPE_COMBO_IP_PREFIX] = {16, 18},
121 [FR_TYPE_IFID] = {8, 8},
122 [FR_TYPE_ETHERNET] = {6, 6},
123
124 [FR_TYPE_BOOL] = {1, 1},
125 [FR_TYPE_UINT8] = {1, 1},
126 [FR_TYPE_UINT16] = {2, 2},
127 [FR_TYPE_UINT32] = {4, 4},
128 [FR_TYPE_UINT64] = {8, 8},
129
130 [FR_TYPE_INT8] = {1, 1},
131 [FR_TYPE_INT16] = {2, 2},
132 [FR_TYPE_INT32] = {4, 4},
133 [FR_TYPE_INT64] = {8, 8},
134
135 [FR_TYPE_FLOAT32] = {4, 4},
136 [FR_TYPE_FLOAT64] = {8, 8},
137
138 [FR_TYPE_DATE] = {2, 8}, //!< 2, 4, or 8 only
139 [FR_TYPE_TIME_DELTA] = {2, 8}, //!< 2, 4, or 8 only
140
141 [FR_TYPE_MAX] = {~0, 0} //!< Ensure array covers all types.
142};
143
144/** How many bytes wide each of the value data fields are
145 *
146 * This is useful when copying a value from a fr_value_box_t to a memory
147 * location passed as a void *.
148 */
149size_t const fr_value_box_field_sizes[] = {
152
161
162 [FR_TYPE_BOOL] = SIZEOF_MEMBER(fr_value_box_t, datum.boolean),
167
172
175
177
178 [FR_TYPE_TIME_DELTA] = SIZEOF_MEMBER(fr_value_box_t, datum.time_delta),
180
182
183 [FR_TYPE_MAX] = 0 //!< Ensure array covers all types.
184};
185
186/** Where the value starts in the #fr_value_box_t
187 *
188 */
189size_t const fr_value_box_offsets[] = {
192
199 [FR_TYPE_IFID] = offsetof(fr_value_box_t, vb_ifid),
201
202 [FR_TYPE_BOOL] = offsetof(fr_value_box_t, vb_bool),
207
208 [FR_TYPE_INT8] = offsetof(fr_value_box_t, vb_int8),
212
215
216 [FR_TYPE_DATE] = offsetof(fr_value_box_t, vb_date),
217
219 [FR_TYPE_SIZE] = offsetof(fr_value_box_t, vb_size),
220
221 [FR_TYPE_VALUE_BOX] = 0,
222
223 [FR_TYPE_MAX] = 0 //!< Ensure array covers all types.
224};
225
226static uint64_t const fr_value_box_integer_max[] = {
227 [FR_TYPE_BOOL] = true,
229 [FR_TYPE_UINT16] = UINT16_MAX,
230 [FR_TYPE_UINT32] = UINT32_MAX,
231 [FR_TYPE_UINT64] = UINT64_MAX,
232
233 [FR_TYPE_INT8] = INT8_MAX,
234 [FR_TYPE_INT16] = INT16_MAX,
235 [FR_TYPE_INT32] = INT32_MAX,
236 [FR_TYPE_INT64] = INT64_MAX,
237
238 [FR_TYPE_DATE] = UINT64_MAX,
239 [FR_TYPE_TIME_DELTA] = INT64_MAX,
240
241 [FR_TYPE_SIZE] = SIZE_MAX,
242
243 [FR_TYPE_MAX] = 0 //!< Ensure array covers all types.
244};
245
246static int64_t const fr_value_box_integer_min[] = {
247 [FR_TYPE_BOOL] = false,
248 [FR_TYPE_UINT8] = 0,
249 [FR_TYPE_UINT16] = 0,
250 [FR_TYPE_UINT32] = 0,
251 [FR_TYPE_UINT64] = 0,
252
253 [FR_TYPE_INT8] = INT8_MIN,
254 [FR_TYPE_INT16] = INT16_MIN,
255 [FR_TYPE_INT32] = INT32_MIN,
256 [FR_TYPE_INT64] = INT64_MIN,
257
258 [FR_TYPE_DATE] = 0,
259 [FR_TYPE_TIME_DELTA] = INT64_MIN,
260
261 [FR_TYPE_SIZE] = 0,
262
263 [FR_TYPE_MAX] = 0 //!< Ensure array covers all types.
264};
265
267 .name = "double",
268 .chr = '\\',
269 .subs = {
270 ['"'] = '"', /* Quoting char */
271 ['%'] = '%', /* xlat expansions */
272 ['\\'] = '\\',
273 ['a'] = '\a',
274 ['b'] = '\b',
275 ['e'] = '\\',
276 ['n'] = '\n',
277 ['r'] = '\r',
278 ['t'] = '\t',
279 ['v'] = '\v'
280 },
281 .do_hex = true,
282 .do_oct = true
283};
284
286 .name = "single",
287 .chr = '\\',
288 .subs = {
289 ['\''] = '\'', /* Quoting char */
290 ['\\'] = '\\'
291 },
292 .do_hex = false,
293 .do_oct = false
294};
295
297 .name = "solidus",
298 .chr = '\\',
299 .subs = {
300 ['%'] = '%', /* xlat expansions */
301 ['/'] = '/', /* Quoting char */
302 ['a'] = '\a',
303 ['b'] = '\b',
304 ['e'] = '\\',
305 ['n'] = '\n',
306 ['r'] = '\r',
307 ['t'] = '\t',
308 ['v'] = '\v'
309 },
310 .skip = {
311 ['\\'] = '\\' /* Leave this for the regex library */
312 },
313 .do_hex = true,
314 .do_oct = true
315};
316
318 .name = "backtick",
319 .chr = '\\',
320 .subs = {
321 ['%'] = '%', /* xlat expansions */
322 ['\\'] = '\\',
323 ['`'] = '`', /* Quoting char */
324 ['a'] = '\a',
325 ['b'] = '\b',
326 ['e'] = '\\',
327 ['n'] = '\n',
328 ['r'] = '\r',
329 ['t'] = '\t',
330 ['v'] = '\v'
331 },
332 .do_hex = true,
333 .do_oct = true
334};
335
342
349
351 .name = "double",
352 .chr = '\\',
353 .subs = {
354 ['"'] = '"', /* Quoting char */
355 ['%'] = '%', /* xlat expansions */
356 ['\\'] = '\\',
357 ['\a'] = 'a',
358 ['\b'] = 'b',
359 ['\n'] = 'n',
360 ['\r'] = 'r',
361 ['\t'] = 't',
362 ['\v'] = 'v'
363 },
364 .esc = {
367 },
368 .do_utf8 = true,
369 .do_oct = true
370};
371
372#ifdef __clang__
373#pragma clang diagnostic ignored "-Wgnu-designator"
374#endif
375
376/** Escape secret fields by simply mashing all data to '.'
377 *
378 * The length of the secret still leaks, but that is likely fine. Fixing that is more work.
379 *
380 */
382 .name = "secret",
383 .subs = {
384 [ 0 ... 255 ] = '.',
385 },
386};
387
389 .name = "single",
390 .chr = '\\',
391 .subs = {
392 ['\''] = '\'', /* Quoting char */
393 ['\\'] = '\\'
394 },
395 .do_utf8 = true,
396};
397
399 .name = "solidus",
400 .chr = '\\',
401 .subs = {
402 ['%'] = '%', /* xlat expansions */
403 ['/'] = '/', /* Quoting char */
404 ['\a'] = 'a',
405 ['\b'] = 'b',
406 ['\n'] = 'n',
407 ['\r'] = 'r',
408 ['\t'] = 't',
409 ['\v'] = 'v'
410 },
411 .esc = {
414 },
415 .do_utf8 = true,
416 .do_oct = true
417};
418
420 .name = "backtick",
421 .chr = '\\',
422 .subs = {
423 ['%'] = '%', /* xlat expansions */
424 ['\\'] = '\\',
425 ['`'] = '`', /* Quoting char */
426 ['\a'] = 'a',
427 ['\b'] = 'b',
428 ['\n'] = 'n',
429 ['\r'] = 'r',
430 ['\t'] = 't',
431 ['\v'] = 'v'
432 },
433 .esc = {
436 },
437 .do_utf8 = true,
438 .do_oct = true
439};
440
447
454
456 .name = "unprintables",
457 .chr = '\\',
458 .subs = {
459 ['\\'] = '\\',
460 },
461 .esc = {
464 },
465 .do_utf8 = true,
466 .do_oct = true
467};
468
469
470/** @name Produce a #tmpl_t from a string or substring
471 *
472 * @{
473 */
474
475/* clang-format off */
476/** Default formatting rules
477 *
478 * Control token termination, escaping and how the tmpl is printed.
479 */
480fr_sbuff_parse_rules_t const value_parse_rules_bareword_unquoted = {
481
482};
483
484fr_sbuff_parse_rules_t const value_parse_rules_double_unquoted = {
485 .escapes = &fr_value_unescape_double
486};
487
488fr_sbuff_parse_rules_t const value_parse_rules_single_unquoted = {
489 .escapes = &fr_value_unescape_single
490};
491
492fr_sbuff_parse_rules_t const value_parse_rules_solidus_unquoted = {
493 .escapes = &fr_value_unescape_solidus
494};
495
496fr_sbuff_parse_rules_t const value_parse_rules_backtick_unquoted = {
498};
499
500/** Parse rules for non-quoted strings
501 *
502 * These parse rules should be used for processing escape sequences in
503 * data from external data sources like SQL databases and REST APIs.
504 *
505 * They do not include terminals to stop parsing as it assumes the values
506 * are discrete, and not wrapped in quotes.
507 */
515
523
524fr_sbuff_parse_rules_t const value_parse_rules_bareword_quoted = {
525 .escapes = &(fr_sbuff_unescape_rules_t){
526 .chr = '\\',
527 /*
528 * Allow barewords to contain whitespace
529 * if they're escaped.
530 */
531 .subs = {
532 ['\t'] = '\t',
533 ['\n'] = '\n',
534 [' '] = ' '
535 },
536 .do_hex = false,
537 .do_oct = false
538 },
539 .terminals = &FR_SBUFF_TERMS(
540 L(""),
541 L("\t"),
542 L("\n"),
543 L(" ")
544 )
545};
546
547fr_sbuff_parse_rules_t const value_parse_rules_double_quoted = {
548 .escapes = &fr_value_unescape_double,
549 .terminals = &FR_SBUFF_TERMS(
550 L(""), L("\n"), L("\r"), L("\""))
551};
552
553fr_sbuff_parse_rules_t const value_parse_rules_single_quoted = {
554 .escapes = &fr_value_unescape_single,
555 .terminals = &FR_SBUFF_TERMS(
556 L(""), L("\n"), L("\r"), L("'"))
557};
558
559fr_sbuff_parse_rules_t const value_parse_rules_solidus_quoted = {
560 .escapes = &fr_value_unescape_solidus,
561 .terminals = &FR_SBUFF_TERMS(
562 L(""), L("\n"), L("\r"), L("/"))
563};
564
565fr_sbuff_parse_rules_t const value_parse_rules_backtick_quoted = {
566 .escapes = &fr_value_unescape_backtick,
567 .terminals = &FR_SBUFF_TERMS(
568 L(""), L("\n"), L("\r"), L("`"))
569};
570
571/*
572 * And triple-quoted versions of the above.
573 */
574fr_sbuff_parse_rules_t const value_parse_rules_double_3quoted = {
575 .escapes = &fr_value_unescape_double,
576 .terminals = &FR_SBUFF_TERMS(
577 L(""), L("\n"), L("\r"), L("\"\"\""))
578};
579
580fr_sbuff_parse_rules_t const value_parse_rules_single_3quoted = {
581 .escapes = &fr_value_unescape_single,
582 .terminals = &FR_SBUFF_TERMS(
583 L(""), L("\n"), L("\r"), L("'''"))
584};
585
586fr_sbuff_parse_rules_t const value_parse_rules_solidus_3quoted = {
587 .escapes = &fr_value_unescape_solidus,
588 .terminals = &FR_SBUFF_TERMS(
589 L(""), L("\n"), L("\r"), L("///"))
590};
591
592fr_sbuff_parse_rules_t const value_parse_rules_backtick_3quoted = {
593 .escapes = &fr_value_unescape_backtick,
594 .terminals = &FR_SBUFF_TERMS(
595 L(""), L("\n"), L("\r"), L("```"))
596};
597
598/** Parse rules for quoted strings
599 *
600 * These parse rules should be used for internal parsing functions that
601 * are working with configuration files.
602 *
603 * They include appropriate quote terminals to force functions parsing
604 * quoted strings to return when they reach a quote character.
605 */
613
621
629
630/* clang-format on */
631/** @} */
632
633/** Copy flags and type data from one value box to another
634 *
635 * @param[in] dst to copy flags to
636 * @param[in] src of data.
637 */
638static inline void fr_value_box_copy_meta(fr_value_box_t *dst, fr_value_box_t const *src)
639{
640 switch (src->type) {
642 dst->vb_length = src->vb_length;
643 break;
644 /*
645 * Not 100% sure this should be done here
646 * but if the intent is to make a null
647 * box usable, then we need to do this
648 * somewhere.
649 */
650 case FR_TYPE_GROUP:
651 fr_value_box_list_init(&dst->vb_group);
652 break;
653
654 default:
655 break;
656 }
657
658 dst->enumv = src->enumv;
659 dst->type = src->type;
660 dst->tainted = src->tainted;
661 dst->safe_for = src->safe_for;
662 dst->secret = src->secret;
663 fr_value_box_list_entry_init(dst);
664}
665
666/** Compare two values
667 *
668 * @param[in] a Value to compare.
669 * @param[in] b Value to compare.
670 * @return
671 * - -1 if a is less than b.
672 * - 0 if both are equal.
673 * - 1 if a is more than b.
674 * - < -1 on failure.
675 */
677{
678 if (!fr_cond_assert(a->type != FR_TYPE_NULL)) return -1;
679 if (!fr_cond_assert(b->type != FR_TYPE_NULL)) return -1;
680
681 if (a->type != b->type) {
682 fr_strerror_printf("%s: Can't compare values of different types", __FUNCTION__);
683 return -2;
684 }
685
686 /*
687 * After doing the previous check for special comparisons,
688 * do the per-type comparison here.
689 */
690 switch (a->type) {
692 {
693 size_t length;
694
695 if (a->vb_length < b->vb_length) {
696 length = a->vb_length;
697 } else {
698 length = b->vb_length;
699 }
700
701 if (length) {
702 int cmp;
703
704 /*
705 * Use constant-time comparisons for secret values.
706 */
707 if (a->secret || b->secret) {
708 cmp = fr_digest_cmp(a->datum.ptr, b->datum.ptr, length);
709 } else {
710 cmp = memcmp(a->datum.ptr, b->datum.ptr, length);
711 }
712 if (cmp != 0) return CMP(cmp, 0);
713 }
714
715 /*
716 * Contents are the same. The return code
717 * is therefore the difference in lengths.
718 *
719 * i.e. "0x00" is smaller than "0x0000"
720 */
721 return CMP(a->vb_length, b->vb_length);
722 }
723
724 /*
725 * Short-hand for simplicity.
726 */
727#define RETURN(_type) return CMP(a->datum._type, b->datum._type)
728#define COMPARE(_type) return CMP(memcmp(&a->datum._type, &b->datum._type, sizeof(a->datum._type)), 0)
729
730 case FR_TYPE_BOOL:
731 RETURN(boolean);
732
733 case FR_TYPE_DATE:
734 return fr_unix_time_cmp(a->datum.date, b->datum.date);
735
736 case FR_TYPE_UINT8:
737 RETURN(uint8);
738
739 case FR_TYPE_UINT16:
740 RETURN(uint16);
741
742 case FR_TYPE_UINT32:
743 RETURN(uint32);
744
745 case FR_TYPE_UINT64:
746 RETURN(uint64);
747
748 case FR_TYPE_INT8:
749 RETURN(int8);
750
751 case FR_TYPE_INT16:
752 RETURN(int16);
753
754 case FR_TYPE_INT32:
755 RETURN(int32);
756
757 case FR_TYPE_INT64:
758 RETURN(int64);
759
760 case FR_TYPE_SIZE:
761 RETURN(size);
762
764 return fr_time_delta_cmp(a->datum.time_delta, b->datum.time_delta);
765
766 case FR_TYPE_FLOAT32:
767 RETURN(float32);
768
769 case FR_TYPE_FLOAT64:
771
772 case FR_TYPE_ETHERNET:
773 COMPARE(ether);
774
781 return fr_ipaddr_cmp(&a->vb_ip, &b->vb_ip);
782
783 case FR_TYPE_IFID:
784 COMPARE(ifid);
785
786 /*
787 * These should be handled at some point
788 */
789 case FR_TYPE_NON_LEAF:
790 (void)fr_cond_assert(0); /* unknown type */
791 return -2;
792
793 /*
794 * Do NOT add a default here, as new types are added
795 * static analysis will warn us they're not handled
796 */
797 }
798 return 0;
799}
800
801/*
802 * We leverage the fact that IPv4 and IPv6 prefixes both
803 * have the same format:
804 *
805 * reserved, prefix-len, data...
806 */
807static int fr_value_box_cidr_cmp_op(fr_token_t op, int bytes,
808 uint8_t a_net, uint8_t const *a,
809 uint8_t b_net, uint8_t const *b)
810{
811 int i, common;
813
814 /*
815 * Handle the case of netmasks being identical.
816 */
817 if (a_net == b_net) {
818 int compare;
819
820 compare = memcmp(a, b, bytes);
821
822 /*
823 * If they're identical return true for
824 * identical.
825 */
826 if ((compare == 0) &&
827 ((op == T_OP_CMP_EQ) ||
828 (op == T_OP_LE) ||
829 (op == T_OP_GE))) {
830 return true;
831 }
832
833 /*
834 * Everything else returns false.
835 *
836 * 10/8 == 24/8 --> false
837 * 10/8 <= 24/8 --> false
838 * 10/8 >= 24/8 --> false
839 */
840 return false;
841 }
842
843 /*
844 * Netmasks are different. That limits the
845 * possible results, based on the operator.
846 */
847 switch (op) {
848 case T_OP_CMP_EQ:
849 return false;
850
851 case T_OP_NE:
852 return true;
853
854 case T_OP_LE:
855 case T_OP_LT: /* 192/8 < 192.168/16 --> false */
856 if (a_net < b_net) {
857 return false;
858 }
859 break;
860
861 case T_OP_GE:
862 case T_OP_GT: /* 192/16 > 192.168/8 --> false */
863 if (a_net > b_net) {
864 return false;
865 }
866 break;
867
868 default:
869 return false;
870 }
871
872 if (a_net < b_net) {
873 common = a_net;
874 } else {
875 common = b_net;
876 }
877
878 /*
879 * Do the check uint8 by uint8. If the bytes are
880 * identical, it MAY be a match. If they're different,
881 * it is NOT a match.
882 */
883 i = 0;
884 while (i < bytes) {
885 /*
886 * All leading bytes are identical.
887 */
888 if (common == 0) return true;
889
890 /*
891 * Doing bitmasks takes more work.
892 */
893 if (common < 8) break;
894
895 if (a[i] != b[i]) return false;
896
897 common -= 8;
898 i++;
899 continue;
900 }
901
902 mask = 1;
903 mask <<= (8 - common);
904 mask--;
905 mask = ~mask;
906
907 if ((a[i] & mask) == ((b[i] & mask))) {
908 return true;
909 }
910
911 return false;
912}
913
914/*
915 * So we don't have to include <util/regex.h> in a recursive fashion.
916 */
917extern int fr_regex_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b);
918
919/** Compare two attributes using an operator
920 *
921 * @param[in] op to use in comparison.
922 * @param[in] a Value to compare.
923 * @param[in] b Value to compare.
924 * @return
925 * - 1 if true
926 * - 0 if false
927 * - -1 on failure.
928 */
930{
931 int compare = 0;
932
933 if (!fr_cond_assert(a->type != FR_TYPE_NULL)) return -1;
934 if (!fr_cond_assert(b->type != FR_TYPE_NULL)) return -1;
935
936 if (unlikely((op == T_OP_REG_EQ) || (op == T_OP_REG_NE))) return fr_regex_cmp_op(op, a, b);
937
938 switch (a->type) {
940 switch (b->type) {
942 if (b->vb_ip.af != AF_INET) goto fail_cmp_v4;
944
945 case FR_TYPE_IPV4_ADDR: /* IPv4 and IPv4 */
946 goto cmp;
947
949 if (b->vb_ip.af != AF_INET) goto fail_cmp_v4;
951
952 case FR_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
953 return fr_value_box_cidr_cmp_op(op, 4, 32, (uint8_t const *) &a->vb_ip.addr.v4.s_addr,
954 b->vb_ip.prefix, (uint8_t const *) &b->vb_ip.addr.v4.s_addr);
955
956 default:
957 fail_cmp_v4:
958 fr_strerror_const("Cannot compare IPv4 with IPv6 address");
959 return -1;
960 }
961
962 case FR_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
963 cmp_prefix_v4:
964 switch (b->type) {
966 if (b->vb_ip.af != AF_INET) goto fail_cmp_v4;
968
970 return fr_value_box_cidr_cmp_op(op, 4, a->vb_ip.prefix,
971 (uint8_t const *) &a->vb_ip.addr.v4.s_addr,
972 32, (uint8_t const *) &b->vb_ip.addr.v4);
973
975 if (b->vb_ip.af != AF_INET) goto fail_cmp_v4;
977
978 case FR_TYPE_IPV4_PREFIX: /* IPv4 Prefix and IPv4 Prefix */
979 return fr_value_box_cidr_cmp_op(op, 4, a->vb_ip.prefix,
980 (uint8_t const *) &a->vb_ip.addr.v4.s_addr,
981 b->vb_ip.prefix, (uint8_t const *) &b->vb_ip.addr.v4.s_addr);
982
983 default:
984 fr_strerror_const("Cannot compare IPv4 with IPv6 address");
985 return -1;
986 }
987
989 switch (b->type) {
991 if (b->vb_ip.af != AF_INET6) goto fail_cmp_v6;
993
994 case FR_TYPE_IPV6_ADDR: /* IPv6 and IPv6 */
995 goto cmp;
996
998 if (b->vb_ip.af != AF_INET6) goto fail_cmp_v6;
1000
1001 case FR_TYPE_IPV6_PREFIX: /* IPv6 and IPv6 Preifx */
1002 return fr_value_box_cidr_cmp_op(op, 16, 128, (uint8_t const *) &a->vb_ip.addr.v6,
1003 b->vb_ip.prefix, (uint8_t const *) &b->vb_ip.addr.v6);
1004
1005 default:
1006 fail_cmp_v6:
1007 fr_strerror_const("Cannot compare IPv6 with IPv4 address");
1008 return -1;
1009 }
1010
1012 cmp_prefix_v6:
1013 switch (b->type) {
1015 if (b->vb_ip.af != AF_INET6) goto fail_cmp_v6;
1017
1018 case FR_TYPE_IPV6_ADDR: /* IPv6 Prefix and IPv6 */
1019 return fr_value_box_cidr_cmp_op(op, 16, a->vb_ip.prefix,
1020 (uint8_t const *) &a->vb_ip.addr.v6,
1021 128, (uint8_t const *) &b->vb_ip.addr.v6);
1022
1024 if (b->vb_ip.af != AF_INET6) goto fail_cmp_v6;
1026
1027 case FR_TYPE_IPV6_PREFIX: /* IPv6 Prefix and IPv6 */
1028 return fr_value_box_cidr_cmp_op(op, 16, a->vb_ip.prefix,
1029 (uint8_t const *) &a->vb_ip.addr.v6,
1030 b->vb_ip.prefix, (uint8_t const *) &b->vb_ip.addr.v6);
1031
1032 default:
1033 fr_strerror_const("Cannot compare IPv6 with IPv4 address");
1034 return -1;
1035 }
1036
1038 if (a->vb_ip.af != b->vb_ip.af) goto fail_cmp_v4; /* as good as any */
1039
1040 goto cmp;
1041
1043 if (a->vb_ip.af != b->vb_ip.af) goto fail_cmp_v4; /* as good as any */
1044
1045 if (a->vb_ip.af == AF_INET) goto cmp_prefix_v4;
1046
1047 goto cmp_prefix_v6;
1048
1049 default:
1050 cmp:
1051 compare = fr_value_box_cmp(a, b);
1052 if (compare < -1) { /* comparison error */
1053 return -1;
1054 }
1055 }
1056
1057 /*
1058 * Now do the operator comparison.
1059 */
1060 switch (op) {
1061 case T_OP_CMP_EQ:
1062 return (compare == 0);
1063
1064 case T_OP_NE:
1065 return (compare != 0);
1066
1067 case T_OP_LT:
1068 return (compare < 0);
1069
1070 case T_OP_GT:
1071 return (compare > 0);
1072
1073 case T_OP_LE:
1074 return (compare <= 0);
1075
1076 case T_OP_GE:
1077 return (compare >= 0);
1078
1079 default:
1080 return 0;
1081 }
1082}
1083
1084/** Convert a string value with escape sequences into its binary form
1085 *
1086 * The quote character determines the escape sequences recognised.
1087 *
1088 * - Literal mode ("'" quote char) will unescape:
1089 @verbatim
1090 - \\ - Literal backslash.
1091 - <quote> - The quotation char.
1092 @endverbatim
1093 * - Expanded mode ('"' quote char) will also unescape:
1094 @verbatim
1095 - \a - Alert.
1096 - \b - Backspace.
1097 - \e - Escape character i.e. (\‍)
1098 - \r - Carriage return.
1099 - \n - Newline.
1100 - \t - Tab.
1101 - \v - Vertical tab
1102 - <oct> - An octal escape sequence.
1103 - \x<hex> - A hex escape sequence.
1104 @endverbatim
1105 * - Backtick mode ('`' quote char) identical to expanded mode.
1106 * - Regex mode ('/') identical to expanded mode but two successive
1107 * backslashes will be interpreted as an escape sequence, but not
1108 * unescaped, so that they will be passed to the underlying regex
1109 * library.
1110 * - Verbatim mode ('\0' quote char) copies in to out verbatim.
1111 *
1112 * @note The resulting output may contain embedded \0s.
1113 * @note Unrecognised escape sequences will be copied verbatim.
1114 * @note In and out may point to the same underlying buffer.
1115 * @note Copying will stop early if an unescaped instance of the
1116 * quoting char is found in the input buffer.
1117 *
1118 * @param[out] out Where to write the unescaped string.
1119 * @param[in] in The string to unescape.
1120 * @param[in] inlen Length of input string. Pass SIZE_MAX to copy all data
1121 * in the input buffer.
1122 * @param[in] quote Character around the string, determines unescaping mode.
1123 *
1124 * @return
1125 * - 0 if input string was empty.
1126 * - >0 the number of bytes written to out.
1127 */
1129{
1130 switch (quote) {
1131 default:
1132 break;
1133
1134 case '"':
1135 {
1137 }
1138 case '\'':
1139 {
1141 }
1142
1143 case '`':
1144 {
1146 }
1147
1148 case '/':
1149 {
1151 }
1152 }
1153
1155}
1156
1157/** Convert a string value with escape sequences into its binary form
1158 *
1159 * The quote character determines the escape sequences recognised.
1160 *
1161 * - Literal mode ("'" quote char) will unescape:
1162 @verbatim
1163 - \\ - Literal backslash.
1164 - <quote> - The quotation char.
1165 @endverbatim
1166 * - Expanded mode ('"' quote char) will also unescape:
1167 @verbatim
1168 - \a - Alert.
1169 - \b - Backspace.
1170 - \e - Escape character i.e. (\‍)
1171 - \r - Carriage return.
1172 - \n - Newline.
1173 - \t - Tab.
1174 - \v - Vertical tab
1175 - <oct> - An octal escape sequence.
1176 - \x<hex> - A hex escape sequence.
1177 @endverbatim
1178 * - Backtick mode ('`' quote char) identical to expanded mode.
1179 * - Regex mode ('/') identical to expanded mode but two successive
1180 * backslashes will be interpreted as an escape sequence, but not
1181 * unescaped, so that they will be passed to the underlying regex
1182 * library.
1183 * - Verbatim mode ('\0' quote char) copies in to out verbatim.
1184 *
1185 * @note The resulting output may contain embedded \0s.
1186 * @note Unrecognised escape sequences will be copied verbatim.
1187 * @note In and out may point to the same underlying buffer.
1188 * @note Copying will stop early if an unescaped instance of the
1189 * quoting char is found in the input buffer.
1190 *
1191 * @param[out] out Where to write the unescaped string.
1192 * @param[in] in The string to unescape.
1193 * @param[in] inlen Length of input string. Pass SIZE_MAX to copy all data
1194 * in the input buffer.
1195 * @param[in] quote Character around the string, determines unescaping mode.
1196 *
1197 * @return
1198 * - 0 if input string was empty.
1199 * - >0 the number of bytes written to out.
1200 */
1202{
1203 switch (quote) {
1204 default:
1205 break;
1206
1207 case '"':
1209
1210 case '\'':
1212
1213 case '`':
1215
1216 case '/':
1218 }
1219
1221}
1222
1223/** Performs byte order reversal for types that need it
1224 *
1225 * @param[in] dst Where to write the result. May be the same as src.
1226 * @param[in] src #fr_value_box_t containing an uint32 value.
1227 * @return
1228 * - 0 on success.
1229 * - -1 on failure.
1230 */
1232{
1233 if (!fr_cond_assert(src->type != FR_TYPE_NULL)) return -1;
1234
1235 switch (src->type) {
1236 default:
1237 break;
1238
1239 case FR_TYPE_BOOL:
1240 case FR_TYPE_UINT8:
1241 case FR_TYPE_INT8:
1242 case FR_TYPE_IPV4_ADDR:
1244 case FR_TYPE_IPV6_ADDR:
1248 case FR_TYPE_IFID:
1249 case FR_TYPE_ETHERNET:
1250 case FR_TYPE_SIZE:
1251 fr_value_box_copy(NULL, dst, src);
1252 return 0;
1253
1254 case FR_TYPE_OCTETS:
1255 case FR_TYPE_STRING:
1256 case FR_TYPE_NON_LEAF:
1257 fr_assert_fail(NULL);
1258 return -1; /* shouldn't happen */
1259 }
1260
1261 /*
1262 * If we're not just flipping in place
1263 * initialise the destination box
1264 * with similar meta data as the src.
1265 *
1266 * Don't use the copy meta data function
1267 * here as that doesn't initialise the
1268 * destination box.
1269 */
1270 if (dst != src) fr_value_box_init(dst, src->type, src->enumv, src->tainted);
1271
1272 switch (src->type) {
1273 case FR_TYPE_UINT16:
1274 dst->vb_uint16 = htons(src->vb_uint16);
1275 break;
1276
1277 case FR_TYPE_UINT32:
1278 dst->vb_uint32 = htonl(src->vb_uint32);
1279 break;
1280
1281 case FR_TYPE_UINT64:
1282 dst->vb_uint64 = htonll(src->vb_uint64);
1283 break;
1284
1285 case FR_TYPE_INT16:
1286 dst->vb_int16 = htons(src->vb_int16);
1287 break;
1288
1289 case FR_TYPE_INT32:
1290 dst->vb_int32 = htonl(src->vb_int32);
1291 break;
1292
1293 case FR_TYPE_INT64:
1294 dst->vb_int64 = htonll(src->vb_int64);
1295 break;
1296
1297 case FR_TYPE_DATE:
1298 dst->vb_date = fr_unix_time_wrap(htonll(fr_unix_time_unwrap(src->vb_date)));
1299 break;
1300
1301 case FR_TYPE_TIME_DELTA:
1302 dst->vb_time_delta = fr_time_delta_wrap(htonll(fr_time_delta_unwrap(src->vb_time_delta)));
1303 break;
1304
1305 case FR_TYPE_FLOAT32:
1306 dst->vb_float32 = htonl((uint32_t)src->vb_float32);
1307 break;
1308
1309 case FR_TYPE_FLOAT64:
1310 dst->vb_float64 = htonll((uint64_t)src->vb_float64);
1311 break;
1312
1313 default:
1314 fr_assert_fail(NULL);
1315 return -1; /* shouldn't happen */
1316 }
1317
1318 return 0;
1319}
1320
1321/** Get the size of the value held by the fr_value_box_t
1322 *
1323 * This is the length of the NETWORK presentation
1324 */
1326{
1327 switch (value->type) {
1329 if (value->enumv) {
1330 /*
1331 * Fixed-width fields.
1332 */
1333 if (value->enumv->flags.length) {
1334 return value->enumv->flags.length;
1335 }
1336
1337 /*
1338 * Clamp length at maximum we're allowed to encode.
1339 */
1340 if (da_is_length_field(value->enumv)) {
1341 if (value->enumv->flags.subtype == FLAG_LENGTH_UINT8) {
1342 if (value->vb_length > 255) return 255;
1343
1344 } else if (value->enumv->flags.subtype == FLAG_LENGTH_UINT16) {
1345 if (value->vb_length > 65535) return 65535;
1346 }
1347 }
1348 }
1349 return value->vb_length;
1350
1351 /*
1352 * These can have different encodings, depending on the underlying protocol.
1353 */
1354 case FR_TYPE_DATE:
1355 case FR_TYPE_TIME_DELTA:
1356 if (value->enumv) return value->enumv->flags.length;
1358
1359 default:
1360 return network_min_size(value->type);
1361 }
1362}
1363
1364/** Encode a single value box, serializing its contents in generic network format
1365 *
1366 * The serialized form of #fr_value_box_t may not match the requirements of your protocol
1367 * completely. In cases where they do not, you should overload specific types in the
1368 * function calling #fr_value_box_to_network.
1369 *
1370 * The general serialization rules are:
1371 *
1372 * - Octets are encoded in binary form (not hex).
1373 * - Strings are encoded without the trailing \0 byte.
1374 * - Integers are encoded big-endian.
1375 * - Bools are encoded using one byte, with value 0x00 (false) or 0x01 (true).
1376 * - Signed integers are encoded two's complement, with the MSB as the sign bit.
1377 * Byte order is big-endian.
1378 * - Network addresses are encoded big-endian.
1379 * - IPv4 prefixes are encoded with 1 byte for the prefix, then 4 bytes of address.
1380 * - IPv6 prefixes are encoded with 1 byte for the scope_id, 1 byte for the prefix,
1381 * and 16 bytes of address.
1382 * - Floats are encoded in IEEE-754 format with a big-endian byte order. We rely
1383 * on the fact that the C standards require floats to be represented in IEEE-754
1384 * format in memory.
1385 * - Dates are encoded as 16/32/64-bit unsigned UNIX timestamps.
1386 * - time_deltas are encoded as 16/32/64-bit signed integers.
1387 *
1388 * #FR_TYPE_SIZE is not encodable, as it is system specific.
1389 *
1390 * This function will not encode structural types (TLVs, VSAs etc...). These are usually
1391 * specific to the protocol anyway.
1392 *
1393 * All of the dictionary rules are respected. string/octets can have
1394 * a fixed length (which is zero-padded if necessary), or can have an
1395 * 8/16-bit "length" prefix.
1396 *
1397 * @param[out] dbuff Where to write serialized data.
1398 * @param[in] value to encode.
1399 * @return
1400 * - 0 no bytes were written.
1401 * - >0 the number of bytes written to out.
1402 * - <0 the number of bytes we'd need in dbuff to complete the operation.
1403 */
1405{
1406 size_t min, max;
1407 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1408
1409 /*
1410 * We cannot encode structural types here.
1411 */
1412 if (!fr_type_is_leaf(value->type)) {
1413 unsupported:
1414 fr_strerror_printf("%s: Cannot encode type \"%s\"",
1415 __FUNCTION__,
1416 fr_type_to_str(value->type));
1418 }
1419
1420 /*
1421 * Variable length types
1422 */
1423 switch (value->type) {
1424 case FR_TYPE_OCTETS:
1425 case FR_TYPE_STRING:
1426 max = value->vb_length;
1427
1428 /*
1429 * Sometimes variable length *inside* the server
1430 * has maximum length on the wire.
1431 */
1432 if (value->enumv) {
1433 if (value->enumv->flags.length) {
1434 /*
1435 * The field is fixed size, and the data is smaller than that, We zero-pad the field.
1436 */
1437 if (max < value->enumv->flags.length) {
1438 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *)value->datum.ptr, max);
1439 FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, value->enumv->flags.length - max);
1440 return fr_dbuff_set(dbuff, &work_dbuff);
1441
1442 } else if (max > value->enumv->flags.length) {
1443 /*
1444 * Truncate the input to the maximum allowed length.
1445 */
1446 max = value->enumv->flags.length;
1447 }
1448
1449 } else if (da_is_length_field(value->enumv)) {
1450 /*
1451 * Truncate the output to the max allowed for this field and encode the length.
1452 */
1453 if (value->enumv->flags.subtype == FLAG_LENGTH_UINT8) {
1454 if (max > 255) max = 255;
1455 FR_DBUFF_IN_RETURN(&work_dbuff, (uint8_t) max);
1456
1457 } else if (value->enumv->flags.subtype == FLAG_LENGTH_UINT16) {
1458 if (max > 65536) max = 65535;
1459 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t) max);
1460
1461 } else {
1462 return -1;
1463 }
1464 }
1465 }
1466
1467 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *)value->datum.ptr, max);
1468 return fr_dbuff_set(dbuff, &work_dbuff);
1469
1470 /*
1471 * The data can be encoded in a variety of widths.
1472 */
1473 case FR_TYPE_DATE:
1474 case FR_TYPE_TIME_DELTA:
1475 if (value->enumv) {
1476 min = value->enumv->flags.length;
1477 } else {
1478 min = 4;
1479 }
1480 break;
1481
1482 default:
1483 min = network_min_size(value->type);
1484 break;
1485 }
1486
1487 /*
1488 * We have to encode actual data here.
1489 */
1490 fr_assert(min > 0);
1491
1492 switch (value->type) {
1493 case FR_TYPE_IPV4_ADDR:
1494 ipv4addr:
1495 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff,
1496 (uint8_t const *)&value->vb_ip.addr.v4.s_addr,
1497 sizeof(value->vb_ip.addr.v4.s_addr));
1498 break;
1499 /*
1500 * Needs special mangling
1501 */
1503 ipv4prefix:
1504 FR_DBUFF_IN_RETURN(&work_dbuff, value->vb_ip.prefix);
1505 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff,
1506 (uint8_t const *)&value->vb_ip.addr.v4.s_addr,
1507 sizeof(value->vb_ip.addr.v4.s_addr));
1508 break;
1509
1510 case FR_TYPE_IPV6_ADDR:
1511 ipv6addr:
1512 if (value->vb_ip.scope_id > 0) FR_DBUFF_IN_RETURN(&work_dbuff, value->vb_ip.scope_id);
1513 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value->vb_ip.addr.v6.s6_addr, sizeof(value->vb_ip.addr.v6.s6_addr));
1514 break;
1515
1517 ipv6prefix:
1518 if (value->vb_ip.scope_id > 0) FR_DBUFF_IN_RETURN(&work_dbuff, value->vb_ip.scope_id);
1519 FR_DBUFF_IN_RETURN(&work_dbuff, value->vb_ip.prefix);
1520 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value->vb_ip.addr.v6.s6_addr, sizeof(value->vb_ip.addr.v6.s6_addr));
1521 break;
1522
1523 case FR_TYPE_BOOL:
1524 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, value->datum.boolean);
1525 break;
1526
1528 switch (value->vb_ip.af) {
1529 case AF_INET:
1530 goto ipv4addr;
1531
1532 case AF_INET6:
1533 goto ipv6addr;
1534
1535 default:
1536 break;
1537 }
1538
1539 fr_strerror_const("Combo IP value missing af");
1540 return 0;
1541
1543 switch (value->vb_ip.af) {
1544 case AF_INET:
1545 goto ipv4prefix;
1546
1547 case AF_INET6:
1548 goto ipv6prefix;
1549
1550 default:
1551 break;
1552 }
1553
1554 fr_strerror_const("Combo IP value missing af");
1555 return 0;
1556
1557 /*
1558 * Already in network byte-order
1559 */
1560 case FR_TYPE_IFID:
1561 case FR_TYPE_ETHERNET:
1562 case FR_TYPE_UINT8:
1563 case FR_TYPE_INT8:
1565 break;
1566
1567 /*
1568 * Needs a bytesex operation
1569 */
1570 case FR_TYPE_UINT16:
1571 case FR_TYPE_UINT32:
1572 case FR_TYPE_UINT64:
1573 case FR_TYPE_INT16:
1574 case FR_TYPE_INT32:
1575 case FR_TYPE_INT64:
1576 case FR_TYPE_FLOAT32:
1577 case FR_TYPE_FLOAT64:
1578 {
1579 fr_value_box_t tmp;
1580
1581 fr_value_box_hton(&tmp, value);
1582
1583 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, fr_value_box_raw(&tmp, value->type), min);
1584 }
1585 break;
1586
1587 /*
1588 * Dates and deltas are stored internally as
1589 * 64-bit nanoseconds. We have to convert to the
1590 * network format. First by resolution (ns, us,
1591 * ms, s), and then by size (16/32/64-bit).
1592 */
1593 case FR_TYPE_DATE:
1594 {
1595 uint64_t date = 0;
1596 fr_time_res_t res;
1597
1598 if (!value->enumv) {
1599 res = FR_TIME_RES_SEC;
1600 } else {
1601 res = value->enumv->flags.flag_time_res;
1602 }
1603 date = fr_unix_time_to_integer(value->vb_date, res);
1604
1605 if (!value->enumv) {
1606 goto date_size4;
1607
1608 } else switch (value->enumv->flags.length) {
1609 case 2:
1610 if (date > UINT16_MAX) date = UINT16_MAX;
1611 FR_DBUFF_IN_RETURN(&work_dbuff, (int16_t) date);
1612 break;
1613
1614 date_size4:
1615 case 4:
1616 if (date > UINT32_MAX) date = UINT32_MAX;
1617 FR_DBUFF_IN_RETURN(&work_dbuff, (int32_t) date);
1618 break;
1619
1620 case 8:
1621 FR_DBUFF_IN_RETURN(&work_dbuff, date);
1622 break;
1623
1624 default:
1625 goto unsupported;
1626 }
1627
1628 }
1629 break;
1630
1631 case FR_TYPE_TIME_DELTA:
1632 {
1633 int64_t date = 0; /* may be negative */
1635 if (value->enumv) res = value->enumv->flags.flag_time_res;
1636
1637 date = fr_time_delta_to_integer(value->vb_time_delta, res);
1638
1639 if (!value->enumv) {
1640 goto delta_size4;
1641
1642 } else if (!value->enumv->flags.is_unsigned) {
1643 switch (value->enumv->flags.length) {
1644 case 2:
1645 if (date < INT16_MIN) {
1646 date = INT16_MIN;
1647 } else if (date > INT16_MAX) {
1648 date = INT16_MAX;
1649 }
1650 FR_DBUFF_IN_RETURN(&work_dbuff, (int16_t)date);
1651 break;
1652
1653 delta_size4:
1654 case 4:
1655 if (date < INT32_MIN) {
1656 date = INT32_MIN;
1657 } else if (date > INT32_MAX) {
1658 date = INT32_MAX;
1659 }
1660 FR_DBUFF_IN_RETURN(&work_dbuff, (int32_t)date);
1661 break;
1662
1663 case 8:
1664 FR_DBUFF_IN_RETURN(&work_dbuff, (int64_t)date);
1665 break;
1666
1667 default:
1668 goto unsupported;
1669 }
1670 } else { /* time delta is unsigned! */
1671 switch (value->enumv->flags.length) {
1672 case 2:
1673 if (date < 0) {
1674 date = 0;
1675 } else if (date > UINT16_MAX) {
1676 date = UINT16_MAX;
1677 }
1678 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t)date);
1679 break;
1680
1681 case 4:
1682 if (date < 0) {
1683 date = 0;
1684 } else if (date > UINT32_MAX) {
1685 date = UINT32_MAX;
1686 }
1687 FR_DBUFF_IN_RETURN(&work_dbuff, (uint32_t)date);
1688 break;
1689
1690 case 8:
1691 FR_DBUFF_IN_RETURN(&work_dbuff, (uint64_t)date);
1692 break;
1693
1694 default:
1695 goto unsupported;
1696 }
1697 }
1698 }
1699 break;
1700
1701 case FR_TYPE_OCTETS:
1702 case FR_TYPE_STRING:
1703 case FR_TYPE_SIZE:
1704 case FR_TYPE_NON_LEAF:
1705 goto unsupported;
1706 }
1707
1708 return fr_dbuff_set(dbuff, &work_dbuff);
1709}
1710
1711/** Decode a #fr_value_box_t from serialized binary data
1712 *
1713 * The general deserialization rules are:
1714 *
1715 * - Octets are decoded in binary form (not hex).
1716 * - Strings are decoded without the trailing \0 byte. Strings must consist only of valid UTF8 chars.
1717 * - Integers are decoded big-endian.
1718 * - Bools are decoded using one byte, with value 0x00 (false) or 0x01 (true).
1719 * - Signed integers are decoded two's complement, with the MSB as the sign bit.
1720 * Byte order is big-endian.
1721 * - Network addresses are decoded big-endian.
1722 * - IPv4 prefixes are decoded with 1 byte for the prefix, then 4 bytes of address.
1723 * - IPv6 prefixes are decoded with 1 byte for the scope_id, 1 byte for the prefix,
1724 * and 16 bytes of address.
1725 * - Floats are decoded in IEEE-754 format with a big-endian byte order. We rely
1726 * on the fact that the C standards require floats to be represented in IEEE-754
1727 * format in memory.
1728 * - Dates are decoded as 32bit unsigned UNIX timestamps.
1729 *
1730 * All of the dictionary rules are respected. string/octets can have
1731 * a fixed length, or can have an 8/16-bit "length" prefix. If the
1732 * enumv is not an array, then the input # len MUST be the correct size
1733 * (not too large or small), otherwise an error is returned.
1734 *
1735 * If the enumv is an array, then the input must have the minimum
1736 * length, and the number of bytes decoded is capped at the maximum
1737 * length allowed to be decoded. This behavior allows the caller to
1738 * decode an array of values simply by calling this function in a
1739 * loop.
1740 *
1741 * @param[in] ctx Where to allocate any talloc buffers required.
1742 * @param[out] dst value_box to write the result to.
1743 * @param[in] type to decode data to.
1744 * @param[in] enumv Aliases for values.
1745 * @param[in] dbuff Binary data to decode.
1746 * @param[in] len Length of data to decode. For fixed length types we only
1747 * decode complete values.
1748 * @param[in] tainted Whether the value came from a trusted source.
1749 * @return
1750 * - >= 0 The number of bytes consumed.
1751 * - <0 - The negative offset where the error occurred.
1752 * - FR_VALUE_BOX_NET_OOM (negative value) - Out of memory.
1753 */
1755 fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv,
1756 fr_dbuff_t *dbuff, size_t len,
1757 bool tainted)
1758{
1759 size_t min, max;
1760 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1761
1763 max = network_max_size(type);
1764
1765 if (len < min) {
1766 fr_strerror_printf("Got truncated value parsing type \"%s\". "
1767 "Expected length >= %zu bytes, got %zu bytes",
1769 min, len);
1770 return -(len);
1771 }
1772
1773 /*
1774 * For array entries, we only decode one value at a time.
1775 */
1776 if (len > max) {
1777 if (enumv && !enumv->flags.array) {
1778 fr_strerror_printf("Found trailing garbage parsing type \"%s\". "
1779 "Expected length <= %zu bytes, got %zu bytes",
1781 max, len);
1782 return -(max);
1783 }
1784
1785 len = max;
1786 }
1787
1788 /*
1789 * String / octets are special.
1790 */
1792 size_t newlen = len;
1793 size_t offset = 0;
1794
1795 /*
1796 * Decode fixed-width fields.
1797 */
1798 if (enumv) {
1799 if (enumv->flags.length) {
1800 newlen = enumv->flags.length;
1801
1802 } else if (da_is_length_field(enumv)) {
1803 /*
1804 * Or fields with a length prefix.
1805 */
1806 if (enumv->flags.subtype == FLAG_LENGTH_UINT8) {
1807 uint8_t num = 0;
1808
1809 FR_DBUFF_OUT_RETURN(&num, &work_dbuff);
1810 newlen = num;
1811 offset = 1;
1812
1813 } else if (enumv->flags.subtype == FLAG_LENGTH_UINT16) {
1814 uint16_t num = 0;
1815
1816 FR_DBUFF_OUT_RETURN(&num, &work_dbuff);
1817 newlen = num;
1818 offset = 2;
1819
1820 } else {
1821 return -1;
1822 }
1823 }
1824 }
1825
1826 /*
1827 * If we need more data than exists, that's an error.
1828 *
1829 * Otherwise, bound the decoding to the count we found.
1830 */
1831 if (newlen > len) return -(newlen + offset);
1832 len = newlen;
1833
1834 switch (type) {
1835 case FR_TYPE_STRING:
1836 if (fr_value_box_bstrndup_dbuff(ctx, dst, enumv, &work_dbuff, len, tainted) < 0) {
1837 return FR_VALUE_BOX_NET_OOM;
1838 }
1839 return fr_dbuff_set(dbuff, &work_dbuff);
1840
1841 case FR_TYPE_OCTETS:
1842 if (fr_value_box_memdup_dbuff(ctx, dst, enumv, &work_dbuff, len, tainted) < 0) {
1843 return FR_VALUE_BOX_NET_OOM;
1844 }
1845 return fr_dbuff_set(dbuff, &work_dbuff);
1846
1847 default:
1848 return -1;
1849 }
1850 }
1851
1852 /*
1853 * Pre-Initialise box for non-variable types
1854 */
1855 fr_value_box_init(dst, type, enumv, tainted);
1856 switch (type) {
1857 /*
1858 * Already in network byte order
1859 */
1860 case FR_TYPE_IPV4_ADDR:
1861 ipv4addr:
1862 dst->vb_ip = (fr_ipaddr_t){
1863 .af = AF_INET,
1864 .prefix = 32,
1865 };
1866 FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *)&dst->vb_ip.addr.v4, &work_dbuff, len);
1867 break;
1868
1870 ipv4prefix:
1871 dst->vb_ip = (fr_ipaddr_t){
1872 .af = AF_INET,
1873 };
1874 FR_DBUFF_OUT_RETURN(&dst->vb_ip.prefix, &work_dbuff);
1875 FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *)&dst->vb_ip.addr.v4, &work_dbuff, len - 1);
1876 break;
1877
1878 case FR_TYPE_IPV6_ADDR:
1879 ipv6addr:
1880 dst->vb_ip = (fr_ipaddr_t){
1881 .af = AF_INET6,
1882 .scope_id = 0,
1883 .prefix = 128
1884 };
1885 if (len == max) {
1886 uint8_t scope_id = 0;
1887
1888 FR_DBUFF_OUT_RETURN(&scope_id, &work_dbuff);
1889 dst->vb_ip.scope_id = scope_id;
1890 len--;
1891 }
1892 FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *)&dst->vb_ip.addr.v6, &work_dbuff, len);
1893 break;
1894
1896 ipv6prefix:
1897 dst->vb_ip = (fr_ipaddr_t){
1898 .af = AF_INET6,
1899 .scope_id = 0,
1900 };
1901 if (len == max) {
1902 uint8_t scope_id = 0;
1903
1904 FR_DBUFF_OUT_RETURN(&scope_id, &work_dbuff);
1905 dst->vb_ip.scope_id = scope_id;
1906 len--;
1907 }
1908 FR_DBUFF_OUT_RETURN(&dst->vb_ip.prefix, &work_dbuff);
1909 FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *)&dst->vb_ip.addr.v6, &work_dbuff, len - 1);
1910 break;
1911
1913 if ((len >= network_min_size(FR_TYPE_IPV6_ADDR)) &&
1914 (len <= network_max_size(FR_TYPE_IPV6_ADDR))) goto ipv6addr; /* scope is optional */
1915 else if ((len >= network_min_size(FR_TYPE_IPV4_ADDR)) &&
1916 (len <= network_max_size(FR_TYPE_IPV4_ADDR))) goto ipv4addr;
1917 fr_strerror_const("Invalid combo ip address value");
1918 return 0;
1919
1921 if ((len >= network_min_size(FR_TYPE_IPV6_PREFIX)) &&
1922 (len <= network_max_size(FR_TYPE_IPV6_PREFIX))) goto ipv6prefix; /* scope is optional */
1923 else if ((len >= network_min_size(FR_TYPE_IPV4_PREFIX)) &&
1924 (len <= network_max_size(FR_TYPE_IPV4_PREFIX))) goto ipv4prefix;
1925 fr_strerror_const("Invalid combo ip prefix value");
1926 return 0;
1927
1928 case FR_TYPE_BOOL:
1929 {
1930 uint8_t val = 0;
1931
1932 FR_DBUFF_OUT_RETURN(&val, &work_dbuff);
1933 dst->datum.boolean = (val != 0);
1934 }
1935 break;
1936
1937 case FR_TYPE_IFID:
1938 case FR_TYPE_ETHERNET:
1939 FR_DBUFF_OUT_MEMCPY_RETURN(fr_value_box_raw(dst, type), &work_dbuff, len);
1940 break;
1941
1942 case FR_TYPE_UINT8:
1943 FR_DBUFF_OUT_RETURN(&dst->vb_uint8, &work_dbuff);
1944 break;
1945
1946 case FR_TYPE_UINT16:
1947 FR_DBUFF_OUT_RETURN(&dst->vb_uint16, &work_dbuff);
1948 break;
1949
1950 case FR_TYPE_UINT32:
1951 FR_DBUFF_OUT_RETURN(&dst->vb_uint32, &work_dbuff);
1952 break;
1953
1954 case FR_TYPE_UINT64:
1955 FR_DBUFF_OUT_RETURN(&dst->vb_uint64, &work_dbuff);
1956 break;
1957
1958 case FR_TYPE_INT8:
1959 FR_DBUFF_OUT_RETURN(&dst->vb_int8, &work_dbuff);
1960 break;
1961
1962 case FR_TYPE_INT16:
1963 FR_DBUFF_OUT_RETURN(&dst->vb_int16, &work_dbuff);
1964 break;
1965
1966 case FR_TYPE_INT32:
1967 FR_DBUFF_OUT_RETURN(&dst->vb_int32, &work_dbuff);
1968 break;
1969
1970 case FR_TYPE_INT64:
1971 FR_DBUFF_OUT_RETURN(&dst->vb_int64, &work_dbuff);
1972 break;
1973
1974 case FR_TYPE_FLOAT32:
1975 FR_DBUFF_OUT_RETURN(&dst->vb_float32, &work_dbuff);
1976 break;
1977
1978 case FR_TYPE_FLOAT64:
1979 FR_DBUFF_OUT_RETURN(&dst->vb_float64, &work_dbuff);
1980 break;
1981
1982 /*
1983 * Dates and deltas are stored internally as
1984 * 64-bit nanoseconds. We have to convert from
1985 * the network format. First by size
1986 * (16/32/64-bit), and then by resolution (ns,
1987 * us, ms, s).
1988 */
1989 case FR_TYPE_DATE:
1990 {
1991 size_t length = 4;
1992 fr_time_res_t precision = FR_TIME_RES_SEC;
1993 uint64_t date;
1994
1995 if (enumv) {
1996 length = enumv->flags.length;
1997 precision = (fr_time_res_t)enumv->flags.flag_time_res;
1998 }
1999
2000 /*
2001 * Input data doesn't match what we were told we
2002 * need.
2003 */
2004 if (len > length) return -(length);
2005
2006 dst->enumv = enumv;
2007
2008 FR_DBUFF_OUT_UINT64V_RETURN(&date, &work_dbuff, length);
2009
2010 if (!fr_multiply(&date, date, fr_time_multiplier_by_res[precision])) {
2011 fr_strerror_const("date would overflow");
2012 return 0;
2013 }
2014
2015 dst->vb_date = fr_unix_time_wrap(date);
2016 }
2017 break;
2018
2019 case FR_TYPE_TIME_DELTA:
2020 {
2021 size_t length = 4;
2022 fr_time_res_t precision = FR_TIME_RES_SEC;
2023 int64_t date;
2024
2025 if (enumv) {
2026 length = enumv->flags.length;
2027 precision = (fr_time_res_t)enumv->flags.flag_time_res;
2028 }
2029
2030 /*
2031 * Input data doesn't match what we were told we
2032 * need.
2033 */
2034 if (len > length) return -(length);
2035
2036 dst->enumv = enumv;
2037
2038 if (!enumv || !enumv->flags.is_unsigned) {
2039 FR_DBUFF_OUT_INT64V_RETURN(&date, &work_dbuff, length);
2040 } else {
2041 uint64_t tmp;
2042
2043 /*
2044 * Else it's an unsigned time delta, but
2045 * we do have to clamp it at the max
2046 * value for a signed 64-bit integer.
2047 */
2048 FR_DBUFF_OUT_UINT64V_RETURN(&tmp, &work_dbuff, length);
2049
2050 if (tmp > INT64_MAX) tmp = INT64_MAX;
2051
2052 date = tmp;
2053 }
2054
2055 dst->vb_time_delta = fr_time_delta_wrap(fr_time_scale(date, precision));
2056 }
2057 break;
2058
2059 case FR_TYPE_STRING:
2060 case FR_TYPE_OCTETS:
2061 break; /* Already dealt with */
2062
2063 case FR_TYPE_SIZE:
2064 case FR_TYPE_NON_LEAF:
2065 fr_strerror_printf("Cannot decode type \"%s\" - Is not a value",
2067 break;
2068 }
2069
2070 return fr_dbuff_set(dbuff, &work_dbuff);
2071}
2072
2073/** Get a key from a value box
2074 *
2075 * @param[in,out] out - set to a small buffer on input. If the callback has more data
2076 * than is available here, the callback can update "out" to point elsewhere
2077 * @param[in,out] outlen The number of bits available in the initial buffer. On output,
2078 * the number of bits available in the key
2079 * @param[in] value the value box which contains the key
2080 * @return
2081 * - <0 on error
2082 * - 0 on success
2083 */
2085{
2086 ssize_t slen;
2087 fr_dbuff_t dbuff;
2088
2089 switch (value->type) {
2090 case FR_TYPE_BOOL:
2091 if (*outlen < 8) return -1;
2092
2093 *out[0] = (value->vb_bool) << 7;
2094 *outlen = 1;
2095 break;
2096
2098 if (*outlen < (fr_value_box_network_sizes[value->type][1] * 8)) return -1;
2099
2100 /*
2101 * Integers are put into network byte order.
2102 */
2103 fr_dbuff_init(&dbuff, *out, *outlen >> 3);
2104
2105 slen = fr_value_box_to_network(&dbuff, value);
2106 if (slen < 0) return -1;
2107 *outlen = slen * 8; /* bits not bytes */
2108 break;
2109
2110 case FR_TYPE_IP:
2111 /*
2112 * IPs are already in network byte order.
2113 */
2114 *out = UNCONST(uint8_t *, &value->vb_ip.addr);
2115 *outlen = value->vb_ip.prefix;
2116 break;
2117
2118 case FR_TYPE_STRING:
2119 case FR_TYPE_OCTETS:
2120 *out = value->datum.ptr;
2121 *outlen = value->vb_length * 8;
2122 break;
2123
2124 case FR_TYPE_ETHERNET:
2125 *out = UNCONST(uint8_t *, &value->vb_ether[0]);
2126 *outlen = sizeof(value->vb_ether) * 8;
2127 break;
2128
2129 default:
2130 fr_strerror_printf("Invalid data type '%s' for getting key",
2131 fr_type_to_str(value->type));
2132 return -1;
2133 }
2134
2135 return 0;
2136}
2137
2138/** Convert octets to a fixed size value box value
2139 *
2140 * All fixed size types are allowed.
2141 *
2142 * @param dst Where to write result of casting.
2143 * @param dst_type to cast to.
2144 * @param dst_enumv enumeration values.
2145 * @param src Input data.
2146 */
2148 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2149 fr_value_box_t const *src)
2150{
2151 uint8_t *ptr;
2152
2153 if (!fr_type_is_fixed_size(dst_type)) if (!fr_cond_assert(false)) return -1;
2154
2155 if (src->vb_length > network_max_size(dst_type)) {
2156 fr_strerror_printf("Invalid cast from %s to %s. Source length %zu is greater than "
2157 "destination type size %zu",
2158 fr_type_to_str(src->type),
2159 fr_type_to_str(dst_type),
2160 src->vb_length,
2161 network_max_size(dst_type));
2162 return -1;
2163 }
2164
2165 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2166
2167 /*
2168 * No data to copy means just reset it to zero.
2169 */
2170 if (!src->vb_length) return 0;
2171
2172 ptr = (uint8_t *) &dst->datum;
2173
2174 /*
2175 * If the source is too small, just left-fill with zeroes.
2176 */
2177 if (src->vb_length < network_min_size(dst_type)) {
2178 ptr += network_min_size(dst_type) - src->vb_length;
2179 }
2180
2181 /*
2182 * Copy the raw octets into the datum of a value_box
2183 * inverting bytesex for uint32s (if LE).
2184 */
2185 memcpy(ptr, src->vb_octets, src->vb_length);
2186 fr_value_box_hton(dst, dst);
2187
2188 return 0;
2189}
2190
2191/** v4 to v6 mapping prefix
2192 *
2193 * Part of the IPv6 range is allocated to represent IPv4 addresses.
2194 */
2195static uint8_t const v4_v6_map[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2196 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
2197
2198
2199/** Convert any supported type to a string
2200 *
2201 * All non-structural types are allowed.
2202 *
2203 * @param ctx unused.
2204 * @param dst Where to write result of casting.
2205 * @param dst_type to cast to.
2206 * @param dst_enumv enumeration values.
2207 * @param src Input data.
2208 */
2209static inline int fr_value_box_cast_to_strvalue(TALLOC_CTX *ctx, fr_value_box_t *dst,
2210 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2211 fr_value_box_t const *src)
2212{
2213 if (!fr_cond_assert(dst_type == FR_TYPE_STRING)) return -1;
2214
2215 switch (src->type) {
2216 /*
2217 * The presentation format of octets is hex
2218 * What we actually want here is the raw string
2219 */
2220 case FR_TYPE_OCTETS:
2221 return fr_value_box_bstrndup(ctx, dst, dst_enumv,
2222 (char const *)src->vb_octets, src->vb_length, src->tainted);
2223
2224 case FR_TYPE_GROUP:
2226 dst, UNCONST(fr_value_box_list_t *, &src->vb_group),
2229 SIZE_MAX);
2230
2231 /*
2232 * Get the presentation format
2233 */
2234 default:
2235 {
2236 char *str;
2237
2238 fr_value_box_aprint(ctx, &str, src, NULL);
2239 if (unlikely(!str)) return -1;
2240
2241 return fr_value_box_bstrdup_buffer_shallow(NULL, dst, dst_enumv, str, src->tainted);
2242 }
2243 }
2244}
2245
2246/** Convert any supported type to octets
2247 *
2248 * All non-structural types are allowed.
2249 *
2250 * @param ctx unused.
2251 * @param dst Where to write result of casting.
2252 * @param dst_type to cast to.
2253 * @param dst_enumv enumeration values.
2254 * @param src Input data.
2255 */
2256static inline int fr_value_box_cast_to_octets(TALLOC_CTX *ctx, fr_value_box_t *dst,
2257 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2258 fr_value_box_t const *src)
2259{
2260 if (!fr_cond_assert(dst_type == FR_TYPE_OCTETS)) return -1;
2261
2262 switch (src->type) {
2263 /*
2264 * <string> (excluding terminating \0)
2265 */
2266 case FR_TYPE_STRING:
2267 if (fr_value_box_memdup(ctx, dst, dst_enumv,
2268 (uint8_t const *)src->vb_strvalue, src->vb_length, src->tainted) < 0) {
2269 return -1;
2270 }
2271 return 0;
2272
2273 case FR_TYPE_GROUP:
2275 dst, UNCONST(fr_value_box_list_t *, &src->vb_group),
2278 SIZE_MAX);
2279 /*
2280 * <4 bytes address>
2281 */
2282 case FR_TYPE_IPV4_ADDR:
2283 return fr_value_box_memdup(ctx, dst, dst_enumv,
2284 (uint8_t const *)&src->vb_ip.addr.v4.s_addr,
2285 sizeof(src->vb_ip.addr.v4.s_addr), src->tainted);
2286
2287 /*
2288 * <1 uint8 prefix> + <4 bytes address>
2289 */
2291 {
2292 uint8_t *bin;
2293
2294 if (fr_value_box_mem_alloc(ctx, &bin, dst, dst_enumv,
2295 sizeof(src->vb_ip.addr.v4.s_addr) + 1, src->tainted) < 0) return -1;
2296
2297 bin[0] = src->vb_ip.prefix;
2298 memcpy(&bin[1], (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2299 }
2300 return 0;
2301
2302 /*
2303 * <16 bytes address>
2304 */
2305 case FR_TYPE_IPV6_ADDR:
2306 return fr_value_box_memdup(ctx, dst, dst_enumv,
2307 (uint8_t const *)src->vb_ip.addr.v6.s6_addr,
2308 sizeof(src->vb_ip.addr.v6.s6_addr), src->tainted);
2309
2310 /*
2311 * <1 uint8 prefix> + <1 uint8 scope> + <16 bytes address>
2312 */
2314 {
2315 uint8_t *bin;
2316
2317 if (fr_value_box_mem_alloc(ctx, &bin, dst, dst_enumv,
2318 sizeof(src->vb_ip.addr.v6.s6_addr) + 2, src->tainted) < 0) return -1;
2319 bin[0] = src->vb_ip.scope_id;
2320 bin[1] = src->vb_ip.prefix;
2321 memcpy(&bin[2], src->vb_ip.addr.v6.s6_addr, sizeof(src->vb_ip.addr.v6.s6_addr));
2322 }
2323 return 0;
2324
2325 /*
2326 * Get the raw binary in memory representation
2327 */
2328 case FR_TYPE_NUMERIC:
2329 {
2330 fr_value_box_t tmp;
2331
2332 fr_value_box_hton(&tmp, src); /* Flip any numeric representations */
2333 return fr_value_box_memdup(ctx, dst, dst_enumv,
2334 fr_value_box_raw(&tmp, src->type),
2335 fr_value_box_field_sizes[src->type], src->tainted);
2336 }
2337
2338 default:
2339 /* Not the same talloc_memdup call as above. The above memdup reads data from the dst */
2340 return fr_value_box_memdup(ctx, dst, dst_enumv,
2341 fr_value_box_raw(src, src->type),
2342 fr_value_box_field_sizes[src->type], src->tainted);
2343 }
2344}
2345
2346#define CAST_IP_FIX_COMBO \
2347 case FR_TYPE_COMBO_IP_ADDR: \
2348 if (src->vb_ip.af == AF_INET) { \
2349 src_type = FR_TYPE_IPV4_ADDR; \
2350 } else if (src->vb_ip.af == AF_INET6) { \
2351 src_type = FR_TYPE_IPV6_ADDR; \
2352 } \
2353 break; \
2354 case FR_TYPE_COMBO_IP_PREFIX: \
2355 if (src->vb_ip.af == AF_INET) { \
2356 src_type = FR_TYPE_IPV4_PREFIX; \
2357 } else if (src->vb_ip.af == AF_INET6) { \
2358 src_type = FR_TYPE_IPV6_PREFIX; \
2359 } \
2360 break
2361
2362
2363/** Convert any supported type to an IPv4 address
2364 *
2365 * Allowed input types are:
2366 * - FR_TYPE_IPV6_ADDR (with v4 prefix).
2367 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2368 * - FR_TYPE_IPV6_PREFIX (with v4 prefix and 128bit mask).
2369 * - FR_TYPE_OCTETS (of length 4).
2370 * - FR_TYPE_UINT32
2371 *
2372 * @param ctx unused.
2373 * @param dst Where to write result of casting.
2374 * @param dst_type to cast to.
2375 * @param dst_enumv enumeration values.
2376 * @param src Input data.
2377 */
2378static inline int fr_value_box_cast_to_ipv4addr(TALLOC_CTX *ctx, fr_value_box_t *dst,
2379 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2380 fr_value_box_t const *src)
2381{
2382 fr_type_t src_type = src->type;
2383
2384 fr_assert(dst_type == FR_TYPE_IPV4_ADDR);
2385
2386 switch (src_type) {
2387 case FR_TYPE_STRING:
2388 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2389 src->vb_strvalue, src->vb_length,
2390 NULL, src->tainted);
2391
2393
2394 default:
2395 break;
2396 }
2397
2398 /*
2399 * Pre-initialise box for non-variable types
2400 */
2401 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2402 dst->vb_ip.af = AF_INET;
2403 dst->vb_ip.prefix = 32;
2404 dst->vb_ip.scope_id = 0;
2405
2406 switch (src_type) {
2407 case FR_TYPE_IPV6_ADDR:
2408 if (memcmp(src->vb_ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
2409 bad_v6_prefix_map:
2410 fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
2411 fr_type_to_str(src->type),
2412 fr_type_to_str(dst_type));
2413 return -1;
2414 }
2415
2416 memcpy(&dst->vb_ip.addr.v4, &src->vb_ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
2417 sizeof(dst->vb_ip.addr.v4));
2418
2419 break;
2420
2422 if (src->vb_ip.prefix != 32) {
2423 fr_strerror_printf("Invalid cast from %s to %s. Only /32 (not %i/) prefixes may be "
2424 "cast to IP address types",
2425 fr_type_to_str(src->type),
2426 fr_type_to_str(dst_type),
2427 src->vb_ip.prefix);
2428 return -1;
2429 }
2431
2432 case FR_TYPE_IPV4_ADDR: /* Needed for handling combo addresses */
2433 memcpy(&dst->vb_ip.addr.v4, &src->vb_ip.addr.v4, sizeof(dst->vb_ip.addr.v4));
2434 break;
2435
2437 if (src->vb_ip.prefix != 128) {
2438 fr_strerror_printf("Invalid cast from %s to %s. Only /128 (not /%i) prefixes may be "
2439 "cast to IP address types",
2440 fr_type_to_str(src->type),
2441 fr_type_to_str(dst_type),
2442 src->vb_ip.prefix);
2443 return -1;
2444 }
2445 if (memcmp(&src->vb_ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) goto bad_v6_prefix_map;
2446 memcpy(&dst->vb_ip.addr.v4, &src->vb_ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
2447 sizeof(dst->vb_ip.addr.v4));
2448 break;
2449
2450 case FR_TYPE_OCTETS:
2451 if (src->vb_length != sizeof(dst->vb_ip.addr.v4.s_addr)) {
2452 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2453 fr_type_to_str(src->type),
2454 fr_type_to_str(dst_type),
2455 sizeof(dst->vb_ip.addr.v4.s_addr), src->vb_length);
2456 return -1;
2457 }
2458 memcpy(&dst->vb_ip.addr.v4, src->vb_octets, sizeof(dst->vb_ip.addr.v4.s_addr));
2459 break;
2460
2461 case FR_TYPE_UINT32:
2462 {
2463 uint32_t net;
2464
2465 net = ntohl(src->vb_uint32);
2466 memcpy(&dst->vb_ip.addr.v4, (uint8_t *)&net, sizeof(dst->vb_ip.addr.v4.s_addr));
2467 }
2468 break;
2469
2470 default:
2471 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2472 fr_type_to_str(src->type),
2473 fr_type_to_str(dst_type));
2474 return -1;
2475 }
2476
2477 return 0;
2478}
2479
2480/** Convert any supported type to an IPv6 address
2481 *
2482 * Allowed input types are:
2483 * - FR_TYPE_IPV4_ADDR
2484 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2485 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
2486 * - FR_TYPE_OCTETS (of length 16).
2487 *
2488 * @param ctx unused.
2489 * @param dst Where to write result of casting.
2490 * @param dst_type to cast to.
2491 * @param dst_enumv enumeration values.
2492 * @param src Input data.
2493 */
2494static inline int fr_value_box_cast_to_ipv4prefix(TALLOC_CTX *ctx, fr_value_box_t *dst,
2495 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2496 fr_value_box_t const *src)
2497{
2498 fr_type_t src_type = src->type;
2499 fr_assert(dst_type == FR_TYPE_IPV4_PREFIX);
2500
2501 switch (src_type) {
2502 case FR_TYPE_STRING:
2503 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2504 src->vb_strvalue, src->vb_length,
2505 NULL, src->tainted);
2506
2508
2509 default:
2510 break;
2511 }
2512
2513 /*
2514 * Pre-initialise box for non-variable types
2515 */
2516 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2517 dst->vb_ip.af = AF_INET;
2518 dst->vb_ip.scope_id = 0;
2519
2520 switch (src_type) {
2521 case FR_TYPE_IPV4_PREFIX: /* Needed for handling combo prefixes */
2522 dst->vb_ip.prefix = src->vb_ip.prefix;
2524
2525 case FR_TYPE_IPV4_ADDR:
2526 memcpy(&dst->vb_ip, &src->vb_ip, sizeof(dst->vb_ip));
2527 break;
2528
2529 /*
2530 * Copy the last four bytes, to make an IPv4prefix
2531 */
2532 case FR_TYPE_IPV6_ADDR:
2533 if (memcmp(src->vb_ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
2534 bad_v6_prefix_map:
2535 fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
2536 fr_type_to_str(src->type),
2537 fr_type_to_str(dst_type));
2538 return -1;
2539 }
2540 memcpy(&dst->vb_ip.addr.v4.s_addr, &src->vb_ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
2541 sizeof(dst->vb_ip.addr.v4.s_addr));
2542 dst->vb_ip.prefix = 32;
2543 break;
2544
2546 if (memcmp(src->vb_ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) goto bad_v6_prefix_map;
2547
2548 if (src->vb_ip.prefix < (sizeof(v4_v6_map) << 3)) {
2549 fr_strerror_printf("Invalid cast from %s to %s. Expected prefix >= %u bits got %u bits",
2550 fr_type_to_str(src->type),
2551 fr_type_to_str(dst_type),
2552 (unsigned int)(sizeof(v4_v6_map) << 3), src->vb_ip.prefix);
2553 return -1;
2554 }
2555 memcpy(&dst->vb_ip.addr.v4.s_addr, &src->vb_ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
2556 sizeof(dst->vb_ip.addr.v4.s_addr));
2557
2558 /*
2559 * Subtract the bits used by the v4_v6_map to get the v4 prefix bits
2560 */
2561 dst->vb_ip.prefix = src->vb_ip.prefix - (sizeof(v4_v6_map) << 3);
2562 break;
2563
2564 case FR_TYPE_OCTETS:
2565 if (src->vb_length != sizeof(dst->vb_ip.addr.v4.s_addr) + 1) {
2566 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2567 fr_type_to_str(src->type),
2568 fr_type_to_str(dst_type),
2569 sizeof(dst->vb_ip.addr.v4.s_addr) + 1, src->vb_length);
2570 return -1;
2571 }
2572 dst->vb_ip.prefix = src->vb_octets[0];
2573 memcpy(&dst->vb_ip.addr.v4, &src->vb_octets[1], sizeof(dst->vb_ip.addr.v4.s_addr));
2574 break;
2575
2576 case FR_TYPE_UINT32:
2577 {
2578 uint32_t net;
2579
2580 net = ntohl(src->vb_uint32);
2581 memcpy(&dst->vb_ip.addr.v4, (uint8_t *)&net, sizeof(dst->vb_ip.addr.v4.s_addr));
2582 dst->vb_ip.prefix = 32;
2583 break;
2584 }
2585
2586 default:
2587 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2588 fr_type_to_str(src->type),
2589 fr_type_to_str(dst_type));
2590 return -1;
2591 }
2592
2593 return 0;
2594}
2595
2596/** Convert any supported type to an IPv6 address
2597 *
2598 * Allowed input types are:
2599 * - FR_TYPE_IPV4_ADDR
2600 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2601 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
2602 * - FR_TYPE_OCTETS (of length 16).
2603 *
2604 * @param ctx unused.
2605 * @param dst Where to write result of casting.
2606 * @param dst_type to cast to.
2607 * @param dst_enumv enumeration values.
2608 * @param src Input data.
2609 */
2610static inline int fr_value_box_cast_to_ipv6addr(TALLOC_CTX *ctx, fr_value_box_t *dst,
2611 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2612 fr_value_box_t const *src)
2613{
2614 fr_type_t src_type = src->type;
2615
2616 static_assert((sizeof(v4_v6_map) + sizeof(src->vb_ip.addr.v4)) <=
2617 sizeof(src->vb_ip.addr.v6), "IPv6 storage too small");
2618 fr_assert(dst_type == FR_TYPE_IPV6_ADDR);
2619
2620 switch (src_type) {
2621 case FR_TYPE_STRING:
2622 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2623 src->vb_strvalue, src->vb_length,
2624 NULL, src->tainted);
2625
2627
2628 default:
2629 break;
2630 }
2631
2632 /*
2633 * Pre-initialise box for non-variable types
2634 */
2635 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2636 dst->vb_ip.af = AF_INET6;
2637 dst->vb_ip.prefix = 128;
2638
2639 switch (src_type) {
2640 case FR_TYPE_IPV4_ADDR:
2641 {
2642 uint8_t *p = dst->vb_ip.addr.v6.s6_addr;
2643
2644 /* Add the v4/v6 mapping prefix */
2645 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
2646 p += sizeof(v4_v6_map);
2647 memcpy(p, (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2648 dst->vb_ip.scope_id = 0;
2649 }
2650 break;
2651
2653 {
2654 uint8_t *p = dst->vb_ip.addr.v6.s6_addr;
2655
2656 if (src->vb_ip.prefix != 32) {
2657 fr_strerror_printf("Invalid cast from %s to %s. Only /32 (not /%i) prefixes may be "
2658 "cast to IP address types",
2659 fr_type_to_str(src->type),
2660 fr_type_to_str(dst_type),
2661 src->vb_ip.prefix);
2662 return -1;
2663 }
2664
2665 /* Add the v4/v6 mapping prefix */
2666 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
2667 p += sizeof(v4_v6_map);
2668 memcpy(p, (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2669 dst->vb_ip.scope_id = 0;
2670 }
2671 break;
2672
2674 if (src->vb_ip.prefix != 128) {
2675 fr_strerror_printf("Invalid cast from %s to %s. Only /128 (not /%i) prefixes may be "
2676 "cast to IP address types",
2677 fr_type_to_str(src->type),
2678 fr_type_to_str(dst_type),
2679 src->vb_ip.prefix);
2680 return -1;
2681 }
2683
2684 case FR_TYPE_IPV6_ADDR: /* Needed for handling combo addresses */
2685 memcpy(dst->vb_ip.addr.v6.s6_addr, src->vb_ip.addr.v6.s6_addr,
2686 sizeof(dst->vb_ip.addr.v6.s6_addr));
2687 dst->vb_ip.scope_id = src->vb_ip.scope_id;
2688 break;
2689
2690 case FR_TYPE_OCTETS:
2691 if (src->vb_length != sizeof(dst->vb_ip.addr.v6.s6_addr)) {
2692 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2693 fr_type_to_str(src->type),
2694 fr_type_to_str(dst_type),
2695 sizeof(dst->vb_ip.addr.v6.s6_addr), src->vb_length);
2696 return -1;
2697 }
2698 memcpy(&dst->vb_ip.addr.v6.s6_addr, src->vb_octets, sizeof(dst->vb_ip.addr.v6.s6_addr));
2699 break;
2700
2701 default:
2702 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2703 fr_type_to_str(src->type),
2704 fr_type_to_str(dst_type));
2705 break;
2706 }
2707
2708 return 0;
2709}
2710
2711/** Convert any supported type to an IPv6 address
2712 *
2713 * Allowed input types are:
2714 * - FR_TYPE_IPV4_ADDR
2715 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2716 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
2717 * - FR_TYPE_OCTETS (of length 16).
2718 *
2719 * @param ctx unused.
2720 * @param dst Where to write result of casting.
2721 * @param dst_type to cast to.
2722 * @param dst_enumv enumeration values.
2723 * @param src Input data.
2724 */
2725static inline int fr_value_box_cast_to_ipv6prefix(TALLOC_CTX *ctx, fr_value_box_t *dst,
2726 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2727 fr_value_box_t const *src)
2728{
2729 fr_type_t src_type = src->type;
2730
2731 fr_assert(dst_type == FR_TYPE_IPV6_PREFIX);
2732
2733 switch (src_type) {
2734 case FR_TYPE_STRING:
2735 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2736 src->vb_strvalue, src->vb_length,
2737 NULL, src->tainted);
2738
2740
2741 default:
2742 break;
2743 }
2744
2745 /*
2746 * Pre-initialise box for non-variable types
2747 */
2748 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2749 dst->vb_ip.af = AF_INET6;
2750
2751 switch (src_type) {
2752 case FR_TYPE_IPV4_ADDR:
2753 {
2754 uint8_t *p = dst->vb_ip.addr.v6.s6_addr;
2755
2756 /* Add the v4/v6 mapping prefix */
2757 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
2758 p += sizeof(v4_v6_map);
2759 memcpy(p, (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2760 dst->vb_ip.prefix = 128;
2761 dst->vb_ip.scope_id = 0;
2762 }
2763 break;
2764
2766 {
2767 uint8_t *p = dst->vb_ip.addr.v6.s6_addr;
2768
2769 /* Add the v4/v6 mapping prefix */
2770 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
2771 p += sizeof(v4_v6_map);
2772 memcpy(p, (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2773 dst->vb_ip.prefix = (sizeof(v4_v6_map) << 3) + src->vb_ip.prefix;
2774 dst->vb_ip.scope_id = 0;
2775 }
2776 break;
2777
2778 case FR_TYPE_IPV6_PREFIX: /* Needed for handling combo prefixes */
2779 dst->vb_ip.prefix = src->vb_ip.prefix;
2780 goto v6_common;
2781
2782 case FR_TYPE_IPV6_ADDR:
2783 dst->vb_ip.prefix = 128;
2784 v6_common:
2785 memcpy(dst->vb_ip.addr.v6.s6_addr, src->vb_ip.addr.v6.s6_addr,
2786 sizeof(dst->vb_ip.addr.v6.s6_addr));
2787 dst->vb_ip.scope_id = src->vb_ip.scope_id;
2788 break;
2789
2790 case FR_TYPE_OCTETS:
2791 if (src->vb_length != (sizeof(dst->vb_ip.addr.v6.s6_addr) + 2)) {
2792 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2793 fr_type_to_str(src->type),
2794 fr_type_to_str(dst_type),
2795 sizeof(dst->vb_ip.addr.v6.s6_addr) + 2, src->vb_length);
2796 return -1;
2797 }
2798 dst->vb_ip.scope_id = src->vb_octets[0];
2799 dst->vb_ip.prefix = src->vb_octets[1];
2800 memcpy(&dst->vb_ip.addr.v6.s6_addr, src->vb_octets, sizeof(dst->vb_ip.addr.v6.s6_addr));
2801 break;
2802
2803 default:
2804 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2805 fr_type_to_str(src->type),
2806 fr_type_to_str(dst_type));
2807 return -1;
2808 }
2809 return 0;
2810}
2811
2812/** Convert any supported type to an ethernet address
2813 *
2814 * Allowed input types are:
2815 * - FR_TYPE_STRING ("00:11:22:33:44:55")
2816 * - FR_TYPE_OCTETS (0x001122334455)
2817 *
2818 *
2819 * @param ctx unused.
2820 * @param dst Where to write result of casting.
2821 * @param dst_type to cast to.
2822 * @param dst_enumv enumeration values.
2823 * @param src Input data.
2824 */
2825static inline int fr_value_box_cast_to_ethernet(TALLOC_CTX *ctx, fr_value_box_t *dst,
2826 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2827 fr_value_box_t const *src)
2828{
2829 fr_assert(dst_type == FR_TYPE_ETHERNET);
2830
2831 switch (src->type) {
2832 case FR_TYPE_STRING:
2833 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2834 src->vb_strvalue, src->vb_length,
2835 NULL, src->tainted);
2836
2837 case FR_TYPE_OCTETS:
2838 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
2839
2840 default:
2841 break;
2842 }
2843
2844 /*
2845 * Pre-initialise box for non-variable types
2846 */
2847 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2848
2849 switch (src->type) {
2850 case FR_TYPE_UINT64: {
2851 uint8_t array[8];
2852
2853 fr_nbo_from_uint64(array, src->vb_uint64);
2854
2855 /*
2856 * For OUIs in the DB.
2857 */
2858 if ((array[0] != 0) || (array[1] != 0)) return -1;
2859
2860 memcpy(dst->vb_ether, &array[2], 6);
2861 break;
2862 }
2863
2864 default:
2865 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2866 fr_type_to_str(src->type),
2867 fr_type_to_str(dst_type));
2868 return -1;
2869 }
2870
2871 return 0;
2872}
2873
2874/** Convert any supported type to a bool
2875 *
2876 * Allowed input types are:
2877 * - FR_TYPE_STRING ("yes", "true", "no", "false")
2878 *
2879 * @param ctx unused.
2880 * @param dst Where to write result of casting.
2881 * @param dst_type to cast to.
2882 * @param dst_enumv enumeration values.
2883 * @param src Input data.
2884 */
2885static inline int fr_value_box_cast_to_bool(TALLOC_CTX *ctx, fr_value_box_t *dst,
2886 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2887 fr_value_box_t const *src)
2888{
2889 fr_assert(dst_type == FR_TYPE_BOOL);
2890
2891 switch (src->type) {
2892 case FR_TYPE_STRING:
2893 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2894 src->vb_strvalue, src->vb_length,
2895 NULL, src->tainted);
2896
2897 case FR_TYPE_OCTETS:
2898 /*
2899 * This is really "bool from network"
2900 */
2901 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
2902
2903 default:
2904 break;
2905 }
2906
2907 /*
2908 * Pre-initialise box for non-variable types
2909 */
2910 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2911
2912 switch (src->type) {
2913 case FR_TYPE_INT8:
2914 dst->vb_bool = (src->vb_int8 != 0);
2915 break;
2916
2917 case FR_TYPE_UINT8:
2918 dst->vb_bool = (src->vb_uint8 != 0);
2919 break;
2920
2921 case FR_TYPE_INT16:
2922 dst->vb_bool = (src->vb_int16 != 0);
2923 break;
2924
2925 case FR_TYPE_UINT16:
2926 dst->vb_bool = (src->vb_uint16 != 0);
2927 break;
2928
2929 case FR_TYPE_INT32:
2930 dst->vb_bool = (src->vb_int32 != 0);
2931 break;
2932
2933 case FR_TYPE_UINT32:
2934 dst->vb_bool = (src->vb_uint32 != 0);
2935 break;
2936
2937 case FR_TYPE_INT64:
2938 dst->vb_bool = (src->vb_int64 != 0);
2939 break;
2940
2941 case FR_TYPE_UINT64:
2942 dst->vb_bool = (src->vb_uint64 != 0);
2943 break;
2944
2945 case FR_TYPE_SIZE:
2946 dst->vb_bool = (src->vb_size != 0);
2947 break;
2948
2949 case FR_TYPE_TIME_DELTA:
2950 dst->vb_bool = (fr_time_delta_unwrap(src->vb_time_delta) != 0);
2951 break;
2952
2953 case FR_TYPE_FLOAT32:
2954 dst->vb_bool = (fpclassify(src->vb_float32) == FP_ZERO);
2955 break;
2956
2957 case FR_TYPE_FLOAT64:
2958 dst->vb_bool = (fpclassify(src->vb_float64) == FP_ZERO);
2959 break;
2960
2961 default:
2962 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2963 fr_type_to_str(src->type),
2964 fr_type_to_str(dst_type));
2965 return -1;
2966 }
2967
2968 return 0;
2969}
2970
2971/** Convert any signed or unsigned integer type to any other signed or unsigned integer type
2972 *
2973 */
2974static inline int fr_value_box_cast_integer_to_integer(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst,
2975 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2976 fr_value_box_t const *src)
2977{
2978 uint64_t tmp = 0;
2979 size_t len = fr_value_box_field_sizes[src->type];
2980 int64_t min;
2981
2982#define SIGN_BIT_HIGH(_int, _len) ((((uint64_t)1) << (((_len) << 3) - 1)) & (_int))
2983#define SIGN_PROMOTE(_int, _len) ((_len) < sizeof(_int) ? \
2984 (_int) | (~((__typeof__(_int))0)) << ((_len) << 3) : (_int))
2985
2986#if !defined(NDEBUG) || defined(STATIC_ANALYZER)
2987 /*
2988 * Helps catch invalid fr_value_box_field_sizes
2989 * entries, and shuts up clang analyzer.
2990 */
2991 if (!fr_cond_assert_msg(len > 0, "Invalid cast from %s to %s. "
2992 "invalid source type len, expected > 0, got %zu",
2993 fr_type_to_str(src->type),
2994 fr_type_to_str(dst_type),
2995 len)) return -1;
2996
2997 if (!fr_cond_assert_msg(len <= sizeof(uint64_t),
2998 "Invalid cast from %s to %s. "
2999 "invalid source type len, expected <= %zu, got %zu",
3000 fr_type_to_str(src->type),
3001 fr_type_to_str(dst_type),
3002 sizeof(uint64_t), len)) return -1;
3003#endif
3004
3005 switch (src->type) {
3006 /*
3007 * Dates are always represented in nanoseconds
3008 * internally, but when we convert to another
3009 * integer type, we scale appropriately.
3010 *
3011 * i.e. if the attribute value resolution is
3012 * seconds, then the integer value is
3013 * nanoseconds -> seconds.
3014 */
3015 case FR_TYPE_DATE:
3016 {
3018 if (src->enumv) res = src->enumv->flags.flag_time_res;
3019
3020 tmp = fr_unix_time_to_integer(src->vb_date, res);
3021 }
3022 break;
3023
3024 /*
3025 * Same deal with time deltas. Note that
3026 * even though we store the value as an
3027 * unsigned integer, it'll be cast to a
3028 * signed integer for comparisons.
3029 */
3030 case FR_TYPE_TIME_DELTA:
3031 {
3033
3034 if (src->enumv) res = src->enumv->flags.flag_time_res;
3035
3036 tmp = (uint64_t)fr_time_delta_to_integer(src->vb_time_delta, res);
3037 }
3038 break;
3039
3040 default:
3041#ifdef WORDS_BIGENDIAN
3042 memcpy(((uint8_t *)&tmp) + (sizeof(tmp) - len),
3043 fr_value_box_raw(src, src->type), len);
3044#else
3045 memcpy(&tmp, fr_value_box_raw(src, src->type), len);
3046#endif
3047 break;
3048 }
3049
3050 min = fr_value_box_integer_min[dst_type];
3051
3052 /*
3053 * Sign promote the input if the source type is
3054 * signed, and the high bit is set.
3055 */
3056 if (fr_value_box_integer_min[src->type] < 0) {
3057 if (SIGN_BIT_HIGH(tmp, len)) tmp = SIGN_PROMOTE(tmp, len);
3058
3059 if ((int64_t)tmp < min) {
3060 fr_strerror_printf("Invalid cast from %s to %s. %"PRId64" "
3061 "outside value range %"PRId64"-%"PRIu64,
3062 fr_type_to_str(src->type),
3063 fr_type_to_str(dst_type),
3064 (int64_t)tmp,
3065 min, fr_value_box_integer_max[dst_type]);
3066 return -1;
3067 }
3068 } else if (tmp > fr_value_box_integer_max[dst_type]) {
3069 fr_strerror_printf("Invalid cast from %s to %s. %"PRIu64" "
3070 "outside value range 0-%"PRIu64,
3071 fr_type_to_str(src->type),
3072 fr_type_to_str(dst_type),
3073 tmp, fr_value_box_integer_max[dst_type]);
3074 return -1;
3075 }
3076
3077 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3078 switch (dst_type) {
3079 case FR_TYPE_DATE:
3080 {
3081 bool overflow;
3083 if (dst->enumv) res = dst->enumv->flags.flag_time_res;
3084
3085 dst->vb_date = fr_unix_time_from_integer(&overflow, tmp, res);
3086 if (overflow) {
3087 fr_strerror_const("Input to data type would overflow");
3088 return -1;
3089 }
3090 }
3091 break;
3092
3093 case FR_TYPE_TIME_DELTA:
3094 {
3095 bool overflow;
3097 if (dst->enumv) res = dst->enumv->flags.flag_time_res;
3098
3099 dst->vb_time_delta = fr_time_delta_from_integer(&overflow, tmp, res);
3100 if (overflow) {
3101 fr_strerror_const("Input to time_delta type would overflow");
3102 return -1;
3103 }
3104 }
3105 break;
3106
3107 default:
3108#ifdef WORDS_BIGENDIAN
3109 memcpy(fr_value_box_raw(dst, dst->type),
3110 ((uint8_t *)&tmp) + (sizeof(tmp) - len), fr_value_box_field_sizes[dst_type]);
3111#else
3112 memcpy(fr_value_box_raw(dst, dst->type),
3113 &tmp, fr_value_box_field_sizes[dst_type]);
3114#endif
3115 break;
3116 }
3117
3118 return 0;
3119}
3120
3121/** Convert any value to a signed or unsigned integer
3122 *
3123 * @param ctx unused.
3124 * @param dst Where to write result of casting.
3125 * @param dst_type to cast to.
3126 * @param dst_enumv enumeration values.
3127 * @param src Input data.
3128 */
3129static inline int fr_value_box_cast_to_integer(TALLOC_CTX *ctx, fr_value_box_t *dst,
3130 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3131 fr_value_box_t const *src)
3132{
3133 switch (src->type) {
3134 case FR_TYPE_STRING:
3135 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3136 src->vb_strvalue, src->vb_length,
3137 NULL, src->tainted);
3138
3139 case FR_TYPE_OCTETS:
3140 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
3141
3142 case FR_TYPE_INTEGER:
3143 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, src);
3144
3145 case FR_TYPE_IPV4_ADDR:
3147 {
3148 fr_value_box_t tmp;
3149
3150 switch (dst_type) {
3151 case FR_TYPE_UINT32:
3152 case FR_TYPE_INT64:
3153 case FR_TYPE_UINT64:
3154 case FR_TYPE_DATE:
3155 case FR_TYPE_TIME_DELTA:
3156 break;
3157
3158 default:
3159 goto bad_cast;
3160 }
3161
3162 fr_value_box_init(&tmp, FR_TYPE_UINT32, src->enumv, src->tainted);
3163 memcpy(&tmp.vb_uint32, &src->vb_ip.addr.v4, sizeof(tmp.vb_uint32));
3164 fr_value_box_hton(&tmp, &tmp);
3165 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, &tmp);
3166 }
3167
3168 case FR_TYPE_ETHERNET:
3169 {
3170 fr_value_box_t tmp;
3171
3172 switch (dst_type) {
3173 case FR_TYPE_INT64:
3174 case FR_TYPE_UINT64:
3175 case FR_TYPE_DATE:
3176 case FR_TYPE_TIME_DELTA:
3177 break;
3178
3179 default:
3180 goto bad_cast;
3181 }
3182
3183 fr_value_box_init(&tmp, FR_TYPE_UINT64, src->enumv, src->tainted);
3184 memcpy(((uint8_t *)&tmp.vb_uint64) + (sizeof(tmp.vb_uint64) - sizeof(src->vb_ether)),
3185 &src->vb_ether, sizeof(src->vb_ether));
3186#ifndef WORDS_BIGENDIAN
3187 /*
3188 * Ethernet addresses are always stored bigendian,
3189 * convert to native on little endian systems
3190 */
3191 fr_value_box_hton(&tmp, &tmp);
3192#endif
3193 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, &tmp);
3194 }
3195
3196 case FR_TYPE_IFID:
3197 {
3198 switch (dst_type) {
3199 case FR_TYPE_UINT64:
3200 break;
3201
3202 default:
3203 goto bad_cast;
3204 }
3205
3206 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3207 dst->vb_uint64 = fr_nbo_to_uint64(&src->vb_ifid[0]);
3208 return 0;
3209 }
3210
3211 default:
3212 break;
3213 }
3214
3215bad_cast:
3216 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
3217 fr_type_to_str(src->type),
3218 fr_type_to_str(dst_type));
3219 return -1;
3220}
3221
3222/** Convert any value to a floating point value
3223 *
3224 * @param ctx unused.
3225 * @param dst Where to write result of casting.
3226 * @param dst_type to cast to.
3227 * @param dst_enumv enumeration values.
3228 * @param src Input data.
3229 */
3230static inline int fr_value_box_cast_to_float(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst,
3231 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3232 fr_value_box_t const *src)
3233{
3234 double num;
3235
3236 switch (src->type) {
3237 case FR_TYPE_FLOAT32:
3238 if (dst_type == FR_TYPE_FLOAT64) {
3239 num = (double) src->vb_float32;
3240 goto good_cast;
3241 }
3242
3243 goto bad_cast;
3244
3245 case FR_TYPE_FLOAT64:
3246 if (dst_type == FR_TYPE_FLOAT32) {
3247 num = src->vb_float64;
3248 goto good_cast;
3249 }
3250
3251 goto bad_cast;
3252
3253 case FR_TYPE_BOOL:
3254 num = src->vb_bool;
3255 goto good_cast;
3256
3257 case FR_TYPE_INT8:
3258 num = src->vb_int8;
3259 goto good_cast;
3260
3261 case FR_TYPE_INT16:
3262 num = src->vb_int16;
3263 goto good_cast;
3264
3265 case FR_TYPE_INT32:
3266 num = src->vb_int32;
3267 goto good_cast;
3268
3269 case FR_TYPE_INT64:
3270 num = src->vb_int64;
3271 goto good_cast;
3272
3273 case FR_TYPE_UINT8:
3274 num = src->vb_uint8;
3275 goto good_cast;
3276
3277 case FR_TYPE_UINT16:
3278 num = src->vb_uint16;
3279 goto good_cast;
3280
3281 case FR_TYPE_UINT32:
3282 num = src->vb_uint32;
3283 goto good_cast;
3284
3285 case FR_TYPE_UINT64:
3286 num = src->vb_uint64;
3287 goto good_cast;
3288
3289 case FR_TYPE_DATE:
3290 /*
3291 * Unix times are in nanoseconds
3292 */
3293 num = fr_unix_time_unwrap(src->vb_date);
3294 num /= NSEC;
3295 goto good_cast;
3296
3297 case FR_TYPE_TIME_DELTA:
3298 /*
3299 * Time deltas are in nanoseconds, but scaled.
3300 */
3301 num = fr_time_delta_unwrap(src->vb_time_delta);
3302 if (src->enumv) {
3303 num /= fr_time_multiplier_by_res[src->enumv->flags.flag_time_res];
3304 } else {
3305 num /= NSEC;
3306 }
3307 goto good_cast;
3308
3309 case FR_TYPE_SIZE:
3310 num = src->vb_size;
3311
3312 good_cast:
3313 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3314 if (dst_type == FR_TYPE_FLOAT32) {
3315 dst->vb_float32 = num;
3316 } else {
3317 dst->vb_float64 = num;
3318 }
3319 return 0;
3320
3321 default:
3322 break;
3323 }
3324
3325bad_cast:
3326 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
3327 fr_type_to_str(src->type),
3328 fr_type_to_str(dst_type));
3329 return -1;
3330}
3331
3332
3333/** Convert one type of fr_value_box_t to another
3334 *
3335 * This should be the canonical function used to convert between INTERNAL data formats.
3336 *
3337 * If you want to convert from PRESENTATION format, use #fr_value_box_from_substr.
3338 *
3339 * @note src and dst must not be the same box. We do not support casting in place.
3340 *
3341 * @param ctx to allocate buffers in (usually the same as dst)
3342 * @param dst Where to write result of casting.
3343 * @param dst_type to cast to.
3344 * @param dst_enumv Aliases for values contained within this fr_value_box_t.
3345 * If #fr_value_box_t is passed to #fr_value_box_aprint
3346 * names will be printed instead of actual value.
3347 * @param src Input data.
3348 * @return
3349 * - 0 on success.
3350 * - -1 on failure.
3351 */
3352int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst,
3353 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3354 fr_value_box_t const *src)
3355{
3356 if (!fr_cond_assert(dst_type != FR_TYPE_NULL)) return -1;
3357 if (!fr_cond_assert(src != dst)) return -1;
3358 if (!fr_cond_assert(src->type != FR_TYPE_NULL)) return -1;
3359
3360 if (fr_type_is_non_leaf(dst_type)) {
3361 fr_strerror_printf("Invalid cast from %s to %s. Can only cast simple data types",
3362 fr_type_to_str(src->type),
3363 fr_type_to_str(dst_type));
3364 return -1;
3365 }
3366
3367 /*
3368 * If it's the same type, copy, but set the enumv
3369 * in the destination box to be the one provided.
3370 *
3371 * The theory here is that the attribute value isn't
3372 * being converted into its presentation format and
3373 * re-parsed, and the enumv names only get applied
3374 * when converting internal values to/from strings,
3375 * so it's OK just to swap out the enumv.
3376 *
3377 * If there's a compelling case in the future we
3378 * might revisit this, but it'd likely mean fixing
3379 * all the casting functions to treat any value
3380 * with an enumv as a string, which seems weird.
3381 */
3382 if (dst_type == src->type) {
3383 int ret;
3384
3385 ret = fr_value_box_copy(ctx, dst, src);
3386 if (ret < 0) return ret;
3387
3388 dst->enumv = dst_enumv;
3389
3390 return ret;
3391 }
3392
3393 /*
3394 * Initialise dst
3395 */
3396 fr_value_box_init(dst, dst_type, NULL, src->tainted);
3397
3398 /*
3399 * Dispatch to specialised cast functions
3400 */
3401 switch (dst_type) {
3402 case FR_TYPE_STRING:
3403 return fr_value_box_cast_to_strvalue(ctx, dst, dst_type, dst_enumv, src);
3404
3405 case FR_TYPE_OCTETS:
3406 return fr_value_box_cast_to_octets(ctx, dst, dst_type, dst_enumv, src);
3407
3408 case FR_TYPE_IPV4_ADDR:
3409 return fr_value_box_cast_to_ipv4addr(ctx, dst, dst_type, dst_enumv, src);
3410
3412 return fr_value_box_cast_to_ipv4prefix(ctx, dst, dst_type, dst_enumv, src);
3413
3414 case FR_TYPE_IPV6_ADDR:
3415 return fr_value_box_cast_to_ipv6addr(ctx, dst, dst_type, dst_enumv, src);
3416
3418 return fr_value_box_cast_to_ipv6prefix(ctx, dst, dst_type, dst_enumv, src);
3419
3422 break;
3423 /*
3424 * Need func
3425 */
3426 case FR_TYPE_IFID:
3427 break;
3428
3429 case FR_TYPE_ETHERNET:
3430 return fr_value_box_cast_to_ethernet(ctx, dst, dst_type, dst_enumv, src);
3431
3432 case FR_TYPE_BOOL:
3433 return fr_value_box_cast_to_bool(ctx, dst, dst_type, dst_enumv, src);
3434
3435 case FR_TYPE_DATE:
3436 if (src->type != FR_TYPE_TIME_DELTA) return fr_value_box_cast_to_integer(ctx, dst, dst_type, dst_enumv, src);
3437
3438 if (fr_time_delta_isneg(src->vb_time_delta)) {
3439 fr_strerror_const("Input to data type would underflow");
3440 return -1;
3441 }
3442
3443 dst->type = dst_type;
3444 dst->enumv = dst_enumv;
3445 dst->vb_date = fr_unix_time_wrap(fr_time_delta_unwrap(src->vb_time_delta));
3446 return 0;
3447
3448 case FR_TYPE_TIME_DELTA:
3449 /*
3450 * Unix time cast to time_delta is just nanoseconds since the epoch.
3451 *
3452 * Note that we do NOT change time resolution, but we DO change enumv. Both unix time
3453 * and time_delta are tracked internally as nanoseconds, and the only use of precision is
3454 * for printing / parsing.
3455 */
3456 if (src->type == FR_TYPE_DATE) {
3457 uint64_t when;
3458
3459 when = fr_unix_time_unwrap(src->vb_date);
3460 if (when > INT64_MAX) {
3461 fr_strerror_const("Input to data type would overflow");
3462 return -1;
3463 }
3464
3465 dst->type = dst_type;
3466 dst->enumv = dst_enumv;
3467 dst->vb_time_delta = fr_time_delta_wrap((int64_t) when);
3468 return 0;
3469 }
3471
3472 case FR_TYPE_UINT8:
3473 case FR_TYPE_UINT16:
3474 case FR_TYPE_UINT32:
3475 case FR_TYPE_UINT64:
3476 case FR_TYPE_INT8:
3477 case FR_TYPE_INT16:
3478 case FR_TYPE_INT32:
3479 case FR_TYPE_INT64:
3480 case FR_TYPE_SIZE:
3481 return fr_value_box_cast_to_integer(ctx, dst, dst_type, dst_enumv, src);
3482
3483 case FR_TYPE_FLOAT32:
3484 case FR_TYPE_FLOAT64:
3485 if (fr_type_is_fixed_size(src->type)) {
3486 return fr_value_box_cast_to_float(ctx, dst, dst_type, dst_enumv, src);
3487 }
3488 break; /* use generic string/octets stuff below */
3489
3490 /*
3491 * Invalid types for casting (should have been caught earlier)
3492 */
3493 case FR_TYPE_VALUE_BOX:
3494 case FR_TYPE_STRUCTURAL:
3495 case FR_TYPE_NULL:
3496 case FR_TYPE_VOID:
3497 case FR_TYPE_MAX:
3498 fr_strerror_printf("Invalid cast from %s to %s. Invalid destination type",
3499 fr_type_to_str(src->type),
3500 fr_type_to_str(dst_type));
3501 return -1;
3502 }
3503
3504 /*
3505 * Deserialise a fr_value_box_t
3506 */
3507 if (src->type == FR_TYPE_STRING) return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3508 src->vb_strvalue, src->vb_length,
3509 NULL, src->tainted);
3510
3511 if (src->type == FR_TYPE_OCTETS) {
3512 fr_value_box_t tmp;
3513
3514 if (src->vb_length < network_min_size(dst_type)) {
3515 fr_strerror_printf("Invalid cast from %s to %s. Source is length %zu is smaller than "
3516 "destination type size %zu",
3517 fr_type_to_str(src->type),
3518 fr_type_to_str(dst_type),
3519 src->vb_length,
3520 network_min_size(dst_type));
3521 return -1;
3522 }
3523
3524 if (src->vb_length > network_max_size(dst_type)) {
3525 fr_strerror_printf("Invalid cast from %s to %s. Source length %zu is greater than "
3526 "destination type size %zu",
3527 fr_type_to_str(src->type),
3528 fr_type_to_str(dst_type),
3529 src->vb_length,
3530 network_max_size(dst_type));
3531 return -1;
3532 }
3533
3534 fr_value_box_init(&tmp, dst_type, NULL, false);
3535
3536 /*
3537 * Copy the raw octets into the datum of a value_box
3538 * inverting bytesex for uint32s (if LE).
3539 */
3540 memcpy(&tmp.datum, src->vb_octets, fr_value_box_field_sizes[dst_type]);
3541 tmp.type = dst_type;
3542 dst->enumv = dst_enumv;
3543
3544 fr_value_box_hton(dst, &tmp);
3545 return 0;
3546 }
3547
3548 memcpy(&dst->datum, &src->datum, fr_value_box_field_sizes[src->type]);
3549
3550 dst->type = dst_type;
3551 dst->enumv = dst_enumv;
3552
3553 return 0;
3554}
3555
3556/** Convert one type of fr_value_box_t to another in place
3557 *
3558 * This should be the canonical function used to convert between INTERNAL data formats.
3559 *
3560 * If you want to convert from PRESENTATION format, use #fr_value_box_from_substr.
3561 *
3562 * @param ctx to allocate buffers in (usually the same as dst)
3563 * @param vb to cast.
3564 * @param dst_type to cast to.
3565 * @param dst_enumv Aliases for values contained within this fr_value_box_t.
3566 * If #fr_value_box_t is passed to #fr_value_box_aprint
3567 * names will be printed instead of actual value.
3568 * @return
3569 * - 0 on success.
3570 * - -1 on failure.
3571 */
3573 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
3574{
3575 fr_value_box_t tmp;
3576 /*
3577 * Store list pointers to restore later - fr_value_box_cast clears them
3578 */
3579 fr_value_box_entry_t entry = vb->entry;
3580
3581 /*
3582 * Simple case, destination type and current
3583 * type are the same.
3584 */
3585 if (vb->type == dst_type) {
3586 vb->enumv = dst_enumv; /* Update the enumv as this may be different */
3587 return 0;
3588 }
3589
3590 /*
3591 * Copy meta data and any existing buffers to
3592 * a temporary box. We then clear that value
3593 * box after the cast has been completed,
3594 * freeing any old buffers.
3595 */
3596 fr_value_box_copy_shallow(NULL, &tmp, vb);
3597
3598 if (fr_value_box_cast(ctx, vb, dst_type, dst_enumv, &tmp) < 0) {
3599 /*
3600 * On error, make sure the original
3601 * box is left in a consistent state.
3602 */
3603 fr_value_box_copy_shallow(NULL, vb, &tmp);
3604 vb->entry = entry;
3605 return -1;
3606 }
3607 fr_value_box_clear_value(&tmp); /* Clear out any old buffers */
3608
3609 /*
3610 * Restore list pointers
3611 */
3612 vb->entry = entry;
3613
3614 return 0;
3615}
3616
3617/** Assign a #fr_value_box_t value from an #fr_ipaddr_t
3618 *
3619 * Automatically determines the type of the value box from the ipaddr address family
3620 * and the length of the prefix field.
3621 *
3622 * @param[in] dst to assign ipaddr to.
3623 * @param[in] enumv Aliases for values.
3624 * @param[in] ipaddr to copy address from.
3625 * @param[in] tainted Whether the value came from a trusted source.
3626 * @return
3627 * - 0 on success.
3628 * - -1 on failure.
3629 */
3630int fr_value_box_ipaddr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, fr_ipaddr_t const *ipaddr, bool tainted)
3631{
3633
3634 switch (ipaddr->af) {
3635 case AF_INET:
3637 break;
3638
3639 case AF_INET6:
3641 break;
3642
3643 default:
3644 fr_strerror_printf("Invalid address family %i", ipaddr->af);
3645 return -1;
3646 }
3647
3648 fr_value_box_init(dst, type, enumv, tainted);
3649 memcpy(&dst->vb_ip, ipaddr, sizeof(dst->vb_ip));
3650
3651 return 0;
3652}
3653
3654/** Unbox an IP address performing a type check
3655 *
3656 * @param[out] dst Where to copy the IP address to.
3657 * @param[in] src Where to copy the IP address from.
3658 * @return
3659 * - 0 on success.
3660 * - -1 on type mismatch.
3661 */
3663{
3664 if (!fr_type_is_ip(src->type)) {
3665 fr_strerror_printf("Unboxing failed. Needed IPv4/6 addr/prefix, had type %s",
3666 fr_type_to_str(src->type));
3667 return -1;
3668 }
3669
3670 memcpy(dst, &src->vb_ip, sizeof(*dst));
3671
3672 return 0;
3673}
3674
3675/** Clear/free any existing value
3676 *
3677 * @note Do not use on uninitialised memory.
3678 *
3679 * @param[in] data to clear.
3680 */
3682{
3683 switch (data->type) {
3684 case FR_TYPE_OCTETS:
3685 case FR_TYPE_STRING:
3686 if (data->secret) memset_explicit(data->datum.ptr, 0, data->vb_length);
3687 talloc_free(data->datum.ptr);
3688 break;
3689
3690 case FR_TYPE_GROUP:
3691 /*
3692 * Depth first freeing of children
3693 *
3694 * This ensures orderly freeing, regardless
3695 * of talloc hierarchy.
3696 */
3697 {
3698 fr_value_box_t *vb = NULL;
3699
3700 while ((vb = fr_value_box_list_next(&data->vb_group, vb))) {
3702 talloc_free(vb);
3703 }
3704 }
3705 return;
3706
3707 case FR_TYPE_NULL:
3708 return;
3709
3710 default:
3711 break;
3712 }
3713
3714 memset(&data->datum, 0, sizeof(data->datum));
3715}
3716
3717/** Clear/free any existing value and metadata
3718 *
3719 * @note Do not use on uninitialised memory.
3720 *
3721 * @param[in] data to clear.
3722 */
3728
3729/** Copy value data verbatim duplicating any buffers
3730 *
3731 * @note Will free any exiting buffers associated with the dst #fr_value_box_t.
3732 *
3733 * @param ctx To allocate buffers in.
3734 * @param dst Where to copy value_box to.
3735 * @param src Where to copy value_box from.
3736 * @return
3737 * - 0 on success.
3738 * - -1 on failure.
3739 */
3740int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
3741{
3742 switch (src->type) {
3743 default:
3744 fr_value_box_memcpy_out(fr_value_box_raw(dst, src->type), src);
3745 fr_value_box_copy_meta(dst, src);
3746 break;
3747
3748 case FR_TYPE_NULL:
3749 fr_value_box_copy_meta(dst, src);
3750 break;
3751
3752 case FR_TYPE_STRING:
3753 {
3754 char *str = NULL;
3755
3756 /*
3757 * Zero length strings still have a one uint8 buffer
3758 */
3759 str = talloc_bstrndup(ctx, src->vb_strvalue, src->vb_length);
3760 if (!str) {
3761 fr_strerror_const("Failed allocating string buffer");
3762 return -1;
3763 }
3764 dst->vb_strvalue = str;
3765 fr_value_box_copy_meta(dst, src);
3766 }
3767 break;
3768
3769 case FR_TYPE_OCTETS:
3770 {
3771 uint8_t *bin;
3772
3773 if (src->vb_length) {
3774 bin = talloc_memdup(ctx, src->vb_octets, src->vb_length);
3775 if (!bin) {
3776 fr_strerror_const("Failed allocating octets buffer");
3777 return -1;
3778 }
3779 talloc_set_type(bin, uint8_t);
3780 } else {
3781 bin = talloc_array(ctx, uint8_t, 0);
3782 }
3783 dst->vb_octets = bin;
3784 fr_value_box_copy_meta(dst, src);
3785 }
3786 break;
3787
3788 case FR_TYPE_GROUP:
3789 {
3790 fr_value_box_t *child = NULL;
3791
3792 fr_value_box_copy_meta(dst, src); /* Initialises group child dlist */
3793
3794 while ((child = fr_value_box_list_next(&src->vb_group, child))) {
3795 fr_value_box_t *new;
3796
3797 /*
3798 * Build out the child
3799 */
3800 new = fr_value_box_alloc_null(ctx);
3801 if (unlikely(!new)) {
3802 group_error:
3803 fr_strerror_const("Failed duplicating group child");
3804 fr_value_box_list_talloc_free(&dst->vb_group);
3805 return -1;
3806 }
3807
3808 /*
3809 * Populate it with the
3810 * data from the original
3811 * child.
3812 */
3813 if (unlikely(fr_value_box_copy(new, new, child) < 0)) goto group_error;
3814 fr_value_box_list_insert_tail(&dst->vb_group, new);
3815 }
3816 }
3817 break;
3818 }
3819
3820 return 0;
3821}
3822
3823/** Perform a shallow copy of a value_box
3824 *
3825 * Like #fr_value_box_copy, but does not duplicate the buffers of the src value_box.
3826 *
3827 * For #FR_TYPE_STRING and #FR_TYPE_OCTETS adds a reference from ctx so that the
3828 * buffer cannot be freed until the ctx is freed.
3829 *
3830 * @param[in] ctx to add reference from. If NULL no reference will be added.
3831 * @param[in] dst to copy value to.
3832 * @param[in] src to copy value from.
3833 */
3834void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
3835{
3836 switch (src->type) {
3837 default:
3838 fr_value_box_copy(NULL, dst, src);
3839 break;
3840
3841 case FR_TYPE_STRING:
3842 case FR_TYPE_OCTETS:
3843 dst->datum.ptr = ctx ? talloc_reference(ctx, src->datum.ptr) : src->datum.ptr;
3844 fr_value_box_copy_meta(dst, src);
3845 break;
3846 }
3847}
3848
3849/** Copy value data verbatim moving any buffers to the specified context
3850 *
3851 * @param[in] ctx to allocate any new buffers in.
3852 * @param[in] dst to copy value to.
3853 * @param[in] src to copy value from.
3854 * @return
3855 * - 0 on success.
3856 * - -1 on failure.
3857 */
3858int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
3859{
3860 if (!fr_cond_assert(src->type != FR_TYPE_NULL)) return -1;
3861
3862 switch (src->type) {
3863 default:
3864 return fr_value_box_copy(ctx, dst, src);
3865
3866 case FR_TYPE_STRING:
3867 {
3868 char const *str;
3869
3870 str = talloc_steal(ctx, src->vb_strvalue);
3871 if (!str) {
3872 fr_strerror_const("Failed stealing string buffer");
3873 return -1;
3874 }
3875 talloc_set_type(str, char);
3876 dst->vb_strvalue = str;
3877 fr_value_box_copy_meta(dst, src);
3878 memset(&src->datum, 0, sizeof(src->datum));
3879 }
3880 return 0;
3881
3882 case FR_TYPE_OCTETS:
3883 {
3884 uint8_t const *bin;
3885
3886 bin = talloc_steal(ctx, src->vb_octets);
3887 if (!bin) {
3888 fr_strerror_const("Failed stealing octets buffer");
3889 return -1;
3890 }
3891 talloc_set_type(bin, uint8_t);
3892
3893 dst->vb_octets = bin;
3894 fr_value_box_copy_meta(dst, src);
3895 memset(&src->datum, 0, sizeof(src->datum));
3896 }
3897 return 0;
3898
3899 case FR_TYPE_GROUP:
3900 {
3901 fr_value_box_t *child;
3902
3903 while ((child = fr_value_box_list_pop_head(&src->vb_group))) {
3904 child = talloc_steal(ctx, child);
3905 if (unlikely(!child)) {
3906 fr_strerror_const("Failed stealing child");
3907 return -1;
3908 }
3909 fr_value_box_list_insert_tail(&dst->vb_group, child);
3910 }
3911 }
3912 return 0;
3913 }
3914}
3915
3916/** Copy a nul terminated string to a #fr_value_box_t
3917 *
3918 * @param[in] ctx to allocate any new buffers in.
3919 * @param[in] dst to assign new buffer to.
3920 * @param[in] enumv Aliases for values.
3921 * @param[in] src a nul terminated buffer.
3922 * @param[in] tainted Whether the value came from a trusted source.
3923 * @return
3924 * - 0 on success.
3925 * - -1 on failure.
3926 */
3927int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
3928 char const *src, bool tainted)
3929{
3930 char const *str;
3931
3932 str = talloc_typed_strdup(ctx, src);
3933 if (!str) {
3934 fr_strerror_const("Failed allocating string buffer");
3935 return -1;
3936 }
3937
3938 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
3939 dst->vb_strvalue = str;
3940 dst->vb_length = talloc_array_length(str) - 1;
3941
3942 return 0;
3943}
3944
3945/** Trim the length of the string buffer to match the length of the C string
3946 *
3947 * @param[in] ctx to re-alloc the buffer in.
3948 * @param[in,out] vb to trim.
3949 * @return
3950 * - 0 on success.
3951 * - -1 on failure.
3952 */
3953int fr_value_box_strtrim(TALLOC_CTX *ctx, fr_value_box_t *vb)
3954{
3955 size_t len;
3956 char *str;
3957
3958 if (!fr_cond_assert(vb->type == FR_TYPE_STRING)) return -1;
3959
3960 len = strlen(vb->vb_strvalue);
3961 str = talloc_realloc(ctx, UNCONST(char *, vb->vb_strvalue), char, len + 1);
3962 if (!str) {
3963 fr_strerror_const("Failed re-allocing string buffer");
3964 return -1;
3965 }
3966 vb->vb_length = len;
3967
3968 return 0;
3969}
3970
3971/** Print a formatted string using our internal printf wrapper and assign it to a value box
3972 *
3973 * @param[in] ctx to allocate any new buffers in.
3974 * @param[in] dst to assign new buffer to.
3975 * @param[in] enumv Aliases for values.
3976 * @param[in] fmt The printf format string to process.
3977 * @param[in] tainted Whether the value came from a trusted source.
3978 * @param[in] ap Substitution arguments.
3979 * @return
3980 * - 0 on success.
3981 * - -1 on failure.
3982 */
3983int fr_value_box_vasprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted,
3984 char const *fmt, va_list ap)
3985{
3986 va_list aq;
3987 char *str;
3988
3989 va_copy(aq, ap); /* See vlog_module_failure_msg for why */
3990 str = fr_vasprintf(ctx, fmt, aq);
3991 va_end(aq);
3992
3993 if (!str) return -1;
3994
3995 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
3996 dst->vb_strvalue = str;
3997 dst->vb_length = talloc_array_length(str) - 1;
3998
3999 return 0;
4000}
4001
4002/** Print a formatted string using our internal printf wrapper and assign it to a value box
4003 *
4004 * @param[in] ctx to allocate any new buffers in.
4005 * @param[in] dst to assign new buffer to.
4006 * @param[in] enumv Aliases for values.
4007 * @param[in] tainted Whether the value came from a trusted source.
4008 * @param[in] fmt The printf format string to process.
4009 * @param[in] ... Substitution arguments.
4010 * @return
4011 * - 0 on success.
4012 * - -1 on failure.
4013 */
4014int fr_value_box_asprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted,
4015 char const *fmt, ...)
4016{
4017 va_list ap;
4018 int ret;
4019
4020 va_start(ap, fmt);
4021 ret = fr_value_box_vasprintf(ctx, dst, enumv, tainted, fmt, ap);
4022 va_end(ap);
4023
4024 return ret;
4025}
4026
4027/** Assign a buffer containing a nul terminated string to a box, but don't copy it
4028 *
4029 * @note Input string will not be duplicated.
4030 *
4031 * @param[in] dst to assign string to.
4032 * @param[in] enumv Aliases for values.
4033 * @param[in] src to copy string from.
4034 * @param[in] tainted Whether the value came from a trusted source.
4035 */
4037 char const *src, bool tainted)
4038{
4039 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4040 dst->vb_strvalue = src;
4041 dst->vb_length = strlen(src);
4042}
4043
4044/** Free the existing buffer (if talloced) associated with the valuebox, and replace it with a new one
4045 *
4046 * @note Input string will not be duplicated.
4047 *
4048 * @param[in] vb to replace string in.
4049 * @param[in] src to assign string from.
4050 * @param[in] len of src.
4051 */
4053{
4055 vb->vb_strvalue = src;
4056 vb->vb_length = len < 0 ? strlen(src) : (size_t)len;
4057}
4058
4059/** Alloc and assign an empty \0 terminated string to a #fr_value_box_t
4060 *
4061 * @param[in] ctx to allocate any new buffers in.
4062 * @param[out] out if non-null where to write a pointer to the new buffer.
4063 * @param[in] dst to assign new buffer to.
4064 * @param[in] enumv Aliases for values.
4065 * @param[in] len of buffer to allocate.
4066 * @param[in] tainted Whether the value came from a trusted source.
4067 * @return
4068 * - 0 on success.
4069 * - -1 on failure.
4070 */
4071int fr_value_box_bstr_alloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4072 size_t len, bool tainted)
4073{
4074 char *str;
4075
4076 str = talloc_zero_array(ctx, char, len + 1);
4077 if (!str) {
4078 fr_strerror_const("Failed allocating string buffer");
4079 return -1;
4080 }
4081 str[len] = '\0';
4082
4083 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4084 dst->vb_strvalue = str;
4085 dst->vb_length = talloc_array_length(str) - 1;
4086
4087 if (out) *out = str;
4088
4089 return 0;
4090}
4091
4092/** Change the length of a buffer already allocated to a value box
4093 *
4094 * @note Do not use on an uninitialised box.
4095 *
4096 * @param[in] ctx to realloc buffer in.
4097 * @param[out] out if non-null where to write a pointer to the new buffer.
4098 * @param[in] dst to realloc buffer for.
4099 * @param[in] len to realloc to (don't include nul byte).
4100 * @return
4101 * - 0 on success.
4102 * - -1 on failure.
4103 */
4104int fr_value_box_bstr_realloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, size_t len)
4105{
4106 size_t clen;
4107 char *cstr;
4108 char *str;
4109
4110 fr_assert(dst->type == FR_TYPE_STRING);
4111
4112 memcpy(&cstr, &dst->vb_strvalue, sizeof(cstr));
4113
4114 clen = talloc_array_length(dst->vb_strvalue) - 1;
4115 if (clen == len) return 0; /* No change */
4116
4117 str = talloc_realloc(ctx, cstr, char, len + 1);
4118 if (!str) {
4119 fr_strerror_printf("Failed reallocing value box buffer to %zu bytes", len + 1);
4120 return -1;
4121 }
4122
4123 /*
4124 * Zero out the additional bytes
4125 */
4126 if (clen < len) {
4127 memset(str + clen, '\0', (len - clen) + 1);
4128 } else {
4129 cstr[len] = '\0';
4130 }
4131 dst->vb_strvalue = str;
4132 dst->vb_length = len;
4133
4134 if (out) *out = str;
4135
4136 return 0;
4137}
4138
4139/** Copy a string to to a #fr_value_box_t
4140 *
4141 * @param[in] ctx to allocate any new buffers in.
4142 * @param[in] dst to assign buffer to.
4143 * @param[in] enumv Aliases for values.
4144 * @param[in] src a string. May be NULL only if len == 0.
4145 * @param[in] len of src.
4146 * @param[in] tainted Whether the value came from a trusted source.
4147 */
4148int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4149 char const *src, size_t len, bool tainted)
4150{
4151 char const *str;
4152
4153 if (unlikely((len > 0) && !src)) {
4154 fr_strerror_printf("Invalid arguments to %s. Len > 0 (%zu) but src string was NULL",
4155 __FUNCTION__, len);
4156 return -1;
4157 }
4158
4159 str = talloc_bstrndup(ctx, src, len);
4160 if (!str) {
4161 fr_strerror_const("Failed allocating string buffer");
4162 return -1;
4163 }
4164
4165 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4166 dst->vb_strvalue = str;
4167 dst->vb_length = len;
4168
4169 return 0;
4170}
4171
4172int fr_value_box_bstrndup_dbuff(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4173 fr_dbuff_t *dbuff, size_t len, bool tainted)
4174{
4175 char *str;
4176
4177 str = talloc_array(ctx, char, len + 1);
4178 if (!str) {
4179 fr_strerror_printf("Failed allocating string buffer");
4180 return -1;
4181 }
4182
4183 if (fr_dbuff_out_memcpy((uint8_t *)str, dbuff, len) < 0) return -1;
4184 str[len] = '\0';
4185
4186 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4187 dst->vb_strvalue = str;
4188 dst->vb_length = len;
4189
4190 return 0;
4191}
4192
4193/** Copy a nul terminated talloced buffer to a #fr_value_box_t
4194 *
4195 * Copy a talloced nul terminated buffer, setting fields in the dst value box appropriately.
4196 *
4197 * The buffer must be \0 terminated, or an error will be returned.
4198 *
4199 * @param[in] ctx to allocate any new buffers in.
4200 * @param[in] dst to assign new buffer to.
4201 * @param[in] enumv Aliases for values.
4202 * @param[in] src a talloced nul terminated buffer.
4203 * @param[in] tainted Whether the value came from a trusted source.
4204 * @return
4205 * - 0 on success.
4206 * - -1 on failure.
4207 */
4208int fr_value_box_bstrdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4209 char const *src, bool tainted)
4210{
4211 size_t len;
4212
4213 (void)talloc_get_type_abort_const(src, char);
4214
4215 len = talloc_array_length(src);
4216 if ((len == 0) || (src[len - 1] != '\0')) {
4217 fr_strerror_const("Input buffer not \\0 terminated");
4218 return -1;
4219 }
4220
4221 return fr_value_box_bstrndup(ctx, dst, enumv, src, len - 1, tainted);
4222}
4223
4224/** Assign a string to to a #fr_value_box_t
4225 *
4226 * @param[in] dst to assign new buffer to.
4227 * @param[in] enumv Aliases for values.
4228 * @param[in] src a string.
4229 * @param[in] len of src.
4230 * @param[in] tainted Whether the value came from a trusted source.
4231 */
4233 char const *src, size_t len, bool tainted)
4234{
4235 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4236 dst->vb_strvalue = src;
4237 dst->vb_length = len;
4238}
4239
4240/** Assign a talloced buffer containing a nul terminated string to a box, but don't copy it
4241 *
4242 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
4243 *
4244 * @param[in] ctx to add reference from. If NULL no reference will be added.
4245 * @param[in] dst to assign string to.
4246 * @param[in] enumv Aliases for values.
4247 * @param[in] src to copy string from.
4248 * @param[in] tainted Whether the value came from a trusted source.
4249 * @return
4250 * - 0 on success.
4251 * - -1 on failure.
4252 */
4254 char const *src, bool tainted)
4255{
4256 size_t len;
4257
4258 (void) talloc_get_type_abort_const(src, char);
4259
4260 len = talloc_array_length(src);
4261 if ((len == 0) || (src[len - 1] != '\0')) {
4262 fr_strerror_const("Input buffer not \\0 terminated");
4263 return -1;
4264 }
4265
4266 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4267 dst->vb_strvalue = ctx ? talloc_reference(ctx, src) : src;
4268 dst->vb_length = len - 1;
4269
4270 return 0;
4271}
4272
4273/** Append bytes from a buffer to an existing #fr_value_box_t
4274 *
4275 * @param[in] ctx Where to allocate any talloc buffers required.
4276 * @param[in] dst value box to append to.
4277 * @param[in] src octets data to append.
4278 * @param[in] len length of octets data.
4279 * @param[in] tainted Whether src is tainted.
4280 * @return
4281 * - 0 on success.
4282 * - -1 on failure.
4283 */
4284int fr_value_box_bstrn_append(TALLOC_CTX *ctx, fr_value_box_t *dst, char const *src, size_t len, bool tainted)
4285{
4286 char *ptr, *nptr;
4287 size_t nlen;
4288
4289 if (len == 0) return 0;
4290
4291 if (dst->type != FR_TYPE_STRING) {
4292 fr_strerror_printf("%s: Expected boxed value of type %s, got type %s", __FUNCTION__,
4294 fr_type_to_str(dst->type));
4295 return -1;
4296 }
4297
4298 ptr = dst->datum.ptr;
4299 if (!fr_cond_assert(ptr)) return -1;
4300
4301 if (talloc_reference_count(ptr) > 0) {
4302 fr_strerror_printf("%s: Boxed value has too many references", __FUNCTION__);
4303 return -1;
4304 }
4305
4306 nlen = dst->vb_length + len + 1;
4307 nptr = talloc_realloc(ctx, ptr, char, dst->vb_length + len + 1);
4308 if (!nptr) {
4309 fr_strerror_printf("%s: Realloc of %s array from %zu to %zu bytes failed",
4310 __FUNCTION__, talloc_get_name(ptr), talloc_array_length(ptr), nlen);
4311 return -1;
4312 }
4313 talloc_set_type(nptr, char);
4314 ptr = nptr;
4315
4316 memcpy(ptr + dst->vb_length, src, len); /* Copy data into the realloced buffer */
4317
4318 dst->tainted = dst->tainted || tainted;
4319 dst->datum.ptr = ptr;
4320 dst->vb_length += len;
4321
4322 ptr[dst->vb_length] = '\0';
4323
4324 return 0;
4325}
4326
4327/** Append a talloced buffer to an existing fr_value_box_t
4328 *
4329 * @param[in] ctx Where to allocate any talloc buffers required.
4330 * @param[in] dst value box to append to.
4331 * @param[in] src string data to append.
4332 * @param[in] tainted Whether src is tainted.
4333 * @return
4334 * - 0 on success.
4335 * - -1 on failure.
4336 */
4337int fr_value_box_bstr_append_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, char const *src, bool tainted)
4338{
4339 size_t len;
4340
4341 (void) talloc_get_type_abort_const(src, char);
4342
4343 len = talloc_array_length(src);
4344 if ((len == 0) || (src[len - 1] != '\0')) {
4345 fr_strerror_const("Input buffer not \\0 terminated");
4346 return -1;
4347 }
4348
4349 return fr_value_box_bstrn_append(ctx, dst, src, len - 1, tainted);
4350}
4351
4352/** Pre-allocate an octets buffer for filling by the caller
4353 *
4354 * @note Buffer will not be zeroed, as it's assumed the caller will be filling it.
4355 *
4356 * @param[in] ctx to allocate any new buffers in.
4357 * @param[out] out If non-null will be filled with a pointer to the
4358 * new buffer.
4359 * @param[in] dst to assign new buffer to.
4360 * @param[in] enumv Aliases for values.
4361 * @param[in] len of data in the buffer. If 0, a zero length
4362 * talloc buffer will be alloced. dst->vb_octets
4363 * will *NOT* be NULL. You should use the length
4364 * field of the box to determine if any value
4365 * is assigned.
4366 * @param[in] tainted Whether the value came from a trusted source.
4367 * @return
4368 * - 0 on success.
4369 * - -1 on failure.
4370 */
4371int fr_value_box_mem_alloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4372 size_t len, bool tainted)
4373{
4374 uint8_t *bin;
4375
4376 bin = talloc_array(ctx, uint8_t, len);
4377 if (!bin) {
4378 fr_strerror_const("Failed allocating octets buffer");
4379 return -1;
4380 }
4381 talloc_set_type(bin, uint8_t);
4382
4383 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4384 dst->vb_octets = bin;
4385 dst->vb_length = len;
4386
4387 if (out) *out = bin;
4388
4389 return 0;
4390}
4391
4392/** Change the length of a buffer already allocated to a value box
4393 *
4394 * @note Do not use on an uninitialised box.
4395 *
4396 * @param[in] ctx to realloc buffer in.
4397 * @param[out] out if non-null where to write a pointer to the new buffer.
4398 * @param[in] dst to realloc buffer for.
4399 * @param[in] len to realloc to.
4400 * @return
4401 * - 0 on success.
4402 * - -1 on failure.
4403 */
4404int fr_value_box_mem_realloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, size_t len)
4405{
4406 size_t clen;
4407 uint8_t *cbin;
4408 uint8_t *bin;
4409
4410 fr_assert(dst->type == FR_TYPE_OCTETS);
4411
4412 memcpy(&cbin, &dst->vb_octets, sizeof(cbin));
4413
4414 clen = talloc_array_length(dst->vb_octets);
4415 if (clen == len) return 0; /* No change */
4416
4417 /*
4418 * Realloc the buffer. If the new length is 0, we
4419 * need to call talloc_array() instead of talloc_realloc()
4420 * as talloc_realloc() will fail.
4421 */
4422 if (len > 0) {
4423 bin = talloc_realloc(ctx, cbin, uint8_t, len);
4424 } else {
4425 bin = talloc_array(ctx, uint8_t, 0);
4426 }
4427 if (!bin) {
4428 fr_strerror_printf("Failed reallocing value box buffer to %zu bytes", len);
4429 return -1;
4430 }
4431
4432 /*
4433 * Only free the original buffer once we've allocated
4434 * a new empty array.
4435 */
4436 if (len == 0) talloc_free(cbin);
4437
4438 /*
4439 * Zero out the additional bytes
4440 */
4441 if (clen < len) memset(bin + clen, 0x00, len - clen);
4442 dst->vb_octets = bin;
4443 dst->vb_length = len;
4444
4445 if (out) *out = bin;
4446
4447 return 0;
4448}
4449
4450/** Copy a buffer to a fr_value_box_t
4451 *
4452 * Copy a buffer containing binary data, setting fields in the dst value box appropriately.
4453 *
4454 * @param[in] ctx to allocate any new buffers in.
4455 * @param[in] dst to assign new buffer to.
4456 * @param[in] enumv Aliases for values.
4457 * @param[in] src a buffer.
4458 * @param[in] len of data in the buffer. If 0, a zero length
4459 * talloc buffer will be alloced. dst->vb_octets
4460 * will *NOT* be NULL. You should use the length
4461 * field of the box to determine if any value
4462 * is assigned.
4463 * @param[in] tainted Whether the value came from a trusted source.
4464 * @return
4465 * - 0 on success.
4466 * - -1 on failure.
4467 */
4468int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4469 uint8_t const *src, size_t len, bool tainted)
4470{
4471 uint8_t *bin;
4472
4473 if (unlikely((len > 0) && !src)) {
4474 fr_strerror_printf("Invalid arguments to %s. Len > 0 (%zu) but src was NULL",
4475 __FUNCTION__, len);
4476 return -1;
4477 }
4478
4479 bin = talloc_memdup(ctx, src, len);
4480 if (!bin) {
4481 fr_strerror_const("Failed allocating octets buffer");
4482 return -1;
4483 }
4484 talloc_set_type(bin, uint8_t);
4485
4486 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4487 dst->vb_octets = bin;
4488 dst->vb_length = len;
4489
4490 return 0;
4491}
4492
4493int fr_value_box_memdup_dbuff(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4494 fr_dbuff_t *dbuff, size_t len, bool tainted)
4495{
4496 uint8_t *bin;
4497
4498 bin = talloc_size(ctx, len);
4499 if (!bin) {
4500 fr_strerror_printf("Failed allocating octets buffer");
4501 return -1;
4502 }
4503 if (fr_dbuff_out_memcpy(bin, dbuff, len) < (ssize_t) len) return -1;
4504 talloc_set_type(bin, uint8_t);
4505
4506 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4507 dst->vb_octets = bin;
4508 dst->vb_length = len;
4509
4510 return 0;
4511}
4512
4513/** Copy a talloced buffer to a fr_value_box_t
4514 *
4515 * Copy a buffer containing binary data, setting fields in the dst value box appropriately.
4516 *
4517 * @param[in] ctx to allocate any new buffers in.
4518 * @param[in] dst to assign new buffer to.
4519 * @param[in] enumv Aliases for values.
4520 * @param[in] src a buffer.
4521 * @param[in] tainted Whether the value came from a trusted source.
4522 * @return
4523 * - 0 on success.
4524 * - -1 on failure.
4525 */
4526int fr_value_box_memdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4527 uint8_t const *src, bool tainted)
4528{
4530
4531 return fr_value_box_memdup(ctx, dst, enumv, src, talloc_array_length(src), tainted);
4532}
4533
4534/** Assign a buffer to a box, but don't copy it
4535 *
4536 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
4537 *
4538 * Caller should set dst->taint = true, where the value was acquired from an untrusted source.
4539 *
4540 * @note Will free any exiting buffers associated with the value box.
4541 *
4542 * @param[in] dst to assign buffer to.
4543 * @param[in] enumv Aliases for values.
4544 * @param[in] src a talloced buffer.
4545 * @param[in] len of buffer.
4546 * @param[in] tainted Whether the value came from a trusted source.
4547 */
4549 uint8_t const *src, size_t len, bool tainted)
4550{
4551 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4552 dst->vb_octets = src;
4553 dst->vb_length = len;
4554}
4555
4556/** Assign a talloced buffer to a box, but don't copy it
4557 *
4558 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
4559 *
4560 * @param[in] ctx to allocate any new buffers in.
4561 * @param[in] dst to assign buffer to.
4562 * @param[in] enumv Aliases for values.
4563 * @param[in] src a talloced buffer.
4564 * @param[in] tainted Whether the value came from a trusted source.
4565 */
4567 uint8_t const *src, bool tainted)
4568{
4570
4571 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4572 dst->vb_octets = ctx ? talloc_reference(ctx, src) : src;
4573 dst->vb_length = talloc_array_length(src);
4574}
4575
4576/** Append data to an existing fr_value_box_t
4577 *
4578 * @param[in] ctx Where to allocate any talloc buffers required.
4579 * @param[in] dst value box to append to.
4580 * @param[in] src octets data to append.
4581 * @param[in] len length of octets data.
4582 * @param[in] tainted Whether src is tainted.
4583 * @return
4584 * - 0 on success.
4585 * - -1 on failure.
4586 */
4587int fr_value_box_mem_append(TALLOC_CTX *ctx, fr_value_box_t *dst, uint8_t const *src, size_t len, bool tainted)
4588{
4589 uint8_t *nptr;
4590 size_t nlen;
4591
4592 if (len == 0) return 0;
4593
4594 if (dst->type != FR_TYPE_OCTETS) {
4595 fr_strerror_printf("%s: Expected boxed value of type %s, got type %s", __FUNCTION__,
4597 fr_type_to_str(dst->type));
4598 return -1;
4599 }
4600
4601 if (!fr_cond_assert(dst->datum.ptr)) return -1;
4602
4603 if (talloc_reference_count(dst->datum.ptr) > 0) {
4604 fr_strerror_printf("%s: Boxed value has too many references", __FUNCTION__);
4605 return -1;
4606 }
4607
4608 nlen = dst->vb_length + len;
4609 nptr = talloc_realloc(ctx, dst->datum.ptr, uint8_t, dst->vb_length + len);
4610 if (!nptr) {
4611 fr_strerror_printf("%s: Realloc of %s array from %zu to %zu bytes failed",
4612 __FUNCTION__,
4613 talloc_get_name(dst->datum.ptr),
4614 talloc_array_length((uint8_t const *)dst->datum.ptr), nlen);
4615 return -1;
4616 }
4617
4618 memcpy(nptr + dst->vb_length, src, len); /* Copy data into the realloced buffer */
4619
4620 dst->tainted = dst->tainted || tainted;
4621 dst->datum.ptr = nptr;
4622 dst->vb_length += len;
4623
4624 return 0;
4625}
4626
4627/** Append a talloc buffer to an existing fr_value_box_t
4628 *
4629 * @param[in] ctx Where to allocate any talloc buffers required.
4630 * @param[in] dst value box to append to.
4631 * @param[in] src octets data to append.
4632 * @param[in] tainted Whether src is tainted.
4633 * @return
4634 * - 0 on success.
4635 * - -1 on failure.
4636 */
4637int fr_value_box_mem_append_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, uint8_t const *src, bool tainted)
4638{
4639 return fr_value_box_mem_append(ctx, dst, src, talloc_array_length(src), tainted);
4640}
4641
4642/** Increment a boxed value
4643 *
4644 * Implements safe integer overflow.
4645 *
4646 * @param[in] vb to increment.
4647 */
4649{
4650 switch (vb->type) {
4651 case FR_TYPE_UINT8:
4652 vb->vb_uint8 = vb->vb_uint8 == UINT8_MAX ? 0 : vb->vb_uint8 + 1;
4653 return;
4654
4655 case FR_TYPE_UINT16:
4656 vb->vb_uint16 = vb->vb_uint16 == UINT16_MAX ? 0 : vb->vb_uint16 + 1;
4657 return;
4658
4659 case FR_TYPE_UINT32:
4660 vb->vb_uint32 = vb->vb_uint32 == UINT32_MAX ? 0 : vb->vb_uint32 + 1;
4661 return;
4662
4663 case FR_TYPE_UINT64:
4664 vb->vb_uint64 = vb->vb_uint64 == UINT64_MAX ? 0 : vb->vb_uint64 + 1;
4665 return;
4666
4667 case FR_TYPE_INT8:
4668 vb->vb_int8 = vb->vb_int8 == INT8_MAX ? INT8_MIN : vb->vb_int8 + 1;
4669 return;
4670
4671 case FR_TYPE_INT16:
4672 vb->vb_int16 = vb->vb_int16 == INT16_MAX ? INT16_MIN : vb->vb_int16 + 1;
4673 return;
4674
4675 case FR_TYPE_INT32:
4676 vb->vb_int32 = vb->vb_int32 == INT32_MAX ? INT32_MIN : vb->vb_int32 + 1;
4677 return;
4678
4679 case FR_TYPE_INT64:
4680 vb->vb_int64 = vb->vb_int64 == INT64_MAX ? INT64_MIN : vb->vb_int64 + 1;
4681 return;
4682
4683 default:
4684 return;
4685 }
4686}
4687
4688/** Convert integer encoded as string to a fr_value_box_t type
4689 *
4690 * @param[out] dst where to write parsed value.
4691 * @param[in] dst_type type of integer to convert string to.
4692 * @param[in] dst_enumv Enumeration values.
4693 * @param[in] in String to convert to integer.
4694 * @param[in] rules for parsing string.
4695 * @param[in] tainted Whether the value came from a trusted source.
4696 * @return
4697 * - >= 0 on success (number of bytes parsed).
4698 * - < 0 on error (where the parse error occurred).
4699 */
4700static inline CC_HINT(always_inline)
4702 fr_dict_attr_t const *dst_enumv,
4703 fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules, bool tainted)
4704{
4705 fr_slen_t slen;
4707
4708 fr_value_box_init(dst, dst_type, dst_enumv, tainted);
4709
4710 switch (dst_type) {
4711 case FR_TYPE_UINT8:
4712 slen = fr_sbuff_out(&err, &dst->vb_uint8, in);
4713 break;
4714
4715 case FR_TYPE_UINT16:
4716 slen = fr_sbuff_out(&err, &dst->vb_uint16, in);
4717 break;
4718
4719 case FR_TYPE_UINT32:
4720 slen = fr_sbuff_out(&err, &dst->vb_uint32, in);
4721 break;
4722
4723 case FR_TYPE_UINT64:
4724 slen = fr_sbuff_out(&err, &dst->vb_uint64, in);
4725 break;
4726
4727 case FR_TYPE_INT8:
4728 slen = fr_sbuff_out(&err, &dst->vb_int8, in);
4729 break;
4730
4731 case FR_TYPE_INT16:
4732 slen = fr_sbuff_out(&err, &dst->vb_int16, in);
4733 break;
4734
4735 case FR_TYPE_INT32:
4736 slen = fr_sbuff_out(&err, &dst->vb_int32, in);
4737 break;
4738
4739 case FR_TYPE_INT64:
4740 slen = fr_sbuff_out(&err, &dst->vb_int64, in);
4741 break;
4742
4743 case FR_TYPE_SIZE:
4744 slen = fr_sbuff_out(&err, &dst->vb_size, in);
4745 break;
4746
4747 case FR_TYPE_FLOAT32:
4748 slen = fr_sbuff_out(&err, &dst->vb_float32, in);
4749 break;
4750
4751 case FR_TYPE_FLOAT64:
4752 slen = fr_sbuff_out(&err, &dst->vb_float64, in);
4753 break;
4754
4755 default:
4756 fr_assert_fail(NULL);
4757 return -1;
4758 }
4759
4760 if (slen < 0) {
4761 /*
4762 * If an enumeration attribute is provided and we
4763 * don't find an integer, assume this is an enumv
4764 * lookup fail, and produce a better error.
4765 */
4766 if (dst_enumv && dst_enumv->flags.has_value && (err == FR_SBUFF_PARSE_ERROR_NOT_FOUND)) {
4767 fr_sbuff_t our_in = FR_SBUFF(in);
4768 fr_sbuff_adv_until(&our_in, SIZE_MAX, rules->terminals,
4769 rules->escapes ? rules->escapes->chr : '\0');
4770
4771 fr_strerror_printf("Invalid enumeration value \"%pV\" for attribute %s",
4773 dst_enumv->name);
4774 return -1;
4775 }
4776
4778 fr_strerror_printf("Failed parsing string as type '%s'",
4779 fr_type_to_str(dst_type));
4780 } else {
4781 fr_sbuff_parse_error_to_strerror(err);
4782 }
4783 }
4784
4785
4786 return slen;
4787}
4788
4789/** Convert string value to a fr_value_box_t type
4790 *
4791 * @param[in] ctx to alloc strings in.
4792 * @param[out] dst where to write parsed value.
4793 * @param[in,out] dst_type of value data to create/dst_type of value created.
4794 * @param[in] dst_enumv fr_dict_attr_t with string names for uint32 values.
4795 * @param[in] in sbuff to read data from.
4796 * @param[in] rules unescape and termination rules.
4797 * @param[in] tainted Whether the value came from a trusted source.
4798 * @return
4799 * - >0 on success.
4800 * - <= 0 on parse error.
4801 */
4803 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
4804 fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules, bool tainted)
4805{
4806 static fr_sbuff_parse_rules_t default_rules;
4807 fr_sbuff_t *unescaped = NULL;
4808 fr_sbuff_t our_in = FR_SBUFF(in);
4809 fr_ipaddr_t addr;
4810 fr_slen_t slen;
4811 char buffer[256];
4812
4813 if (!rules) rules = &default_rules;
4814
4816
4817 /*
4818 * Lookup any names before continuing
4819 */
4820 if (dst_enumv && dst_enumv->flags.has_value) {
4821 size_t name_len;
4822 fr_dict_enum_value_t *enumv;
4823
4824 /*
4825 * @todo - allow enum names for IPv6 addresses and prefixes. See also
4826 * tmpl_afrom_enum().
4827 */
4828 (void) fr_sbuff_adv_past_str_literal(&our_in, "::");
4829
4830 /*
4831 * If there is no escaping, then we ignore the terminals. The list of allowed characters
4832 * in enum names will ensure that the parsing doesn't go too far. i.e. to '\r', '\n'. '}', etc.
4833 *
4834 * The reason is that the list of terminals may include things like '-', which is also a
4835 * valid character in enum names. We don't want to parse "Framed-User" as "Framed - User".
4836 */
4837 if (!rules->escapes) {
4838 size_t len;
4840
4841 fr_sbuff_marker(&m, &our_in);
4842
4843 len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in),
4845 fr_sbuff_set(&our_in, &m);
4846 fr_sbuff_marker_release(&m);
4847
4848 if (!len) goto parse; /* Zero length name can't match enum */
4849
4850 enumv = fr_dict_enum_by_name(dst_enumv, fr_sbuff_current(&our_in), len);
4851 if (!enumv) {
4852 goto parse; /* No enumeration matches escaped string */
4853 }
4854
4855 (void) fr_sbuff_advance(&our_in, len);
4856 goto cast_enum;
4857 }
4858
4859 /*
4860 * Create a thread-local extensible buffer to
4861 * store unescaped data.
4862 *
4863 * This is created once per-thread (the first time
4864 * this function is called), and freed when the
4865 * thread exits.
4866 */
4867 FR_SBUFF_TALLOC_THREAD_LOCAL(&unescaped, 256, 4096);
4868
4869 /*
4870 * This function only does escaping until a terminal character, such as '-'. So
4871 * Framed-User will get parsed as "Framed - User".
4872 *
4873 * Pretty much no other enum has this problem. For Service-Type, it defines "Framed" ss
4874 * an equivalent name to "Framed-User". The parser sees "Framed-User", stops at the '-',
4875 * and then finds the enum named "Framed". It then returns the trailing "-User" as
4876 * something more to parse.
4877 *
4878 * As a result, when the user passes in "Framed-User", the output is "Framed-User -
4879 * User", which is more than a bit surprising.
4880 */
4881 name_len = fr_sbuff_out_unescape_until(unescaped, &our_in, SIZE_MAX,
4882 rules->terminals, rules->escapes);
4883 if (!name_len) {
4884 fr_sbuff_set_to_start(&our_in);
4885 goto parse; /* Zero length name can't match enum */
4886 }
4887
4888 enumv = fr_dict_enum_by_name(dst_enumv, fr_sbuff_start(unescaped), fr_sbuff_used(unescaped));
4889 if (!enumv) {
4890 fr_sbuff_set_to_start(&our_in);
4891 goto parse; /* No enumeration matches escaped string */
4892 }
4893
4894 cast_enum:
4895 /*
4896 * dst_type may not match enumv type
4897 */
4898 if (fr_value_box_cast(ctx, dst, dst_type, dst_enumv, enumv->value) < 0) return -1;
4899
4900 FR_SBUFF_SET_RETURN(in, &our_in);
4901 }
4902
4903parse:
4904 /*
4905 * It's a variable ret src->dst_type so we just alloc a new buffer
4906 * of size len and copy.
4907 */
4908 switch (dst_type) {
4909 case FR_TYPE_STRING:
4910 /*
4911 * We've not unescaped the string yet, produce an unescaped version
4912 */
4913 if (!dst_enumv || !unescaped) {
4914 char *buff;
4915
4916 if (unlikely(fr_sbuff_out_aunescape_until(ctx, &buff, &our_in, SIZE_MAX,
4917 rules->terminals, rules->escapes) < 0)) {
4918 return -1;
4919 }
4920 fr_value_box_bstrdup_buffer_shallow(NULL, dst, dst_enumv, buff, tainted);
4921 /*
4922 * We already have an unescaped version, just use that
4923 */
4924 } else {
4925 fr_value_box_bstrndup(ctx, dst, dst_enumv,
4926 fr_sbuff_start(unescaped), fr_sbuff_used(unescaped), tainted);
4927 }
4928 FR_SBUFF_SET_RETURN(in, &our_in);
4929
4930 /* raw octets: 0x01020304... */
4931 case FR_TYPE_OCTETS:
4932 {
4933 fr_sbuff_marker_t hex_start;
4934 size_t hex_len;
4935 uint8_t *bin_buff;
4936
4937 /*
4938 * If there's escape sequences that need to be processed
4939 * or the string doesn't start with 0x, then assume this
4940 * is literal data, not hex encoded data.
4941 */
4942 if (rules->escapes || !fr_sbuff_adv_past_strcase_literal(&our_in, "0x")) {
4943 if (!dst_enumv || !unescaped) {
4944 char *buff = NULL;
4945 uint8_t *bin;
4946
4947 if (fr_sbuff_extend(&our_in)) {
4948 fr_sbuff_out_aunescape_until(ctx, &buff, &our_in, SIZE_MAX,
4949 rules->terminals, rules->escapes);
4950
4951 if (talloc_array_length(buff) == 1) {
4953 goto zero;
4954 }
4955
4956 bin = talloc_realloc(ctx, buff, uint8_t, talloc_array_length(buff) - 1);
4957 if (unlikely(!bin)) {
4958 fr_strerror_const("Failed trimming string buffer");
4960 return -1;
4961 }
4962 talloc_set_type(bin, uint8_t); /* talloc_realloc doesn't do this */
4963 /*
4964 * Input data is zero
4965 *
4966 * talloc realloc will refuse to realloc to
4967 * a zero length buffer. This is probably
4968 * a bug, because we can create zero length
4969 * arrays normally
4970 */
4971 } else {
4972 zero:
4973 bin = talloc_zero_array(ctx, uint8_t, 0);
4974 }
4975
4976 fr_value_box_memdup_buffer_shallow(NULL, dst, dst_enumv, bin, tainted);
4977 /*
4978 * We already have an unescaped version, just use that
4979 */
4980 } else {
4981 fr_value_box_memdup(ctx, dst, dst_enumv,
4982 (uint8_t *)fr_sbuff_start(unescaped),
4983 fr_sbuff_used(unescaped), tainted);
4984 }
4985 FR_SBUFF_SET_RETURN(in, &our_in);
4986 }
4987
4988 fr_sbuff_marker(&hex_start, &our_in); /* Record where the hexits start */
4989
4990 /*
4991 * Find the end of the hex sequence.
4992 *
4993 * We don't technically need to do this, fr_base16_decode
4994 * will find the end on its own.
4995 *
4996 * We do this so we can alloc the correct sized
4997 * output buffer.
4998 */
4999 hex_len = fr_sbuff_adv_past_allowed(&our_in, SIZE_MAX, sbuff_char_class_hex, rules->terminals);
5000 if (hex_len == 0) {
5001 if (fr_value_box_memdup(ctx, dst, dst_enumv, (uint8_t[]){ 0x00 }, 0, tainted) < 0) return -1;
5002 FR_SBUFF_SET_RETURN(in, &our_in);
5003 }
5004
5005 if ((hex_len & 0x01) != 0) {
5006 fr_strerror_printf("Length of hex string is not even, got %zu bytes", hex_len);
5007 FR_SBUFF_ERROR_RETURN(&our_in);
5008 }
5009
5010 /*
5011 * Pre-allocate the bin buff and initialise the box
5012 */
5013 if (fr_value_box_mem_alloc(ctx, &bin_buff, dst, dst_enumv, (hex_len >> 1), tainted) < 0) return -1;
5014
5015 /*
5016 * Reset to the start of the hex string
5017 */
5018 fr_sbuff_set(&our_in, &hex_start);
5019
5020 if (unlikely(fr_base16_decode(NULL, &FR_DBUFF_TMP(bin_buff, hex_len), &our_in, false) < 0)) {
5021 talloc_free(bin_buff);
5022 FR_SBUFF_ERROR_RETURN(&our_in);
5023 }
5024
5025 FR_SBUFF_SET_RETURN(in, &our_in);
5026 }
5027
5028 case FR_TYPE_IPV4_ADDR:
5029 {
5030 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5031 if (!name_len) return 0;
5032
5033 if (fr_inet_pton4(&addr, fr_sbuff_current(in), name_len,
5034 fr_hostname_lookups, false, true) < 0) return -1;
5035
5036 /*
5037 * We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
5038 * print them this way.
5039 */
5040 if (addr.prefix != 32) {
5041 fail_ipv4_prefix:
5042 fr_strerror_printf("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted "
5043 "for non-prefix types", addr.prefix);
5044 return -1;
5045 }
5046
5047 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5048 }
5049 goto finish;
5050
5052 {
5053 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5054 if (!name_len) return 0;
5055
5056 if (fr_inet_pton4(&dst->vb_ip, fr_sbuff_current(in), name_len,
5057 fr_hostname_lookups, false, true) < 0) return -1;
5058 }
5059 goto finish;
5060
5061 case FR_TYPE_IPV6_ADDR:
5062 {
5063 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5064 if (!name_len) return 0;
5065
5066 /*
5067 * Parse scope, too.
5068 */
5069 if (fr_sbuff_next_if_char(&our_in, '%')) {
5070 name_len += fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_uint, rules->terminals);
5071 }
5072
5073 if (fr_inet_pton6(&addr, fr_sbuff_current(in), name_len,
5074 fr_hostname_lookups, false, true) < 0) return -1;
5075
5076 /*
5077 * We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
5078 * print them this way.
5079 */
5080 if (addr.prefix != 128) {
5081 fail_ipv6_prefix:
5082 fr_strerror_printf("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted "
5083 "for non-prefix types", addr.prefix);
5084 return -1;
5085 }
5086
5087 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5088 }
5089 goto finish;
5090
5092 {
5093 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5094 if (!name_len) return 0;
5095
5096 if (fr_inet_pton6(&dst->vb_ip, fr_sbuff_current(in), name_len,
5097 fr_hostname_lookups, false, true) < 0) return -1;
5098 }
5099 goto finish;
5100
5102 {
5103 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5104 if (!name_len) return 0;
5105
5106 /*
5107 * Parse scope, too.
5108 */
5109 if (fr_sbuff_next_if_char(&our_in, '%')) {
5110 name_len += fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_uint, rules->terminals);
5111 }
5112
5113 if (fr_inet_pton(&addr, fr_sbuff_current(in), name_len, AF_UNSPEC,
5114 fr_hostname_lookups, true) < 0) return -1;
5115
5116 if ((addr.af == AF_INET) && (addr.prefix != 32)) {
5117 goto fail_ipv4_prefix;
5118 }
5119
5120 if ((addr.af == AF_INET6) && (addr.prefix != 128)) {
5121 goto fail_ipv6_prefix;
5122 }
5123
5124 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5125 }
5126 goto finish;
5127
5129 {
5130 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5131 if (!name_len) return 0;
5132
5133 if (fr_inet_pton(&dst->vb_ip, fr_sbuff_current(in), name_len, AF_UNSPEC,
5134 fr_hostname_lookups, true) < 0) return -1;
5135 }
5136 goto finish;
5137
5138 case FR_TYPE_UINT8:
5139 case FR_TYPE_UINT16:
5140 case FR_TYPE_UINT32:
5141 case FR_TYPE_UINT64:
5142 case FR_TYPE_INT8:
5143 case FR_TYPE_INT16:
5144 case FR_TYPE_INT32:
5145 case FR_TYPE_INT64:
5146 case FR_TYPE_FLOAT32:
5147 case FR_TYPE_FLOAT64:
5148 return fr_value_box_from_numeric_substr(dst, dst_type, dst_enumv, in, rules, tainted);
5149
5150 case FR_TYPE_SIZE:
5151 if (fr_size_from_str(&dst->datum.size, &our_in) < 0) return -1;
5152 goto finish;
5153
5154 case FR_TYPE_BOOL:
5155 fr_value_box_init(dst, dst_type, dst_enumv, tainted);
5156
5157 /*
5158 * Quoted boolean values are "yes", "no", "true", "false"
5159 */
5160 slen = fr_sbuff_out(NULL, &dst->vb_bool, in);
5161 if (slen >= 0) return slen;
5162
5163 /*
5164 * For barewords we also allow 0 for false and any other
5165 * integer value for true.
5166 */
5167 if (!rules->escapes) {
5168 int64_t stmp;
5169 uint64_t utmp;
5170
5171 slen = fr_sbuff_out(NULL, &stmp, in);
5172 if (slen >= 0) {
5173 dst->vb_bool = (stmp != 0);
5174 return slen;
5175 }
5176
5177 slen = fr_sbuff_out(NULL, &utmp, in);
5178 if (slen >= 0) {
5179 dst->vb_bool = (utmp != 0);
5180 return slen;
5181 }
5182 }
5183
5184 fr_strerror_const("Invalid boolean value. Accepted values are "
5185 "\"yes\", \"no\", \"true\", \"false\" or any unquoted integer");
5186
5187 return slen; /* Just whatever the last error offset was */
5188
5189 case FR_TYPE_ETHERNET:
5190 {
5191 uint64_t num;
5192 fr_ethernet_t ether;
5193 fr_dbuff_t dbuff;
5195
5196 fr_dbuff_init(&dbuff, ether.addr, sizeof(ether.addr));
5197
5198 /*
5199 * Convert things which are obviously integers to Ethernet addresses
5200 *
5201 * We assume the number is the decimal
5202 * representation of the ethernet address.
5203 * i.e. the ethernet address converted to a
5204 * number, and printed.
5205 *
5206 * The string gets converted to a network-order
5207 * 8-byte number, and then the lower bytes of
5208 * that get copied to the ethernet address.
5209 *
5210 * Note: We need to check for a terminal sequence
5211 * after the number, else we may just end up
5212 * parsing the first hexit and returning.
5213 *
5214 * i.e. 1c:00:00:00:00 -> 1
5215 */
5216 if ((fr_sbuff_out(NULL, &num, &our_in) > 0) && fr_sbuff_is_terminal(&our_in, rules->terminals)) {
5217 num = htonll(num);
5218
5219 FR_DBUFF_IN_MEMCPY_RETURN(&dbuff, ((uint8_t *) &num) + 2, sizeof(dst->vb_ether));
5220 fr_value_box_ethernet_addr(dst, dst_enumv, &ether, tainted);
5221
5222 FR_SBUFF_SET_RETURN(in, &our_in);
5223 }
5224
5225 fr_sbuff_set_to_start(&our_in);
5226
5227 fr_base16_decode(&err, &dbuff, &our_in, true);
5228 if (err != FR_SBUFF_PARSE_OK) {
5229 ether_error:
5230 fr_sbuff_parse_error_to_strerror(err);
5231 FR_SBUFF_ERROR_RETURN(&our_in);
5232 }
5233
5234 if (!fr_sbuff_next_if_char(&our_in, ':')) {
5235 ether_sep_error:
5236 fr_strerror_const("Missing separator, expected ':'");
5237 FR_SBUFF_ERROR_RETURN(&our_in);
5238 }
5239
5240 fr_base16_decode(&err, &dbuff, &our_in, true);
5241 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5242
5243 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5244
5245 fr_base16_decode(&err, &dbuff, &our_in, true);
5246 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5247
5248 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5249
5250 fr_base16_decode(&err, &dbuff, &our_in, true);
5251 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5252
5253 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5254
5255 fr_base16_decode(&err, &dbuff, &our_in, true);
5256 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5257
5258 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5259
5260 fr_base16_decode(&err, &dbuff, &our_in, true);
5261 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5262
5263 fr_value_box_ethernet_addr(dst, dst_enumv, (fr_ethernet_t * const)fr_dbuff_start(&dbuff), tainted);
5264
5265 FR_SBUFF_SET_RETURN(in, &our_in);
5266 }
5267
5268 case FR_TYPE_TIME_DELTA:
5269 fr_value_box_init(dst, FR_TYPE_TIME_DELTA, dst_enumv, tainted);
5270
5271 slen = fr_time_delta_from_substr(&dst->datum.time_delta, &our_in,
5272 dst_enumv ? dst_enumv->flags.flag_time_res : FR_TIME_RES_SEC,
5273 false, rules->terminals);
5274 if (slen < 0) return slen;
5275 FR_SBUFF_SET_RETURN(in, &our_in);
5276
5277 case FR_TYPE_NULL:
5278 if (!rules->escapes && fr_sbuff_adv_past_str_literal(&our_in, "NULL")) {
5279 fr_value_box_init(dst, dst_type, dst_enumv, tainted);
5280 FR_SBUFF_SET_RETURN(in, &our_in);
5281 }
5282
5283 fr_strerror_const("String value was not NULL");
5284 return -1;
5285
5286 /*
5287 * Dealt with below
5288 */
5289 default:
5290 break;
5291 }
5292
5293 /*
5294 * We may have terminals. If so, respect them.
5295 */
5296 if (rules && rules->terminals) {
5297 size_t len;
5298
5299 len = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(buffer, sizeof(buffer)), &our_in, SIZE_MAX,
5300 rules->terminals, rules->escapes);
5301 if (len >= sizeof(buffer)) goto too_small;
5302
5303 buffer[len] = '\0';
5304
5305 } else {
5306 /*
5307 * It's a fixed size src->dst_type, copy to a temporary buffer and
5308 * \0 terminate.
5309 *
5310 * @todo - note that this brute-force copy means that the input sbuff
5311 * is NOT advanced, and this function will return 0, even though it parsed data!
5312 */
5313 if (fr_sbuff_remaining(in) >= sizeof(buffer)) {
5314 too_small:
5315 fr_strerror_const("Temporary buffer too small");
5316 return -1;
5317 }
5318
5320 buffer[fr_sbuff_remaining(in)] = '\0';
5321 }
5322
5323 switch (dst_type) {
5324 case FR_TYPE_DATE:
5325 {
5326 if (dst_enumv) {
5327 if (fr_unix_time_from_str(&dst->vb_date, buffer, dst_enumv->flags.flag_time_res) < 0) return -1;
5328 } else {
5329 if (fr_unix_time_from_str(&dst->vb_date, buffer, FR_TIME_RES_SEC) < 0) return -1;
5330 }
5331
5332 dst->enumv = dst_enumv;
5333 }
5334 break;
5335
5336 case FR_TYPE_IFID:
5337 if (fr_inet_ifid_pton((void *) dst->vb_ifid, buffer) == NULL) {
5338 fr_strerror_printf("Failed to parse interface-id string \"%s\"", buffer);
5339 return -1;
5340 }
5341 break;
5342
5343 default:
5344 fr_strerror_printf("Cannot parse input as data type %s", fr_type_to_str(dst_type));
5345 return -1;
5346 }
5347
5348finish:
5349 dst->type = dst_type;
5350 dst->tainted = tainted;
5351
5352 /*
5353 * Fixup enumvs
5354 */
5355 dst->enumv = dst_enumv;
5356 fr_value_box_list_entry_init(dst);
5357
5358 FR_SBUFF_SET_RETURN(in, &our_in);
5359}
5360
5362 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
5363 char const *in, size_t inlen,
5364 fr_sbuff_unescape_rules_t const *erules, bool tainted)
5365{
5366 ssize_t slen;
5367 fr_sbuff_parse_rules_t prules = { .escapes = erules };
5368
5369 slen = fr_value_box_from_substr(ctx, dst, dst_type, dst_enumv, &FR_SBUFF_IN(in, inlen), &prules, tainted);
5370 if (slen <= 0) return slen;
5371
5372 if (slen != (ssize_t)inlen) {
5373 fr_strerror_printf("Failed parsing '%s'. %zu bytes of trailing data after string value \"%pV\"",
5374 fr_type_to_str(dst_type),
5375 inlen - slen,
5376 fr_box_strvalue_len(in + slen, inlen - slen));
5377 return (slen - inlen) - 1;
5378 }
5379
5380 return slen;
5381}
5382
5383/** Print one boxed value to a string
5384 *
5385 * This function should primarily be used when a #fr_value_box_t is being
5386 * serialized in some non-standard way, i.e. as a value for a field
5387 * in a database, in all other instances it's better to use
5388 * #fr_value_box_print_quoted.
5389 *
5390 * @note - this function does NOT respect tainting! The escaping rules
5391 * are ONLY for escaping quotation characters, CR, LF, etc.
5392 *
5393 * @param[in] out Where to write the printed string.
5394 * @param[in] data Value box to print.
5395 * @param[in] e_rules To apply to FR_TYPE_STRING types, for escaping quotation characters _only_.
5396 * Is not currently applied to any other box type.
5397 */