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: aef20f9768e87368d647c3e0ce7bbf5f07f71e76 $")
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 fr_value_box_init(dst, FR_TYPE_STRING, dst_enumv, false);
2216
2217 switch (src->type) {
2218 /*
2219 * The presentation format of octets is hex
2220 * What we actually want here is the raw string
2221 */
2222 case FR_TYPE_OCTETS:
2223 fr_value_box_safety_copy(dst, src);
2224 return fr_value_box_bstrndup(ctx, dst, dst_enumv,
2225 (char const *)src->vb_octets, src->vb_length, src->tainted);
2226
2227 case FR_TYPE_GROUP:
2229 dst, UNCONST(fr_value_box_list_t *, &src->vb_group),
2232 SIZE_MAX);
2233
2234 /*
2235 * Get the presentation format
2236 */
2237 default:
2238 {
2239 char *str;
2240
2241 fr_value_box_aprint(ctx, &str, src, NULL);
2242 if (unlikely(!str)) return -1;
2243
2245 return fr_value_box_bstrdup_buffer_shallow(NULL, dst, dst_enumv, str, src->tainted);
2246 }
2247 }
2248}
2249
2250/** Convert any supported type to octets
2251 *
2252 * All non-structural types are allowed.
2253 *
2254 * @param ctx unused.
2255 * @param dst Where to write result of casting.
2256 * @param dst_type to cast to.
2257 * @param dst_enumv enumeration values.
2258 * @param src Input data.
2259 */
2260static inline int fr_value_box_cast_to_octets(TALLOC_CTX *ctx, fr_value_box_t *dst,
2261 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2262 fr_value_box_t const *src)
2263{
2264 if (!fr_cond_assert(dst_type == FR_TYPE_OCTETS)) return -1;
2265
2266 fr_value_box_init(dst, FR_TYPE_OCTETS, dst_enumv, false);
2268
2269 switch (src->type) {
2270 /*
2271 * <string> (excluding terminating \0)
2272 */
2273 case FR_TYPE_STRING:
2274 fr_value_box_safety_copy(dst, src);
2275 return fr_value_box_memdup(ctx, dst, dst_enumv,
2276 (uint8_t const *)src->vb_strvalue, src->vb_length, src->tainted);
2277
2278 case FR_TYPE_GROUP:
2280 dst, UNCONST(fr_value_box_list_t *, &src->vb_group),
2283 SIZE_MAX);
2284 /*
2285 * <4 bytes address>
2286 */
2287 case FR_TYPE_IPV4_ADDR:
2288 return fr_value_box_memdup(ctx, dst, dst_enumv,
2289 (uint8_t const *)&src->vb_ip.addr.v4.s_addr,
2290 sizeof(src->vb_ip.addr.v4.s_addr), src->tainted);
2291
2292 /*
2293 * <1 uint8 prefix> + <4 bytes address>
2294 */
2296 {
2297 uint8_t *bin;
2298
2299 if (fr_value_box_mem_alloc(ctx, &bin, dst, dst_enumv,
2300 sizeof(src->vb_ip.addr.v4.s_addr) + 1, src->tainted) < 0) return -1;
2301
2302 bin[0] = src->vb_ip.prefix;
2303 memcpy(&bin[1], (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2304 }
2305 return 0;
2306
2307 /*
2308 * <16 bytes address>
2309 */
2310 case FR_TYPE_IPV6_ADDR:
2311 return fr_value_box_memdup(ctx, dst, dst_enumv,
2312 (uint8_t const *)src->vb_ip.addr.v6.s6_addr,
2313 sizeof(src->vb_ip.addr.v6.s6_addr), src->tainted);
2314
2315 /*
2316 * <1 uint8 prefix> + <1 uint8 scope> + <16 bytes address>
2317 */
2319 {
2320 uint8_t *bin;
2321
2322 if (fr_value_box_mem_alloc(ctx, &bin, dst, dst_enumv,
2323 sizeof(src->vb_ip.addr.v6.s6_addr) + 2, src->tainted) < 0) return -1;
2324 bin[0] = src->vb_ip.scope_id;
2325 bin[1] = src->vb_ip.prefix;
2326 memcpy(&bin[2], src->vb_ip.addr.v6.s6_addr, sizeof(src->vb_ip.addr.v6.s6_addr));
2327 }
2328 return 0;
2329
2330 /*
2331 * Get the raw binary in memory representation
2332 */
2333 case FR_TYPE_NUMERIC:
2334 {
2335 fr_value_box_t tmp;
2336
2337 fr_value_box_hton(&tmp, src); /* Flip any numeric representations */
2338 return fr_value_box_memdup(ctx, dst, dst_enumv,
2339 fr_value_box_raw(&tmp, src->type),
2340 fr_value_box_field_sizes[src->type], src->tainted);
2341 }
2342
2343 default:
2344 /* Not the same talloc_memdup call as above. The above memdup reads data from the dst */
2345 return fr_value_box_memdup(ctx, dst, dst_enumv,
2346 fr_value_box_raw(src, src->type),
2347 fr_value_box_field_sizes[src->type], src->tainted);
2348 }
2349}
2350
2351#define CAST_IP_FIX_COMBO \
2352 case FR_TYPE_COMBO_IP_ADDR: \
2353 if (src->vb_ip.af == AF_INET) { \
2354 src_type = FR_TYPE_IPV4_ADDR; \
2355 } else if (src->vb_ip.af == AF_INET6) { \
2356 src_type = FR_TYPE_IPV6_ADDR; \
2357 } \
2358 break; \
2359 case FR_TYPE_COMBO_IP_PREFIX: \
2360 if (src->vb_ip.af == AF_INET) { \
2361 src_type = FR_TYPE_IPV4_PREFIX; \
2362 } else if (src->vb_ip.af == AF_INET6) { \
2363 src_type = FR_TYPE_IPV6_PREFIX; \
2364 } \
2365 break
2366
2367
2368/** Convert any supported type to an IPv4 address
2369 *
2370 * Allowed input types are:
2371 * - FR_TYPE_IPV6_ADDR (with v4 prefix).
2372 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2373 * - FR_TYPE_IPV6_PREFIX (with v4 prefix and 128bit mask).
2374 * - FR_TYPE_OCTETS (of length 4).
2375 * - FR_TYPE_UINT32
2376 *
2377 * @param ctx unused.
2378 * @param dst Where to write result of casting.
2379 * @param dst_type to cast to.
2380 * @param dst_enumv enumeration values.
2381 * @param src Input data.
2382 */
2383static inline int fr_value_box_cast_to_ipv4addr(TALLOC_CTX *ctx, fr_value_box_t *dst,
2384 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2385 fr_value_box_t const *src)
2386{
2387 fr_type_t src_type = src->type;
2388
2389 fr_assert(dst_type == FR_TYPE_IPV4_ADDR);
2391
2392 switch (src_type) {
2393 case FR_TYPE_STRING:
2394 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2395 src->vb_strvalue, src->vb_length,
2396 NULL);
2397
2399
2400 default:
2401 break;
2402 }
2403
2404 /*
2405 * Pre-initialise box for non-variable types
2406 */
2407 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2408 dst->vb_ip.af = AF_INET;
2409 dst->vb_ip.prefix = 32;
2410 dst->vb_ip.scope_id = 0;
2411
2412 switch (src_type) {
2413 case FR_TYPE_IPV6_ADDR:
2414 if (memcmp(src->vb_ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
2415 bad_v6_prefix_map:
2416 fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
2417 fr_type_to_str(src->type),
2418 fr_type_to_str(dst_type));
2419 return -1;
2420 }
2421
2422 memcpy(&dst->vb_ip.addr.v4, &src->vb_ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
2423 sizeof(dst->vb_ip.addr.v4));
2424
2425 break;
2426
2428 if (src->vb_ip.prefix != 32) {
2429 fr_strerror_printf("Invalid cast from %s to %s. Only /32 (not %i/) prefixes may be "
2430 "cast to IP address types",
2431 fr_type_to_str(src->type),
2432 fr_type_to_str(dst_type),
2433 src->vb_ip.prefix);
2434 return -1;
2435 }
2437
2438 case FR_TYPE_IPV4_ADDR: /* Needed for handling combo addresses */
2439 memcpy(&dst->vb_ip.addr.v4, &src->vb_ip.addr.v4, sizeof(dst->vb_ip.addr.v4));
2440 break;
2441
2443 if (src->vb_ip.prefix != 128) {
2444 fr_strerror_printf("Invalid cast from %s to %s. Only /128 (not /%i) prefixes may be "
2445 "cast to IP address types",
2446 fr_type_to_str(src->type),
2447 fr_type_to_str(dst_type),
2448 src->vb_ip.prefix);
2449 return -1;
2450 }
2451 if (memcmp(&src->vb_ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) goto bad_v6_prefix_map;
2452 memcpy(&dst->vb_ip.addr.v4, &src->vb_ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
2453 sizeof(dst->vb_ip.addr.v4));
2454 break;
2455
2456 case FR_TYPE_OCTETS:
2457 if (src->vb_length != sizeof(dst->vb_ip.addr.v4.s_addr)) {
2458 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2459 fr_type_to_str(src->type),
2460 fr_type_to_str(dst_type),
2461 sizeof(dst->vb_ip.addr.v4.s_addr), src->vb_length);
2462 return -1;
2463 }
2464 memcpy(&dst->vb_ip.addr.v4, src->vb_octets, sizeof(dst->vb_ip.addr.v4.s_addr));
2465 break;
2466
2467 case FR_TYPE_UINT32:
2468 {
2469 uint32_t net;
2470
2471 net = ntohl(src->vb_uint32);
2472 memcpy(&dst->vb_ip.addr.v4, (uint8_t *)&net, sizeof(dst->vb_ip.addr.v4.s_addr));
2473 }
2474 break;
2475
2476 default:
2477 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2478 fr_type_to_str(src->type),
2479 fr_type_to_str(dst_type));
2480 return -1;
2481 }
2482
2483 return 0;
2484}
2485
2486/** Convert any supported type to an IPv6 address
2487 *
2488 * Allowed input types are:
2489 * - FR_TYPE_IPV4_ADDR
2490 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2491 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
2492 * - FR_TYPE_OCTETS (of length 16).
2493 *
2494 * @param ctx unused.
2495 * @param dst Where to write result of casting.
2496 * @param dst_type to cast to.
2497 * @param dst_enumv enumeration values.
2498 * @param src Input data.
2499 */
2500static inline int fr_value_box_cast_to_ipv4prefix(TALLOC_CTX *ctx, fr_value_box_t *dst,
2501 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2502 fr_value_box_t const *src)
2503{
2504 fr_type_t src_type = src->type;
2505
2506 fr_assert(dst_type == FR_TYPE_IPV4_PREFIX);
2508
2509 switch (src_type) {
2510 case FR_TYPE_STRING:
2511 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2512 src->vb_strvalue, src->vb_length,
2513 NULL);
2514
2516
2517 default:
2518 break;
2519 }
2520
2521 /*
2522 * Pre-initialise box for non-variable types
2523 */
2524 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2525 dst->vb_ip.af = AF_INET;
2526 dst->vb_ip.scope_id = 0;
2527
2528 switch (src_type) {
2529 case FR_TYPE_IPV4_PREFIX: /* Needed for handling combo prefixes */
2530 dst->vb_ip.prefix = src->vb_ip.prefix;
2532
2533 case FR_TYPE_IPV4_ADDR:
2534 memcpy(&dst->vb_ip, &src->vb_ip, sizeof(dst->vb_ip));
2535 break;
2536
2537 /*
2538 * Copy the last four bytes, to make an IPv4prefix
2539 */
2540 case FR_TYPE_IPV6_ADDR:
2541 if (memcmp(src->vb_ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
2542 bad_v6_prefix_map:
2543 fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
2544 fr_type_to_str(src->type),
2545 fr_type_to_str(dst_type));
2546 return -1;
2547 }
2548 memcpy(&dst->vb_ip.addr.v4.s_addr, &src->vb_ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
2549 sizeof(dst->vb_ip.addr.v4.s_addr));
2550 dst->vb_ip.prefix = 32;
2551 break;
2552
2554 if (memcmp(src->vb_ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) goto bad_v6_prefix_map;
2555
2556 if (src->vb_ip.prefix < (sizeof(v4_v6_map) << 3)) {
2557 fr_strerror_printf("Invalid cast from %s to %s. Expected prefix >= %u bits got %u bits",
2558 fr_type_to_str(src->type),
2559 fr_type_to_str(dst_type),
2560 (unsigned int)(sizeof(v4_v6_map) << 3), src->vb_ip.prefix);
2561 return -1;
2562 }
2563 memcpy(&dst->vb_ip.addr.v4.s_addr, &src->vb_ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
2564 sizeof(dst->vb_ip.addr.v4.s_addr));
2565
2566 /*
2567 * Subtract the bits used by the v4_v6_map to get the v4 prefix bits
2568 */
2569 dst->vb_ip.prefix = src->vb_ip.prefix - (sizeof(v4_v6_map) << 3);
2570 break;
2571
2572 case FR_TYPE_OCTETS:
2573 if (src->vb_length != sizeof(dst->vb_ip.addr.v4.s_addr) + 1) {
2574 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2575 fr_type_to_str(src->type),
2576 fr_type_to_str(dst_type),
2577 sizeof(dst->vb_ip.addr.v4.s_addr) + 1, src->vb_length);
2578 return -1;
2579 }
2580 dst->vb_ip.prefix = src->vb_octets[0];
2581 memcpy(&dst->vb_ip.addr.v4, &src->vb_octets[1], sizeof(dst->vb_ip.addr.v4.s_addr));
2582 break;
2583
2584 case FR_TYPE_UINT32:
2585 {
2586 uint32_t net;
2587
2588 net = ntohl(src->vb_uint32);
2589 memcpy(&dst->vb_ip.addr.v4, (uint8_t *)&net, sizeof(dst->vb_ip.addr.v4.s_addr));
2590 dst->vb_ip.prefix = 32;
2591 break;
2592 }
2593
2594 default:
2595 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2596 fr_type_to_str(src->type),
2597 fr_type_to_str(dst_type));
2598 return -1;
2599 }
2600
2601 return 0;
2602}
2603
2604/** Convert any supported type to an IPv6 address
2605 *
2606 * Allowed input types are:
2607 * - FR_TYPE_IPV4_ADDR
2608 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2609 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
2610 * - FR_TYPE_OCTETS (of length 16).
2611 *
2612 * @param ctx unused.
2613 * @param dst Where to write result of casting.
2614 * @param dst_type to cast to.
2615 * @param dst_enumv enumeration values.
2616 * @param src Input data.
2617 */
2618static inline int fr_value_box_cast_to_ipv6addr(TALLOC_CTX *ctx, fr_value_box_t *dst,
2619 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2620 fr_value_box_t const *src)
2621{
2622 fr_type_t src_type = src->type;
2623
2624 static_assert((sizeof(v4_v6_map) + sizeof(src->vb_ip.addr.v4)) <=
2625 sizeof(src->vb_ip.addr.v6), "IPv6 storage too small");
2626
2627 fr_assert(dst_type == FR_TYPE_IPV6_ADDR);
2629
2630 switch (src_type) {
2631 case FR_TYPE_STRING:
2632 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2633 src->vb_strvalue, src->vb_length,
2634 NULL);
2635
2637
2638 default:
2639 break;
2640 }
2641
2642 /*
2643 * Pre-initialise box for non-variable types
2644 */
2645 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2646 dst->vb_ip.af = AF_INET6;
2647 dst->vb_ip.prefix = 128;
2648
2649 switch (src_type) {
2650 case FR_TYPE_IPV4_ADDR:
2651 {
2652 uint8_t *p = dst->vb_ip.addr.v6.s6_addr;
2653
2654 /* Add the v4/v6 mapping prefix */
2655 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
2656 p += sizeof(v4_v6_map);
2657 memcpy(p, (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2658 dst->vb_ip.scope_id = 0;
2659 }
2660 break;
2661
2663 {
2664 uint8_t *p = dst->vb_ip.addr.v6.s6_addr;
2665
2666 if (src->vb_ip.prefix != 32) {
2667 fr_strerror_printf("Invalid cast from %s to %s. Only /32 (not /%i) prefixes may be "
2668 "cast to IP address types",
2669 fr_type_to_str(src->type),
2670 fr_type_to_str(dst_type),
2671 src->vb_ip.prefix);
2672 return -1;
2673 }
2674
2675 /* Add the v4/v6 mapping prefix */
2676 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
2677 p += sizeof(v4_v6_map);
2678 memcpy(p, (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2679 dst->vb_ip.scope_id = 0;
2680 }
2681 break;
2682
2684 if (src->vb_ip.prefix != 128) {
2685 fr_strerror_printf("Invalid cast from %s to %s. Only /128 (not /%i) prefixes may be "
2686 "cast to IP address types",
2687 fr_type_to_str(src->type),
2688 fr_type_to_str(dst_type),
2689 src->vb_ip.prefix);
2690 return -1;
2691 }
2693
2694 case FR_TYPE_IPV6_ADDR: /* Needed for handling combo addresses */
2695 memcpy(dst->vb_ip.addr.v6.s6_addr, src->vb_ip.addr.v6.s6_addr,
2696 sizeof(dst->vb_ip.addr.v6.s6_addr));
2697 dst->vb_ip.scope_id = src->vb_ip.scope_id;
2698 break;
2699
2700 case FR_TYPE_OCTETS:
2701 if (src->vb_length != sizeof(dst->vb_ip.addr.v6.s6_addr)) {
2702 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2703 fr_type_to_str(src->type),
2704 fr_type_to_str(dst_type),
2705 sizeof(dst->vb_ip.addr.v6.s6_addr), src->vb_length);
2706 return -1;
2707 }
2708 memcpy(&dst->vb_ip.addr.v6.s6_addr, src->vb_octets, sizeof(dst->vb_ip.addr.v6.s6_addr));
2709 break;
2710
2711 default:
2712 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2713 fr_type_to_str(src->type),
2714 fr_type_to_str(dst_type));
2715 break;
2716 }
2717
2718 return 0;
2719}
2720
2721/** Convert any supported type to an IPv6 address
2722 *
2723 * Allowed input types are:
2724 * - FR_TYPE_IPV4_ADDR
2725 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2726 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
2727 * - FR_TYPE_OCTETS (of length 16).
2728 *
2729 * @param ctx unused.
2730 * @param dst Where to write result of casting.
2731 * @param dst_type to cast to.
2732 * @param dst_enumv enumeration values.
2733 * @param src Input data.
2734 */
2735static inline int fr_value_box_cast_to_ipv6prefix(TALLOC_CTX *ctx, fr_value_box_t *dst,
2736 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2737 fr_value_box_t const *src)
2738{
2739 fr_type_t src_type = src->type;
2740
2741 fr_assert(dst_type == FR_TYPE_IPV6_PREFIX);
2743
2744 switch (src_type) {
2745 case FR_TYPE_STRING:
2746 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2747 src->vb_strvalue, src->vb_length,
2748 NULL);
2749
2751
2752 default:
2753 break;
2754 }
2755
2756 /*
2757 * Pre-initialise box for non-variable types
2758 */
2759 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2760 dst->vb_ip.af = AF_INET6;
2761
2762 switch (src_type) {
2763 case FR_TYPE_IPV4_ADDR:
2764 {
2765 uint8_t *p = dst->vb_ip.addr.v6.s6_addr;
2766
2767 /* Add the v4/v6 mapping prefix */
2768 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
2769 p += sizeof(v4_v6_map);
2770 memcpy(p, (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2771 dst->vb_ip.prefix = 128;
2772 dst->vb_ip.scope_id = 0;
2773 }
2774 break;
2775
2777 {
2778 uint8_t *p = dst->vb_ip.addr.v6.s6_addr;
2779
2780 /* Add the v4/v6 mapping prefix */
2781 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
2782 p += sizeof(v4_v6_map);
2783 memcpy(p, (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2784 dst->vb_ip.prefix = (sizeof(v4_v6_map) << 3) + src->vb_ip.prefix;
2785 dst->vb_ip.scope_id = 0;
2786 }
2787 break;
2788
2789 case FR_TYPE_IPV6_PREFIX: /* Needed for handling combo prefixes */
2790 dst->vb_ip.prefix = src->vb_ip.prefix;
2791 goto v6_common;
2792
2793 case FR_TYPE_IPV6_ADDR:
2794 dst->vb_ip.prefix = 128;
2795 v6_common:
2796 memcpy(dst->vb_ip.addr.v6.s6_addr, src->vb_ip.addr.v6.s6_addr,
2797 sizeof(dst->vb_ip.addr.v6.s6_addr));
2798 dst->vb_ip.scope_id = src->vb_ip.scope_id;
2799 break;
2800
2801 case FR_TYPE_OCTETS:
2802 if (src->vb_length != (sizeof(dst->vb_ip.addr.v6.s6_addr) + 2)) {
2803 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2804 fr_type_to_str(src->type),
2805 fr_type_to_str(dst_type),
2806 sizeof(dst->vb_ip.addr.v6.s6_addr) + 2, src->vb_length);
2807 return -1;
2808 }
2809 dst->vb_ip.scope_id = src->vb_octets[0];
2810 dst->vb_ip.prefix = src->vb_octets[1];
2811 memcpy(&dst->vb_ip.addr.v6.s6_addr, src->vb_octets, sizeof(dst->vb_ip.addr.v6.s6_addr));
2812 break;
2813
2814 default:
2815 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2816 fr_type_to_str(src->type),
2817 fr_type_to_str(dst_type));
2818 return -1;
2819 }
2820 return 0;
2821}
2822
2823/** Convert any supported type to an ethernet address
2824 *
2825 * Allowed input types are:
2826 * - FR_TYPE_STRING ("00:11:22:33:44:55")
2827 * - FR_TYPE_OCTETS (0x001122334455)
2828 *
2829 *
2830 * @param ctx unused.
2831 * @param dst Where to write result of casting.
2832 * @param dst_type to cast to.
2833 * @param dst_enumv enumeration values.
2834 * @param src Input data.
2835 */
2836static inline int fr_value_box_cast_to_ethernet(TALLOC_CTX *ctx, fr_value_box_t *dst,
2837 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2838 fr_value_box_t const *src)
2839{
2840 fr_assert(dst_type == FR_TYPE_ETHERNET);
2842
2843 switch (src->type) {
2844 case FR_TYPE_STRING:
2845 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2846 src->vb_strvalue, src->vb_length,
2847 NULL);
2848
2849 case FR_TYPE_OCTETS:
2850 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
2851
2852 default:
2853 break;
2854 }
2855
2856 /*
2857 * Pre-initialise box for non-variable types
2858 */
2859 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2860
2861 switch (src->type) {
2862 case FR_TYPE_UINT64: {
2863 uint8_t array[8];
2864
2865 fr_nbo_from_uint64(array, src->vb_uint64);
2866
2867 /*
2868 * For OUIs in the DB.
2869 */
2870 if ((array[0] != 0) || (array[1] != 0)) return -1;
2871
2872 memcpy(dst->vb_ether, &array[2], 6);
2873 break;
2874 }
2875
2876 default:
2877 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2878 fr_type_to_str(src->type),
2879 fr_type_to_str(dst_type));
2880 return -1;
2881 }
2882
2883 return 0;
2884}
2885
2886/** Convert any supported type to a bool
2887 *
2888 * Allowed input types are:
2889 * - FR_TYPE_STRING ("yes", "true", "no", "false")
2890 *
2891 * @param ctx unused.
2892 * @param dst Where to write result of casting.
2893 * @param dst_type to cast to.
2894 * @param dst_enumv enumeration values.
2895 * @param src Input data.
2896 */
2897static inline int fr_value_box_cast_to_bool(TALLOC_CTX *ctx, fr_value_box_t *dst,
2898 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2899 fr_value_box_t const *src)
2900{
2901 fr_assert(dst_type == FR_TYPE_BOOL);
2903
2904 switch (src->type) {
2905 case FR_TYPE_STRING:
2906 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2907 src->vb_strvalue, src->vb_length,
2908 NULL);
2909
2910 case FR_TYPE_OCTETS:
2911 /*
2912 * This is really "bool from network"
2913 */
2914 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
2915
2916 default:
2917 break;
2918 }
2919
2920 /*
2921 * Pre-initialise box for non-variable types
2922 */
2923 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2924
2925 switch (src->type) {
2926 case FR_TYPE_INT8:
2927 dst->vb_bool = (src->vb_int8 != 0);
2928 break;
2929
2930 case FR_TYPE_UINT8:
2931 dst->vb_bool = (src->vb_uint8 != 0);
2932 break;
2933
2934 case FR_TYPE_INT16:
2935 dst->vb_bool = (src->vb_int16 != 0);
2936 break;
2937
2938 case FR_TYPE_UINT16:
2939 dst->vb_bool = (src->vb_uint16 != 0);
2940 break;
2941
2942 case FR_TYPE_INT32:
2943 dst->vb_bool = (src->vb_int32 != 0);
2944 break;
2945
2946 case FR_TYPE_UINT32:
2947 dst->vb_bool = (src->vb_uint32 != 0);
2948 break;
2949
2950 case FR_TYPE_INT64:
2951 dst->vb_bool = (src->vb_int64 != 0);
2952 break;
2953
2954 case FR_TYPE_UINT64:
2955 dst->vb_bool = (src->vb_uint64 != 0);
2956 break;
2957
2958 case FR_TYPE_SIZE:
2959 dst->vb_bool = (src->vb_size != 0);
2960 break;
2961
2962 case FR_TYPE_TIME_DELTA:
2963 dst->vb_bool = (fr_time_delta_unwrap(src->vb_time_delta) != 0);
2964 break;
2965
2966 case FR_TYPE_FLOAT32:
2967 dst->vb_bool = (fpclassify(src->vb_float32) == FP_ZERO);
2968 break;
2969
2970 case FR_TYPE_FLOAT64:
2971 dst->vb_bool = (fpclassify(src->vb_float64) == FP_ZERO);
2972 break;
2973
2974 default:
2975 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2976 fr_type_to_str(src->type),
2977 fr_type_to_str(dst_type));
2978 return -1;
2979 }
2980
2981 return 0;
2982}
2983
2984/** Convert any signed or unsigned integer type to any other signed or unsigned integer type
2985 *
2986 */
2987static inline int fr_value_box_cast_integer_to_integer(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst,
2988 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2989 fr_value_box_t const *src)
2990{
2991 uint64_t tmp = 0;
2992 size_t len = fr_value_box_field_sizes[src->type];
2993 int64_t min;
2994
2996
2997#define SIGN_BIT_HIGH(_int, _len) ((((uint64_t)1) << (((_len) << 3) - 1)) & (_int))
2998#define SIGN_PROMOTE(_int, _len) ((_len) < sizeof(_int) ? \
2999 (_int) | (~((__typeof__(_int))0)) << ((_len) << 3) : (_int))
3000
3001#if !defined(NDEBUG) || defined(STATIC_ANALYZER)
3002 /*
3003 * Helps catch invalid fr_value_box_field_sizes
3004 * entries, and shuts up clang analyzer.
3005 */
3006 if (!fr_cond_assert_msg(len > 0, "Invalid cast from %s to %s. "
3007 "invalid source type len, expected > 0, got %zu",
3008 fr_type_to_str(src->type),
3009 fr_type_to_str(dst_type),
3010 len)) return -1;
3011
3012 if (!fr_cond_assert_msg(len <= sizeof(uint64_t),
3013 "Invalid cast from %s to %s. "
3014 "invalid source type len, expected <= %zu, got %zu",
3015 fr_type_to_str(src->type),
3016 fr_type_to_str(dst_type),
3017 sizeof(uint64_t), len)) return -1;
3018#endif
3019
3020 switch (src->type) {
3021 /*
3022 * Dates are always represented in nanoseconds
3023 * internally, but when we convert to another
3024 * integer type, we scale appropriately.
3025 *
3026 * i.e. if the attribute value resolution is
3027 * seconds, then the integer value is
3028 * nanoseconds -> seconds.
3029 */
3030 case FR_TYPE_DATE:
3031 {
3033 if (src->enumv) res = src->enumv->flags.flag_time_res;
3034
3035 tmp = fr_unix_time_to_integer(src->vb_date, res);
3036 }
3037 break;
3038
3039 /*
3040 * Same deal with time deltas. Note that
3041 * even though we store the value as an
3042 * unsigned integer, it'll be cast to a
3043 * signed integer for comparisons.
3044 */
3045 case FR_TYPE_TIME_DELTA:
3046 {
3048
3049 if (src->enumv) res = src->enumv->flags.flag_time_res;
3050
3051 tmp = (uint64_t)fr_time_delta_to_integer(src->vb_time_delta, res);
3052 }
3053 break;
3054
3055 default:
3056#ifdef WORDS_BIGENDIAN
3057 memcpy(((uint8_t *)&tmp) + (sizeof(tmp) - len),
3058 fr_value_box_raw(src, src->type), len);
3059#else
3060 memcpy(&tmp, fr_value_box_raw(src, src->type), len);
3061#endif
3062 break;
3063 }
3064
3065 min = fr_value_box_integer_min[dst_type];
3066
3067 /*
3068 * Sign promote the input if the source type is
3069 * signed, and the high bit is set.
3070 */
3071 if (fr_value_box_integer_min[src->type] < 0) {
3072 if (SIGN_BIT_HIGH(tmp, len)) tmp = SIGN_PROMOTE(tmp, len);
3073
3074 if ((int64_t)tmp < min) {
3075 fr_strerror_printf("Invalid cast from %s to %s. %"PRId64" "
3076 "outside value range %"PRId64"-%"PRIu64,
3077 fr_type_to_str(src->type),
3078 fr_type_to_str(dst_type),
3079 (int64_t)tmp,
3080 min, fr_value_box_integer_max[dst_type]);
3081 return -1;
3082 }
3083 } else if (tmp > fr_value_box_integer_max[dst_type]) {
3084 fr_strerror_printf("Invalid cast from %s to %s. %"PRIu64" "
3085 "outside value range 0-%"PRIu64,
3086 fr_type_to_str(src->type),
3087 fr_type_to_str(dst_type),
3088 tmp, fr_value_box_integer_max[dst_type]);
3089 return -1;
3090 }
3091
3092 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3093 switch (dst_type) {
3094 case FR_TYPE_DATE:
3095 {
3096 bool overflow;
3098 if (dst->enumv) res = dst->enumv->flags.flag_time_res;
3099
3100 dst->vb_date = fr_unix_time_from_integer(&overflow, tmp, res);
3101 if (overflow) {
3102 fr_strerror_const("Input to data type would overflow");
3103 return -1;
3104 }
3105 }
3106 break;
3107
3108 case FR_TYPE_TIME_DELTA:
3109 {
3110 bool overflow;
3112 if (dst->enumv) res = dst->enumv->flags.flag_time_res;
3113
3114 dst->vb_time_delta = fr_time_delta_from_integer(&overflow, tmp, res);
3115 if (overflow) {
3116 fr_strerror_const("Input to time_delta type would overflow");
3117 return -1;
3118 }
3119 }
3120 break;
3121
3122 default:
3123#ifdef WORDS_BIGENDIAN
3124 memcpy(fr_value_box_raw(dst, dst->type),
3125 ((uint8_t *)&tmp) + (sizeof(tmp) - len), fr_value_box_field_sizes[dst_type]);
3126#else
3127 memcpy(fr_value_box_raw(dst, dst->type),
3128 &tmp, fr_value_box_field_sizes[dst_type]);
3129#endif
3130 break;
3131 }
3132
3133 return 0;
3134}
3135
3136/** Convert any value to a signed or unsigned integer
3137 *
3138 * @param ctx unused.
3139 * @param dst Where to write result of casting.
3140 * @param dst_type to cast to.
3141 * @param dst_enumv enumeration values.
3142 * @param src Input data.
3143 */
3144static inline int fr_value_box_cast_to_integer(TALLOC_CTX *ctx, fr_value_box_t *dst,
3145 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3146 fr_value_box_t const *src)
3147{
3148 switch (src->type) {
3149 case FR_TYPE_STRING:
3150 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3151 src->vb_strvalue, src->vb_length,
3152 NULL);
3153
3154 case FR_TYPE_OCTETS:
3155 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
3156
3157 case FR_TYPE_INTEGER:
3158 fr_value_box_init(dst, dst_type, dst_enumv, false);
3159 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, src);
3160
3161 case FR_TYPE_IPV4_ADDR:
3163 {
3164 fr_value_box_t tmp;
3165
3166 switch (dst_type) {
3167 case FR_TYPE_UINT32:
3168 case FR_TYPE_INT64:
3169 case FR_TYPE_UINT64:
3170 case FR_TYPE_DATE:
3171 case FR_TYPE_TIME_DELTA:
3172 break;
3173
3174 default:
3175 goto bad_cast;
3176 }
3177
3178 fr_value_box_init(&tmp, FR_TYPE_UINT32, src->enumv, src->tainted);
3179 memcpy(&tmp.vb_uint32, &src->vb_ip.addr.v4, sizeof(tmp.vb_uint32));
3180 fr_value_box_hton(&tmp, &tmp);
3181 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, &tmp);
3182 }
3183
3184 case FR_TYPE_ETHERNET:
3185 {
3186 fr_value_box_t tmp;
3187
3188 switch (dst_type) {
3189 case FR_TYPE_INT64:
3190 case FR_TYPE_UINT64:
3191 case FR_TYPE_DATE:
3192 case FR_TYPE_TIME_DELTA:
3193 break;
3194
3195 default:
3196 goto bad_cast;
3197 }
3198
3199 fr_value_box_init(&tmp, FR_TYPE_UINT64, src->enumv, src->tainted);
3200 memcpy(((uint8_t *)&tmp.vb_uint64) + (sizeof(tmp.vb_uint64) - sizeof(src->vb_ether)),
3201 &src->vb_ether, sizeof(src->vb_ether));
3202#ifndef WORDS_BIGENDIAN
3203 /*
3204 * Ethernet addresses are always stored bigendian,
3205 * convert to native on little endian systems
3206 */
3207 fr_value_box_hton(&tmp, &tmp);
3208#endif
3209 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, &tmp);
3210 }
3211
3212 case FR_TYPE_IFID:
3213 {
3214 switch (dst_type) {
3215 case FR_TYPE_UINT64:
3216 break;
3217
3218 default:
3219 goto bad_cast;
3220 }
3221
3222 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3223 dst->vb_uint64 = fr_nbo_to_uint64(&src->vb_ifid[0]);
3224 return 0;
3225 }
3226
3227 default:
3228 break;
3229 }
3230
3231bad_cast:
3232 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
3233 fr_type_to_str(src->type),
3234 fr_type_to_str(dst_type));
3235 return -1;
3236}
3237
3238/** Convert any value to a floating point value
3239 *
3240 * @param ctx unused.
3241 * @param dst Where to write result of casting.
3242 * @param dst_type to cast to.
3243 * @param dst_enumv enumeration values.
3244 * @param src Input data.
3245 */
3246static inline int fr_value_box_cast_to_float(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst,
3247 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3248 fr_value_box_t const *src)
3249{
3250 double num;
3251
3252 switch (src->type) {
3253 case FR_TYPE_FLOAT32:
3254 if (dst_type == FR_TYPE_FLOAT64) {
3255 num = (double) src->vb_float32;
3256 goto good_cast;
3257 }
3258
3259 goto bad_cast;
3260
3261 case FR_TYPE_FLOAT64:
3262 if (dst_type == FR_TYPE_FLOAT32) {
3263 num = src->vb_float64;
3264 goto good_cast;
3265 }
3266
3267 goto bad_cast;
3268
3269 case FR_TYPE_BOOL:
3270 num = src->vb_bool;
3271 goto good_cast;
3272
3273 case FR_TYPE_INT8:
3274 num = src->vb_int8;
3275 goto good_cast;
3276
3277 case FR_TYPE_INT16:
3278 num = src->vb_int16;
3279 goto good_cast;
3280
3281 case FR_TYPE_INT32:
3282 num = src->vb_int32;
3283 goto good_cast;
3284
3285 case FR_TYPE_INT64:
3286 num = src->vb_int64;
3287 goto good_cast;
3288
3289 case FR_TYPE_UINT8:
3290 num = src->vb_uint8;
3291 goto good_cast;
3292
3293 case FR_TYPE_UINT16:
3294 num = src->vb_uint16;
3295 goto good_cast;
3296
3297 case FR_TYPE_UINT32:
3298 num = src->vb_uint32;
3299 goto good_cast;
3300
3301 case FR_TYPE_UINT64:
3302 num = src->vb_uint64;
3303 goto good_cast;
3304
3305 case FR_TYPE_DATE:
3306 /*
3307 * Unix times are in nanoseconds
3308 */
3309 num = fr_unix_time_unwrap(src->vb_date);
3310 num /= NSEC;
3311 goto good_cast;
3312
3313 case FR_TYPE_TIME_DELTA:
3314 /*
3315 * Time deltas are in nanoseconds, but scaled.
3316 */
3317 num = fr_time_delta_unwrap(src->vb_time_delta);
3318 if (src->enumv) {
3319 num /= fr_time_multiplier_by_res[src->enumv->flags.flag_time_res];
3320 } else {
3321 num /= NSEC;
3322 }
3323 goto good_cast;
3324
3325 case FR_TYPE_SIZE:
3326 num = src->vb_size;
3327
3328 good_cast:
3329 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3331
3332 if (dst_type == FR_TYPE_FLOAT32) {
3333 dst->vb_float32 = num;
3334 } else {
3335 dst->vb_float64 = num;
3336 }
3337 return 0;
3338
3339 default:
3340 break;
3341 }
3342
3343bad_cast:
3344 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
3345 fr_type_to_str(src->type),
3346 fr_type_to_str(dst_type));
3347 return -1;
3348}
3349
3350
3351/** Convert one type of fr_value_box_t to another
3352 *
3353 * This should be the canonical function used to convert between INTERNAL data formats.
3354 *
3355 * If you want to convert from PRESENTATION format, use #fr_value_box_from_substr.
3356 *
3357 * @note src and dst must not be the same box. We do not support casting in place.
3358 *
3359 * @param ctx to allocate buffers in (usually the same as dst)
3360 * @param dst Where to write result of casting.
3361 * @param dst_type to cast to.
3362 * @param dst_enumv Aliases for values contained within this fr_value_box_t.
3363 * If #fr_value_box_t is passed to #fr_value_box_aprint
3364 * names will be printed instead of actual value.
3365 * @param src Input data.
3366 * @return
3367 * - 0 on success.
3368 * - -1 on failure.
3369 */
3370int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst,
3371 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3372 fr_value_box_t const *src)
3373{
3374 if (!fr_cond_assert(dst_type != FR_TYPE_NULL)) return -1;
3375 if (!fr_cond_assert(src != dst)) return -1;
3376 if (!fr_cond_assert(src->type != FR_TYPE_NULL)) return -1;
3377
3378 if (fr_type_is_non_leaf(dst_type)) {
3379 fr_strerror_printf("Invalid cast from %s to %s. Can only cast simple data types",
3380 fr_type_to_str(src->type),
3381 fr_type_to_str(dst_type));
3382 return -1;
3383 }
3384
3385 /*
3386 * If it's the same type, copy, but set the enumv
3387 * in the destination box to be the one provided.
3388 *
3389 * The theory here is that the attribute value isn't
3390 * being converted into its presentation format and
3391 * re-parsed, and the enumv names only get applied
3392 * when converting internal values to/from strings,
3393 * so it's OK just to swap out the enumv.
3394 *
3395 * If there's a compelling case in the future we
3396 * might revisit this, but it'd likely mean fixing
3397 * all the casting functions to treat any value
3398 * with an enumv as a string, which seems weird.
3399 */
3400 if (dst_type == src->type) {
3401 int ret;
3402
3403 ret = fr_value_box_copy(ctx, dst, src);
3404 if (ret < 0) return ret;
3405
3406 dst->enumv = dst_enumv;
3407
3408 return ret;
3409 }
3410
3411 /*
3412 * Initialise dst
3413 */
3414 fr_value_box_init(dst, dst_type, NULL, src->tainted);
3415
3416 /*
3417 * Dispatch to specialised cast functions
3418 */
3419 switch (dst_type) {
3420 case FR_TYPE_STRING:
3421 return fr_value_box_cast_to_strvalue(ctx, dst, dst_type, dst_enumv, src);
3422
3423 case FR_TYPE_OCTETS:
3424 return fr_value_box_cast_to_octets(ctx, dst, dst_type, dst_enumv, src);
3425
3426 case FR_TYPE_IPV4_ADDR:
3427 return fr_value_box_cast_to_ipv4addr(ctx, dst, dst_type, dst_enumv, src);
3428
3430 return fr_value_box_cast_to_ipv4prefix(ctx, dst, dst_type, dst_enumv, src);
3431
3432 case FR_TYPE_IPV6_ADDR:
3433 return fr_value_box_cast_to_ipv6addr(ctx, dst, dst_type, dst_enumv, src);
3434
3436 return fr_value_box_cast_to_ipv6prefix(ctx, dst, dst_type, dst_enumv, src);
3437
3440 break;
3441 /*
3442 * Need func
3443 */
3444 case FR_TYPE_IFID:
3445 break;
3446
3447 case FR_TYPE_ETHERNET:
3448 return fr_value_box_cast_to_ethernet(ctx, dst, dst_type, dst_enumv, src);
3449
3450 case FR_TYPE_BOOL:
3451 return fr_value_box_cast_to_bool(ctx, dst, dst_type, dst_enumv, src);
3452
3453 case FR_TYPE_DATE:
3454 if (src->type != FR_TYPE_TIME_DELTA) return fr_value_box_cast_to_integer(ctx, dst, dst_type, dst_enumv, src);
3455
3456 if (fr_time_delta_isneg(src->vb_time_delta)) {
3457 fr_strerror_const("Input to data type would underflow");
3458 return -1;
3459 }
3460
3462 dst->enumv = dst_enumv;
3463 dst->vb_date = fr_unix_time_wrap(fr_time_delta_unwrap(src->vb_time_delta));
3464 return 0;
3465
3466 case FR_TYPE_TIME_DELTA:
3467 /*
3468 * Unix time cast to time_delta is just nanoseconds since the epoch.
3469 *
3470 * Note that we do NOT change time resolution, but we DO change enumv. Both unix time
3471 * and time_delta are tracked internally as nanoseconds, and the only use of precision is
3472 * for printing / parsing.
3473 */
3474 if (src->type == FR_TYPE_DATE) {
3475 uint64_t when;
3476
3477 when = fr_unix_time_unwrap(src->vb_date);
3478 if (when > INT64_MAX) {
3479 fr_strerror_const("Input to data type would overflow");
3480 return -1;
3481 }
3482
3484 dst->enumv = dst_enumv;
3485 dst->vb_time_delta = fr_time_delta_wrap((int64_t) when);
3486 return 0;
3487 }
3489
3490 case FR_TYPE_UINT8:
3491 case FR_TYPE_UINT16:
3492 case FR_TYPE_UINT32:
3493 case FR_TYPE_UINT64:
3494 case FR_TYPE_INT8:
3495 case FR_TYPE_INT16:
3496 case FR_TYPE_INT32:
3497 case FR_TYPE_INT64:
3498 case FR_TYPE_SIZE:
3499 return fr_value_box_cast_to_integer(ctx, dst, dst_type, dst_enumv, src);
3500
3501 case FR_TYPE_FLOAT32:
3502 case FR_TYPE_FLOAT64:
3503 if (fr_type_is_fixed_size(src->type)) {
3504 return fr_value_box_cast_to_float(ctx, dst, dst_type, dst_enumv, src);
3505 }
3506 break; /* use generic string/octets stuff below */
3507
3508 /*
3509 * Invalid types for casting (should have been caught earlier)
3510 */
3511 case FR_TYPE_VALUE_BOX:
3512 case FR_TYPE_STRUCTURAL:
3513 case FR_TYPE_NULL:
3514 case FR_TYPE_VOID:
3515 case FR_TYPE_MAX:
3516 fr_strerror_printf("Invalid cast from %s to %s. Invalid destination type",
3517 fr_type_to_str(src->type),
3518 fr_type_to_str(dst_type));
3519 return -1;
3520 }
3521
3522 /*
3523 * Deserialise a fr_value_box_t
3524 */
3525 if (src->type == FR_TYPE_STRING) return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3526 src->vb_strvalue, src->vb_length,
3527 NULL);
3528
3529 if (src->type == FR_TYPE_OCTETS) {
3530 fr_value_box_t tmp;
3531
3532 if (src->vb_length < network_min_size(dst_type)) {
3533 fr_strerror_printf("Invalid cast from %s to %s. Source is length %zu is smaller than "
3534 "destination type size %zu",
3535 fr_type_to_str(src->type),
3536 fr_type_to_str(dst_type),
3537 src->vb_length,
3538 network_min_size(dst_type));
3539 return -1;
3540 }
3541
3542 if (src->vb_length > network_max_size(dst_type)) {
3543 fr_strerror_printf("Invalid cast from %s to %s. Source length %zu is greater than "
3544 "destination type size %zu",
3545 fr_type_to_str(src->type),
3546 fr_type_to_str(dst_type),
3547 src->vb_length,
3548 network_max_size(dst_type));
3549 return -1;
3550 }
3551
3552 fr_value_box_init(&tmp, dst_type, NULL, false);
3553
3554 /*
3555 * Copy the raw octets into the datum of a value_box
3556 * inverting bytesex for uint32s (if LE).
3557 */
3558 memcpy(&tmp.datum, src->vb_octets, fr_value_box_field_sizes[dst_type]);
3559 tmp.type = dst_type;
3560 dst->enumv = dst_enumv;
3561
3562 fr_value_box_hton(dst, &tmp);
3563 fr_value_box_safety_copy(dst, src);
3564 return 0;
3565 }
3566
3567 memcpy(&dst->datum, &src->datum, fr_value_box_field_sizes[src->type]);
3568
3570 dst->enumv = dst_enumv;
3571
3572 return 0;
3573}
3574
3575/** Convert one type of fr_value_box_t to another in place
3576 *
3577 * This should be the canonical function used to convert between INTERNAL data formats.
3578 *
3579 * If you want to convert from PRESENTATION format, use #fr_value_box_from_substr.
3580 *
3581 * @param ctx to allocate buffers in (usually the same as dst)
3582 * @param vb to cast.
3583 * @param dst_type to cast to.
3584 * @param dst_enumv Aliases for values contained within this fr_value_box_t.
3585 * If #fr_value_box_t is passed to #fr_value_box_aprint
3586 * names will be printed instead of actual value.
3587 * @return
3588 * - 0 on success.
3589 * - -1 on failure.
3590 */
3592 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
3593{
3594 fr_value_box_t tmp;
3595 /*
3596 * Store list pointers to restore later - fr_value_box_cast clears them
3597 */
3598 fr_value_box_entry_t entry = vb->entry;
3599
3600 /*
3601 * Simple case, destination type and current
3602 * type are the same.
3603 */
3604 if (vb->type == dst_type) {
3605 vb->enumv = dst_enumv; /* Update the enumv as this may be different */
3606 return 0;
3607 }
3608
3609 /*
3610 * Copy meta data and any existing buffers to
3611 * a temporary box. We then clear that value
3612 * box after the cast has been completed,
3613 * freeing any old buffers.
3614 */
3615 fr_value_box_copy_shallow(NULL, &tmp, vb);
3616
3617 if (fr_value_box_cast(ctx, vb, dst_type, dst_enumv, &tmp) < 0) {
3618 /*
3619 * On error, make sure the original
3620 * box is left in a consistent state.
3621 */
3622 fr_value_box_copy_shallow(NULL, vb, &tmp);
3623 vb->entry = entry;
3624 return -1;
3625 }
3626 fr_value_box_clear_value(&tmp); /* Clear out any old buffers */
3627
3628 /*
3629 * Restore list pointers
3630 */
3631 vb->entry = entry;
3632
3633 return 0;
3634}
3635
3636/** Assign a #fr_value_box_t value from an #fr_ipaddr_t
3637 *
3638 * Automatically determines the type of the value box from the ipaddr address family
3639 * and the length of the prefix field.
3640 *
3641 * @param[in] dst to assign ipaddr to.
3642 * @param[in] enumv Aliases for values.
3643 * @param[in] ipaddr to copy address from.
3644 * @param[in] tainted Whether the value came from a trusted source.
3645 * @return
3646 * - 0 on success.
3647 * - -1 on failure.
3648 */
3649int fr_value_box_ipaddr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, fr_ipaddr_t const *ipaddr, bool tainted)
3650{
3652
3653 switch (ipaddr->af) {
3654 case AF_INET:
3656 break;
3657
3658 case AF_INET6:
3660 break;
3661
3662 default:
3663 fr_strerror_printf("Invalid address family %i", ipaddr->af);
3664 return -1;
3665 }
3666
3667 fr_value_box_init(dst, type, enumv, tainted);
3668 memcpy(&dst->vb_ip, ipaddr, sizeof(dst->vb_ip));
3669
3670 return 0;
3671}
3672
3673/** Unbox an IP address performing a type check
3674 *
3675 * @param[out] dst Where to copy the IP address to.
3676 * @param[in] src Where to copy the IP address from.
3677 * @return
3678 * - 0 on success.
3679 * - -1 on type mismatch.
3680 */
3682{
3683 if (!fr_type_is_ip(src->type)) {
3684 fr_strerror_printf("Unboxing failed. Needed IPv4/6 addr/prefix, had type %s",
3685 fr_type_to_str(src->type));
3686 return -1;
3687 }
3688
3689 memcpy(dst, &src->vb_ip, sizeof(*dst));
3690
3691 return 0;
3692}
3693
3694/** Clear/free any existing value
3695 *
3696 * @note Do not use on uninitialised memory.
3697 *
3698 * @param[in] data to clear.
3699 */
3701{
3702 switch (data->type) {
3703 case FR_TYPE_OCTETS:
3704 case FR_TYPE_STRING:
3705 if (data->secret) memset_explicit(data->datum.ptr, 0, data->vb_length);
3706 talloc_free(data->datum.ptr);
3707 break;
3708
3709 case FR_TYPE_GROUP:
3710 /*
3711 * Depth first freeing of children
3712 *
3713 * This ensures orderly freeing, regardless
3714 * of talloc hierarchy.
3715 */
3716 {
3717 fr_value_box_t *vb = NULL;
3718
3719 while ((vb = fr_value_box_list_next(&data->vb_group, vb))) {
3721 talloc_free(vb);
3722 }
3723 }
3724 return;
3725
3726 case FR_TYPE_NULL:
3727 return;
3728
3729 default:
3730 break;
3731 }
3732
3733 memset(&data->datum, 0, sizeof(data->datum));
3734}
3735
3736/** Clear/free any existing value and metadata
3737 *
3738 * @note Do not use on uninitialised memory.
3739 *
3740 * @param[in] data to clear.
3741 */
3747
3748/** Copy value data verbatim duplicating any buffers
3749 *
3750 * @note Will free any exiting buffers associated with the dst #fr_value_box_t.
3751 *
3752 * @param ctx To allocate buffers in.
3753 * @param dst Where to copy value_box to.
3754 * @param src Where to copy value_box from.
3755 * @return
3756 * - 0 on success.
3757 * - -1 on failure.
3758 */
3759int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
3760{
3761 switch (src->type) {
3762 default:
3763 fr_value_box_memcpy_out(fr_value_box_raw(dst, src->type), src);
3764 fr_value_box_copy_meta(dst, src);
3765 break;
3766
3767 case FR_TYPE_NULL:
3768 fr_value_box_copy_meta(dst, src);
3769 break;
3770
3771 case FR_TYPE_STRING:
3772 {
3773 char *str = NULL;
3774
3775 /*
3776 * Zero length strings still have a one uint8 buffer
3777 */
3778 str = talloc_bstrndup(ctx, src->vb_strvalue, src->vb_length);
3779 if (!str) {
3780 fr_strerror_const("Failed allocating string buffer");
3781 return -1;
3782 }
3783 dst->vb_strvalue = str;
3784 fr_value_box_copy_meta(dst, src);
3785 }
3786 break;
3787
3788 case FR_TYPE_OCTETS:
3789 {
3790 uint8_t *bin;
3791
3792 if (src->vb_length) {
3793 bin = talloc_memdup(ctx, src->vb_octets, src->vb_length);
3794 if (!bin) {
3795 fr_strerror_const("Failed allocating octets buffer");
3796 return -1;
3797 }
3798 talloc_set_type(bin, uint8_t);
3799 } else {
3800 bin = talloc_array(ctx, uint8_t, 0);
3801 }
3802 dst->vb_octets = bin;
3803 fr_value_box_copy_meta(dst, src);
3804 }
3805 break;
3806
3807 case FR_TYPE_GROUP:
3808 {
3809 fr_value_box_t *child = NULL;
3810
3811 fr_value_box_copy_meta(dst, src); /* Initialises group child dlist */
3812
3813 while ((child = fr_value_box_list_next(&src->vb_group, child))) {
3814 fr_value_box_t *new;
3815
3816 /*
3817 * Build out the child
3818 */
3819 new = fr_value_box_alloc_null(ctx);
3820 if (unlikely(!new)) {
3821 group_error:
3822 fr_strerror_const("Failed duplicating group child");
3823 fr_value_box_list_talloc_free(&dst->vb_group);
3824 return -1;
3825 }
3826
3827 /*
3828 * Populate it with the data from the original child.
3829 *
3830 * We do NOT update the dst safety. The individual boxes have safety. A group
3831 * doesn't.
3832 */
3833 if (unlikely(fr_value_box_copy(new, new, child) < 0)) goto group_error;
3834 fr_value_box_list_insert_tail(&dst->vb_group, new);
3835 }
3836 }
3837 break;
3838
3839 case FR_TYPE_TLV:
3840 case FR_TYPE_STRUCT:
3841 case FR_TYPE_VSA:
3842 case FR_TYPE_VENDOR:
3843 case FR_TYPE_VALUE_BOX:
3844 case FR_TYPE_VOID:
3845 case FR_TYPE_MAX:
3846 fr_strerror_printf("Cannot copy data type '%s'", fr_type_to_str(src->type));
3847 return -1;
3848 }
3849
3850 return 0;
3851}
3852
3853/** Perform a shallow copy of a value_box
3854 *
3855 * Like #fr_value_box_copy, but does not duplicate the buffers of the src value_box.
3856 *
3857 * For #FR_TYPE_STRING and #FR_TYPE_OCTETS adds a reference from ctx so that the
3858 * buffer cannot be freed until the ctx is freed.
3859 *
3860 * @param[in] ctx to add reference from. If NULL no reference will be added.
3861 * @param[in] dst to copy value to.
3862 * @param[in] src to copy value from.
3863 */
3864void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
3865{
3866 switch (src->type) {
3867 default:
3868 fr_value_box_copy(NULL, dst, src);
3869 break;
3870
3871 case FR_TYPE_STRING:
3872 case FR_TYPE_OCTETS:
3873 dst->datum.ptr = ctx ? talloc_reference(ctx, src->datum.ptr) : src->datum.ptr;
3874 fr_value_box_copy_meta(dst, src);
3875 break;
3876 }
3877}
3878
3879/** Copy value data verbatim moving any buffers to the specified context
3880 *
3881 * @param[in] ctx to allocate any new buffers in.
3882 * @param[in] dst to copy value to.
3883 * @param[in] src to copy value from.
3884 * @return
3885 * - 0 on success.
3886 * - -1 on failure.
3887 */
3888int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
3889{
3890 if (!fr_cond_assert(src->type != FR_TYPE_NULL)) return -1;
3891
3892 switch (src->type) {
3893 default:
3894 return fr_value_box_copy(ctx, dst, src);
3895
3896 case FR_TYPE_STRING:
3897 {
3898 char const *str;
3899
3900 str = talloc_steal(ctx, src->vb_strvalue);
3901 if (!str) {
3902 fr_strerror_const("Failed stealing string buffer");
3903 return -1;
3904 }
3905 talloc_set_type(str, char);
3906 dst->vb_strvalue = str;
3907 fr_value_box_copy_meta(dst, src);
3908 memset(&src->datum, 0, sizeof(src->datum));
3909 }
3910 return 0;
3911
3912 case FR_TYPE_OCTETS:
3913 {
3914 uint8_t const *bin;
3915
3916 bin = talloc_steal(ctx, src->vb_octets);
3917 if (!bin) {
3918 fr_strerror_const("Failed stealing octets buffer");
3919 return -1;
3920 }
3921 talloc_set_type(bin, uint8_t);
3922
3923 dst->vb_octets = bin;
3924 fr_value_box_copy_meta(dst, src);
3925 memset(&src->datum, 0, sizeof(src->datum));
3926 }
3927 return 0;
3928
3929 case FR_TYPE_GROUP:
3930 {
3931 fr_value_box_t *child;
3932
3933 while ((child = fr_value_box_list_pop_head(&src->vb_group))) {
3934 child = talloc_steal(ctx, child);
3935 if (unlikely(!child)) {
3936 fr_strerror_const("Failed stealing child");
3937 return -1;
3938 }
3939 fr_value_box_list_insert_tail(&dst->vb_group, child);
3940 }
3941 }
3942 return 0;
3943 }
3944}
3945
3946/** Copy a nul terminated string to a #fr_value_box_t
3947 *
3948 * @param[in] ctx to allocate any new buffers in.
3949 * @param[in] dst to assign new buffer to.
3950 * @param[in] enumv Aliases for values.
3951 * @param[in] src a nul terminated buffer.
3952 * @param[in] tainted Whether the value came from a trusted source.
3953 * @return
3954 * - 0 on success.
3955 * - -1 on failure.
3956 */
3957int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
3958 char const *src, bool tainted)
3959{
3960 char const *str;
3961
3962 str = talloc_typed_strdup(ctx, src);
3963 if (!str) {
3964 fr_strerror_const("Failed allocating string buffer");
3965 return -1;
3966 }
3967
3968 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
3969 dst->vb_strvalue = str;
3970 dst->vb_length = talloc_array_length(str) - 1;
3971
3972 return 0;
3973}
3974
3975/** Trim the length of the string buffer to match the length of the C string
3976 *
3977 * @param[in] ctx to re-alloc the buffer in.
3978 * @param[in,out] vb to trim.
3979 * @return
3980 * - 0 on success.
3981 * - -1 on failure.
3982 */
3983int fr_value_box_strtrim(TALLOC_CTX *ctx, fr_value_box_t *vb)
3984{
3985 size_t len;
3986 char *str;
3987
3988 if (!fr_cond_assert(vb->type == FR_TYPE_STRING)) return -1;
3989
3990 len = strlen(vb->vb_strvalue);
3991 str = talloc_realloc(ctx, UNCONST(char *, vb->vb_strvalue), char, len + 1);
3992 if (!str) {
3993 fr_strerror_const("Failed re-allocing string buffer");
3994 return -1;
3995 }
3996 vb->vb_length = len;
3997
3998 return 0;
3999}
4000
4001/** Print a formatted string using our internal printf wrapper and assign it to a value box
4002 *
4003 * @param[in] ctx to allocate any new buffers in.
4004 * @param[in] dst to assign new buffer to.
4005 * @param[in] enumv Aliases for values.
4006 * @param[in] fmt The printf format string to process.
4007 * @param[in] tainted Whether the value came from a trusted source.
4008 * @param[in] ap Substitution arguments.
4009 * @return
4010 * - 0 on success.
4011 * - -1 on failure.
4012 */
4013int fr_value_box_vasprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted,
4014 char const *fmt, va_list ap)
4015{
4016 va_list aq;
4017 char *str;
4018
4019 va_copy(aq, ap); /* See vlog_module_failure_msg for why */
4020 str = fr_vasprintf(ctx, fmt, aq);
4021 va_end(aq);
4022
4023 if (!str) return -1;
4024
4025 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4026 dst->vb_strvalue = str;
4027 dst->vb_length = talloc_array_length(str) - 1;
4028
4029 return 0;
4030}
4031
4032/** Print a formatted string using our internal printf wrapper and assign it to a value box
4033 *
4034 * @param[in] ctx to allocate any new buffers in.
4035 * @param[in] dst to assign new buffer to.
4036 * @param[in] enumv Aliases for values.
4037 * @param[in] tainted Whether the value came from a trusted source.
4038 * @param[in] fmt The printf format string to process.
4039 * @param[in] ... Substitution arguments.
4040 * @return
4041 * - 0 on success.
4042 * - -1 on failure.
4043 */
4044int fr_value_box_asprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted,
4045 char const *fmt, ...)
4046{
4047 va_list ap;
4048 int ret;
4049
4050 va_start(ap, fmt);
4051 ret = fr_value_box_vasprintf(ctx, dst, enumv, tainted, fmt, ap);
4052 va_end(ap);
4053
4054 return ret;
4055}
4056
4057/** Assign a buffer containing a nul terminated string to a box, but don't copy it
4058 *
4059 * @note Input string will not be duplicated.
4060 *
4061 * @param[in] dst to assign string to.
4062 * @param[in] enumv Aliases for values.
4063 * @param[in] src to copy string from.
4064 * @param[in] tainted Whether the value came from a trusted source.
4065 */
4067 char const *src, bool tainted)
4068{
4069 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4070 dst->vb_strvalue = src;
4071 dst->vb_length = strlen(src);
4072}
4073
4074/** Free the existing buffer (if talloced) associated with the valuebox, and replace it with a new one
4075 *
4076 * @note Input string will not be duplicated.
4077 *
4078 * @param[in] vb to replace string in.
4079 * @param[in] src to assign string from.
4080 * @param[in] len of src.
4081 */
4083{
4085 vb->vb_strvalue = src;
4086 vb->vb_length = len < 0 ? strlen(src) : (size_t)len;
4087}
4088
4089/** Alloc and assign an empty \0 terminated string to a #fr_value_box_t
4090 *
4091 * @param[in] ctx to allocate any new buffers in.
4092 * @param[out] out if non-null where to write a pointer to the new buffer.
4093 * @param[in] dst to assign new buffer to.
4094 * @param[in] enumv Aliases for values.
4095 * @param[in] len of buffer to allocate.
4096 * @param[in] tainted Whether the value came from a trusted source.
4097 * @return
4098 * - 0 on success.
4099 * - -1 on failure.
4100 */
4101int fr_value_box_bstr_alloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4102 size_t len, bool tainted)
4103{
4104 char *str;
4105
4106 str = talloc_zero_array(ctx, char, len + 1);
4107 if (!str) {
4108 fr_strerror_const("Failed allocating string buffer");
4109 return -1;
4110 }
4111 str[len] = '\0';
4112
4113 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4114 dst->vb_strvalue = str;
4115 dst->vb_length = len;
4116
4117 if (out) *out = str;
4118
4119 return 0;
4120}
4121
4122/** Change the length of a buffer already allocated to a value box
4123 *
4124 * @note Do not use on an uninitialised box.
4125 *
4126 * @param[in] ctx to realloc buffer in.
4127 * @param[out] out if non-null where to write a pointer to the new buffer.
4128 * @param[in] dst to realloc buffer for.
4129 * @param[in] len to realloc to (don't include nul byte).
4130 * @return
4131 * - 0 on success.
4132 * - -1 on failure.
4133 */
4134int fr_value_box_bstr_realloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, size_t len)
4135{
4136 size_t clen;
4137 char *cstr;
4138 char *str;
4139
4140 fr_assert(dst->type == FR_TYPE_STRING);
4141
4142 memcpy(&cstr, &dst->vb_strvalue, sizeof(cstr));
4143
4144 clen = talloc_array_length(dst->vb_strvalue) - 1;
4145 if (clen == len) return 0; /* No change */
4146
4147 str = talloc_realloc(ctx, cstr, char, len + 1);
4148 if (!str) {
4149 fr_strerror_printf("Failed reallocing value box buffer to %zu bytes", len + 1);
4150 return -1;
4151 }
4152
4153 /*
4154 * Zero out the additional bytes
4155 */
4156 if (clen < len) {
4157 memset(str + clen, '\0', (len - clen) + 1);
4158 } else {
4159 cstr[len] = '\0';
4160 }
4161 dst->vb_strvalue = str;
4162 dst->vb_length = len;
4163
4164 if (out) *out = str;
4165
4166 return 0;
4167}
4168
4169/** Copy a string to to a #fr_value_box_t
4170 *
4171 * @param[in] ctx to allocate any new buffers in.
4172 * @param[in] dst to assign buffer to.
4173 * @param[in] enumv Aliases for values.
4174 * @param[in] src a string. May be NULL only if len == 0.
4175 * @param[in] len of src.
4176 * @param[in] tainted Whether the value came from a trusted source.
4177 */
4178int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4179 char const *src, size_t len, bool tainted)
4180{
4181 char const *str;
4182
4183 if (unlikely((len > 0) && !src)) {
4184 fr_strerror_printf("Invalid arguments to %s. Len > 0 (%zu) but src string was NULL",
4185 __FUNCTION__, len);
4186 return -1;
4187 }
4188
4189 str = talloc_bstrndup(ctx, src, len);
4190 if (!str) {
4191 fr_strerror_const("Failed allocating string buffer");
4192 return -1;
4193 }
4194
4195 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4196 dst->vb_strvalue = str;
4197 dst->vb_length = len;
4198
4199 return 0;
4200}
4201
4202int fr_value_box_bstrndup_dbuff(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4203 fr_dbuff_t *dbuff, size_t len, bool tainted)
4204{
4205 char *str;
4206
4207 str = talloc_array(ctx, char, len + 1);
4208 if (!str) {
4209 fr_strerror_printf("Failed allocating string buffer");
4210 return -1;
4211 }
4212
4213 if (fr_dbuff_out_memcpy((uint8_t *)str, dbuff, len) < 0) return -1;
4214 str[len] = '\0';
4215
4216 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4217 dst->vb_strvalue = str;
4218 dst->vb_length = len;
4219
4220 return 0;
4221}
4222
4223/** Copy a nul terminated talloced buffer to a #fr_value_box_t
4224 *
4225 * Copy a talloced nul terminated buffer, setting fields in the dst value box appropriately.
4226 *
4227 * The buffer must be \0 terminated, or an error will be returned.
4228 *
4229 * @param[in] ctx to allocate any new buffers in.
4230 * @param[in] dst to assign new buffer to.
4231 * @param[in] enumv Aliases for values.
4232 * @param[in] src a talloced nul terminated buffer.
4233 * @param[in] tainted Whether the value came from a trusted source.
4234 * @return
4235 * - 0 on success.
4236 * - -1 on failure.
4237 */
4238int fr_value_box_bstrdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4239 char const *src, bool tainted)
4240{
4241 size_t len;
4242
4243 (void)talloc_get_type_abort_const(src, char);
4244
4245 len = talloc_array_length(src);
4246 if ((len == 0) || (src[len - 1] != '\0')) {
4247 fr_strerror_const("Input buffer not \\0 terminated");
4248 return -1;
4249 }
4250
4251 return fr_value_box_bstrndup(ctx, dst, enumv, src, len - 1, tainted);
4252}
4253
4254/** Assign a string to to a #fr_value_box_t
4255 *
4256 * @param[in] dst to assign new buffer to.
4257 * @param[in] enumv Aliases for values.
4258 * @param[in] src a string.
4259 * @param[in] len of src.
4260 * @param[in] tainted Whether the value came from a trusted source.
4261 */
4263 char const *src, size_t len, bool tainted)
4264{
4265 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4266 dst->vb_strvalue = src;
4267 dst->vb_length = len;
4268}
4269
4270/** Assign a talloced buffer containing a nul terminated string to a box, but don't copy it
4271 *
4272 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
4273 *
4274 * @param[in] ctx to add reference from. If NULL no reference will be added.
4275 * @param[in] dst to assign string to.
4276 * @param[in] enumv Aliases for values.
4277 * @param[in] src to copy string from.
4278 * @param[in] tainted Whether the value came from a trusted source.
4279 * @return
4280 * - 0 on success.
4281 * - -1 on failure.
4282 */
4284 char const *src, bool tainted)
4285{
4286 size_t len;
4287
4288 (void) talloc_get_type_abort_const(src, char);
4289
4290 len = talloc_array_length(src);
4291 if ((len == 0) || (src[len - 1] != '\0')) {
4292 fr_strerror_const("Input buffer not \\0 terminated");
4293 return -1;
4294 }
4295
4296 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4297 dst->vb_strvalue = ctx ? talloc_reference(ctx, src) : src;
4298 dst->vb_length = len - 1;
4299
4300 return 0;
4301}
4302
4303/** Pre-allocate an octets buffer for filling by the caller
4304 *
4305 * @note Buffer will not be zeroed, as it's assumed the caller will be filling it.
4306 *
4307 * @param[in] ctx to allocate any new buffers in.
4308 * @param[out] out If non-null will be filled with a pointer to the
4309 * new buffer.
4310 * @param[in] dst to assign new buffer to.
4311 * @param[in] enumv Aliases for values.
4312 * @param[in] len of data in the buffer. If 0, a zero length
4313 * talloc buffer will be alloced. dst->vb_octets
4314 * will *NOT* be NULL. You should use the length
4315 * field of the box to determine if any value
4316 * is assigned.
4317 * @param[in] tainted Whether the value came from a trusted source.
4318 * @return
4319 * - 0 on success.
4320 * - -1 on failure.
4321 */
4322int fr_value_box_mem_alloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4323 size_t len, bool tainted)
4324{
4325 uint8_t *bin;
4326
4327 bin = talloc_array(ctx, uint8_t, len);
4328 if (!bin) {
4329 fr_strerror_const("Failed allocating octets buffer");
4330 return -1;
4331 }
4332 talloc_set_type(bin, uint8_t);
4333
4334 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4335 dst->vb_octets = bin;
4336 dst->vb_length = len;
4337
4338 if (out) *out = bin;
4339
4340 return 0;
4341}
4342
4343/** Change the length of a buffer already allocated to a value box
4344 *
4345 * @note Do not use on an uninitialised box.
4346 *
4347 * @param[in] ctx to realloc buffer in.
4348 * @param[out] out if non-null where to write a pointer to the new buffer.
4349 * @param[in] dst to realloc buffer for.
4350 * @param[in] len to realloc to.
4351 * @return
4352 * - 0 on success.
4353 * - -1 on failure.
4354 */
4355int fr_value_box_mem_realloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, size_t len)
4356{
4357 size_t clen;
4358 uint8_t *cbin;
4359 uint8_t *bin;
4360
4361 fr_assert(dst->type == FR_TYPE_OCTETS);
4362
4363 memcpy(&cbin, &dst->vb_octets, sizeof(cbin));
4364
4365 clen = talloc_array_length(dst->vb_octets);
4366 if (clen == len) return 0; /* No change */
4367
4368 /*
4369 * Realloc the buffer. If the new length is 0, we
4370 * need to call talloc_array() instead of talloc_realloc()
4371 * as talloc_realloc() will fail.
4372 */
4373 if (len > 0) {
4374 bin = talloc_realloc(ctx, cbin, uint8_t, len);
4375 } else {
4376 bin = talloc_array(ctx, uint8_t, 0);
4377 }
4378 if (!bin) {
4379 fr_strerror_printf("Failed reallocing value box buffer to %zu bytes", len);
4380 return -1;
4381 }
4382
4383 /*
4384 * Only free the original buffer once we've allocated
4385 * a new empty array.
4386 */
4387 if (len == 0) talloc_free(cbin);
4388
4389 /*
4390 * Zero out the additional bytes
4391 */
4392 if (clen < len) memset(bin + clen, 0x00, len - clen);
4393 dst->vb_octets = bin;
4394 dst->vb_length = len;
4395
4396 if (out) *out = bin;
4397
4398 return 0;
4399}
4400
4401/** Copy a buffer to a fr_value_box_t
4402 *
4403 * Copy a buffer containing binary data, setting fields in the dst value box appropriately.
4404 *
4405 * @param[in] ctx to allocate any new buffers in.
4406 * @param[in] dst to assign new buffer to.
4407 * @param[in] enumv Aliases for values.
4408 * @param[in] src a buffer.
4409 * @param[in] len of data in the buffer. If 0, a zero length
4410 * talloc buffer will be alloced. dst->vb_octets
4411 * will *NOT* be NULL. You should use the length
4412 * field of the box to determine if any value
4413 * is assigned.
4414 * @param[in] tainted Whether the value came from a trusted source.
4415 * @return
4416 * - 0 on success.
4417 * - -1 on failure.
4418 */
4419int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4420 uint8_t const *src, size_t len, bool tainted)
4421{
4422 uint8_t *bin;
4423
4424 if (unlikely((len > 0) && !src)) {
4425 fr_strerror_printf("Invalid arguments to %s. Len > 0 (%zu) but src was NULL",
4426 __FUNCTION__, len);
4427 return -1;
4428 }
4429
4430 bin = talloc_memdup(ctx, src, len);
4431 if (!bin) {
4432 fr_strerror_const("Failed allocating octets buffer");
4433 return -1;
4434 }
4435 talloc_set_type(bin, uint8_t);
4436
4437 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4438 dst->vb_octets = bin;
4439 dst->vb_length = len;
4440
4441 return 0;
4442}
4443
4444int fr_value_box_memdup_dbuff(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4445 fr_dbuff_t *dbuff, size_t len, bool tainted)
4446{
4447 uint8_t *bin;
4448
4449 bin = talloc_size(ctx, len);
4450 if (!bin) {
4451 fr_strerror_printf("Failed allocating octets buffer");
4452 return -1;
4453 }
4454 if (fr_dbuff_out_memcpy(bin, dbuff, len) < (ssize_t) len) return -1;
4455 talloc_set_type(bin, uint8_t);
4456
4457 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4458 dst->vb_octets = bin;
4459 dst->vb_length = len;
4460
4461 return 0;
4462}
4463
4464/** Copy a talloced buffer to a fr_value_box_t
4465 *
4466 * Copy a buffer containing binary data, setting fields in the dst value box appropriately.
4467 *
4468 * @param[in] ctx to allocate any new buffers in.
4469 * @param[in] dst to assign new buffer to.
4470 * @param[in] enumv Aliases for values.
4471 * @param[in] src a buffer.
4472 * @param[in] tainted Whether the value came from a trusted source.
4473 * @return
4474 * - 0 on success.
4475 * - -1 on failure.
4476 */
4477int fr_value_box_memdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4478 uint8_t const *src, bool tainted)
4479{
4481
4482 return fr_value_box_memdup(ctx, dst, enumv, src, talloc_array_length(src), tainted);
4483}
4484
4485/** Assign a buffer to a box, but don't copy it
4486 *
4487 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
4488 *
4489 * Caller should set dst->taint = true, where the value was acquired from an untrusted source.
4490 *
4491 * @note Will free any exiting buffers associated with the value box.
4492 *
4493 * @param[in] dst to assign buffer to.
4494 * @param[in] enumv Aliases for values.
4495 * @param[in] src a talloced buffer.
4496 * @param[in] len of buffer.
4497 * @param[in] tainted Whether the value came from a trusted source.
4498 */
4500 uint8_t const *src, size_t len, bool tainted)
4501{
4502 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4503 dst->vb_octets = src;
4504 dst->vb_length = len;
4505}
4506
4507/** Assign a talloced buffer to a box, but don't copy it
4508 *
4509 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
4510 *
4511 * @param[in] ctx to allocate any new buffers in.
4512 * @param[in] dst to assign buffer to.
4513 * @param[in] enumv Aliases for values.
4514 * @param[in] src a talloced buffer.
4515 * @param[in] tainted Whether the value came from a trusted source.
4516 */
4518 uint8_t const *src, bool tainted)
4519{
4521
4522 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4523 dst->vb_octets = ctx ? talloc_reference(ctx, src) : src;
4524 dst->vb_length = talloc_array_length(src);
4525}
4526
4527/** Increment a boxed value
4528 *
4529 * Implements safe integer overflow.
4530 *
4531 * @param[in] vb to increment.
4532 */
4534{
4535 switch (vb->type) {
4536 case FR_TYPE_UINT8:
4537 vb->vb_uint8 = vb->vb_uint8 == UINT8_MAX ? 0 : vb->vb_uint8 + 1;
4538 return;
4539
4540 case FR_TYPE_UINT16:
4541 vb->vb_uint16 = vb->vb_uint16 == UINT16_MAX ? 0 : vb->vb_uint16 + 1;
4542 return;
4543
4544 case FR_TYPE_UINT32:
4545 vb->vb_uint32 = vb->vb_uint32 == UINT32_MAX ? 0 : vb->vb_uint32 + 1;
4546 return;
4547
4548 case FR_TYPE_UINT64:
4549 vb->vb_uint64 = vb->vb_uint64 == UINT64_MAX ? 0 : vb->vb_uint64 + 1;
4550 return;
4551
4552 case FR_TYPE_INT8:
4553 vb->vb_int8 = vb->vb_int8 == INT8_MAX ? INT8_MIN : vb->vb_int8 + 1;
4554 return;
4555
4556 case FR_TYPE_INT16:
4557 vb->vb_int16 = vb->vb_int16 == INT16_MAX ? INT16_MIN : vb->vb_int16 + 1;
4558 return;
4559
4560 case FR_TYPE_INT32:
4561 vb->vb_int32 = vb->vb_int32 == INT32_MAX ? INT32_MIN : vb->vb_int32 + 1;
4562 return;
4563
4564 case FR_TYPE_INT64:
4565 vb->vb_int64 = vb->vb_int64 == INT64_MAX ? INT64_MIN : vb->vb_int64 + 1;
4566 return;
4567
4568 default:
4569 return;
4570 }
4571}
4572
4573/** Convert integer encoded as string to a fr_value_box_t type
4574 *
4575 * @param[out] dst where to write parsed value.
4576 * @param[in] dst_type type of integer to convert string to.
4577 * @param[in] dst_enumv Enumeration values.
4578 * @param[in] in String to convert to integer.
4579 * @param[in] rules for parsing string.
4580 * @param[in] tainted Whether the value came from a trusted source.
4581 * @return
4582 * - >= 0 on success (number of bytes parsed).
4583 * - < 0 on error (where the parse error occurred).
4584 */
4585static inline CC_HINT(always_inline)
4587 fr_dict_attr_t const *dst_enumv,
4588 fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules, bool tainted)
4589{
4590 fr_slen_t slen;
4592
4593 fr_value_box_init(dst, dst_type, dst_enumv, tainted);
4594
4595 switch (dst_type) {
4596 case FR_TYPE_UINT8:
4597 slen = fr_sbuff_out(&err, &dst->vb_uint8, in);
4598 break;
4599
4600 case FR_TYPE_UINT16:
4601 slen = fr_sbuff_out(&err, &dst->vb_uint16, in);
4602 break;
4603
4604 case FR_TYPE_UINT32:
4605 slen = fr_sbuff_out(&err, &dst->vb_uint32, in);
4606 break;
4607
4608 case FR_TYPE_UINT64:
4609 slen = fr_sbuff_out(&err, &dst->vb_uint64, in);
4610 break;
4611
4612 case FR_TYPE_INT8:
4613 slen = fr_sbuff_out(&err, &dst->vb_int8, in);
4614 break;
4615
4616 case FR_TYPE_INT16:
4617 slen = fr_sbuff_out(&err, &dst->vb_int16, in);
4618 break;
4619
4620 case FR_TYPE_INT32:
4621 slen = fr_sbuff_out(&err, &dst->vb_int32, in);
4622 break;
4623
4624 case FR_TYPE_INT64:
4625 slen = fr_sbuff_out(&err, &dst->vb_int64, in);
4626 break;
4627
4628 case FR_TYPE_SIZE:
4629 slen = fr_sbuff_out(&err, &dst->vb_size, in);
4630 break;
4631
4632 case FR_TYPE_FLOAT32:
4633 slen = fr_sbuff_out(&err, &dst->vb_float32, in);
4634 break;
4635
4636 case FR_TYPE_FLOAT64:
4637 slen = fr_sbuff_out(&err, &dst->vb_float64, in);
4638 break;
4639
4640 default:
4641 fr_assert_fail(NULL);
4642 return -1;
4643 }
4644
4645 if (slen < 0) {
4646 /*
4647 * If an enumeration attribute is provided and we
4648 * don't find an integer, assume this is an enumv
4649 * lookup fail, and produce a better error.
4650 */
4651 if (dst_enumv && dst_enumv->flags.has_value && (err == FR_SBUFF_PARSE_ERROR_NOT_FOUND)) {
4652 fr_sbuff_t our_in = FR_SBUFF(in);
4653 fr_sbuff_adv_until(&our_in, SIZE_MAX, rules->terminals,
4654 rules->escapes ? rules->escapes->chr : '\0');
4655
4656 fr_strerror_printf("Invalid enumeration value \"%pV\" for attribute %s",
4658 dst_enumv->name);
4659 return -1;
4660 }
4661
4663 fr_strerror_printf("Failed parsing string as type '%s'",
4664 fr_type_to_str(dst_type));
4665 } else {
4666 fr_sbuff_parse_error_to_strerror(err);
4667 }
4668 }
4669
4670
4671 return slen;
4672}
4673
4674/** Convert string value to a fr_value_box_t type
4675 *
4676 * @param[in] ctx to alloc strings in.
4677 * @param[out] dst where to write parsed value.
4678 * @param[in,out] dst_type of value data to create/dst_type of value created.
4679 * @param[in] dst_enumv fr_dict_attr_t with string names for uint32 values.
4680 * @param[in] in sbuff to read data from.
4681 * @param[in] rules unescape and termination rules.
4682 * @return
4683 * - >0 on success.
4684 * - <= 0 on parse error.
4685 */
4687 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
4688 fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules)
4689{
4690 static fr_sbuff_parse_rules_t default_rules;
4691 fr_sbuff_t *unescaped = NULL;
4692 fr_sbuff_t our_in = FR_SBUFF(in);
4693 fr_ipaddr_t addr;
4694 fr_slen_t slen;
4695 char buffer[256];
4696
4697 if (!rules) rules = &default_rules;
4698
4700
4701 /*
4702 * Lookup any names before continuing
4703 */
4704 if (dst_enumv && dst_enumv->flags.has_value) {
4705 size_t name_len;
4706 fr_dict_enum_value_t *enumv;
4707
4708 /*
4709 * @todo - allow enum names for IPv6 addresses and prefixes. See also
4710 * tmpl_afrom_enum().
4711 */
4712 (void) fr_sbuff_adv_past_str_literal(&our_in, "::");
4713
4714 /*
4715 * If there is no escaping, then we ignore the terminals. The list of allowed characters
4716 * in enum names will ensure that the parsing doesn't go too far. i.e. to '\r', '\n'. '}', etc.
4717 *
4718 * The reason is that the list of terminals may include things like '-', which is also a
4719 * valid character in enum names. We don't want to parse "Framed-User" as "Framed - User".
4720 */
4721 if (!rules->escapes) {
4722 size_t len;
4724
4725 fr_sbuff_marker(&m, &our_in);
4726
4727 len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in),
4729 fr_sbuff_set(&our_in, &m);
4730 fr_sbuff_marker_release(&m);
4731
4732 if (!len) goto parse; /* Zero length name can't match enum */
4733
4734 enumv = fr_dict_enum_by_name(dst_enumv, fr_sbuff_current(&our_in), len);
4735 if (!enumv) {
4736 goto parse; /* No enumeration matches escaped string */
4737 }
4738
4739 (void) fr_sbuff_advance(&our_in, len);
4740 goto cast_enum;
4741 }
4742
4743 /*
4744 * Create a thread-local extensible buffer to
4745 * store unescaped data.
4746 *
4747 * This is created once per-thread (the first time
4748 * this function is called), and freed when the
4749 * thread exits.
4750 */
4751 FR_SBUFF_TALLOC_THREAD_LOCAL(&unescaped, 256, 4096);
4752
4753 /*
4754 * This function only does escaping until a terminal character, such as '-'. So
4755 * Framed-User will get parsed as "Framed - User".
4756 *
4757 * Pretty much no other enum has this problem. For Service-Type, it defines "Framed" ss
4758 * an equivalent name to "Framed-User". The parser sees "Framed-User", stops at the '-',
4759 * and then finds the enum named "Framed". It then returns the trailing "-User" as
4760 * something more to parse.
4761 *
4762 * As a result, when the user passes in "Framed-User", the output is "Framed-User -
4763 * User", which is more than a bit surprising.
4764 */
4765 name_len = fr_sbuff_out_unescape_until(unescaped, &our_in, SIZE_MAX,
4766 rules->terminals, rules->escapes);
4767 if (!name_len) {
4768 fr_sbuff_set_to_start(&our_in);
4769 goto parse; /* Zero length name can't match enum */
4770 }
4771
4772 enumv = fr_dict_enum_by_name(dst_enumv, fr_sbuff_start(unescaped), fr_sbuff_used(unescaped));
4773 if (!enumv) {
4774 fr_sbuff_set_to_start(&our_in);
4775 goto parse; /* No enumeration matches escaped string */
4776 }
4777
4778 cast_enum:
4779 /*
4780 * dst_type may not match enumv type
4781 */
4782 if (fr_value_box_cast(ctx, dst, dst_type, dst_enumv, enumv->value) < 0) return -1;
4783
4784 FR_SBUFF_SET_RETURN(in, &our_in);
4785 }
4786
4787parse:
4788 /*
4789 * It's a variable ret src->dst_type so we just alloc a new buffer
4790 * of size len and copy.
4791 */
4792 switch (dst_type) {
4793 case FR_TYPE_STRING:
4794 /*
4795 * We've not unescaped the string yet, produce an unescaped version
4796 */
4797 if (!dst_enumv || !unescaped) {
4798 char *buff;
4799
4800 if (unlikely(fr_sbuff_out_aunescape_until(ctx, &buff, &our_in, SIZE_MAX,
4801 rules->terminals, rules->escapes) < 0)) {
4802 return -1;
4803 }
4804 fr_value_box_bstrdup_buffer_shallow(NULL, dst, dst_enumv, buff, false);
4805 /*
4806 * We already have an unescaped version, just use that
4807 */
4808 } else {
4809 fr_value_box_bstrndup(ctx, dst, dst_enumv,
4810 fr_sbuff_start(unescaped), fr_sbuff_used(unescaped), false);
4811 }
4812 FR_SBUFF_SET_RETURN(in, &our_in);
4813
4814 /* raw octets: 0x01020304... */
4815 case FR_TYPE_OCTETS:
4816 {
4817 fr_sbuff_marker_t hex_start;
4818 size_t hex_len;
4819 uint8_t *bin_buff;
4820
4821 /*
4822 * If there's escape sequences that need to be processed
4823 * or the string doesn't start with 0x, then assume this
4824 * is literal data, not hex encoded data.
4825 */
4826 if (rules->escapes || !fr_sbuff_adv_past_strcase_literal(&our_in, "0x")) {
4827 if (!dst_enumv || !unescaped) {
4828 char *buff = NULL;
4829 uint8_t *bin;
4830
4831 if (fr_sbuff_extend(&our_in)) {
4832 fr_sbuff_out_aunescape_until(ctx, &buff, &our_in, SIZE_MAX,
4833 rules->terminals, rules->escapes);
4834
4835 if (talloc_array_length(buff) == 1) {
4837 goto zero;
4838 }
4839
4840 bin = talloc_realloc(ctx, buff, uint8_t, talloc_array_length(buff) - 1);
4841 if (unlikely(!bin)) {
4842 fr_strerror_const("Failed trimming string buffer");
4844 return -1;
4845 }
4846 talloc_set_type(bin, uint8_t); /* talloc_realloc doesn't do this */
4847 /*
4848 * Input data is zero
4849 *
4850 * talloc realloc will refuse to realloc to
4851 * a zero length buffer. This is probably
4852 * a bug, because we can create zero length
4853 * arrays normally
4854 */
4855 } else {
4856 zero:
4857 bin = talloc_zero_array(ctx, uint8_t, 0);
4858 }
4859
4860 fr_value_box_memdup_buffer_shallow(NULL, dst, dst_enumv, bin, false);
4861 /*
4862 * We already have an unescaped version, just use that
4863 */
4864 } else {
4865 fr_value_box_memdup(ctx, dst, dst_enumv,
4866 (uint8_t *)fr_sbuff_start(unescaped),
4867 fr_sbuff_used(unescaped), false);
4868 }
4869 FR_SBUFF_SET_RETURN(in, &our_in);
4870 }
4871
4872 fr_sbuff_marker(&hex_start, &our_in); /* Record where the hexits start */
4873
4874 /*
4875 * Find the end of the hex sequence.
4876 *
4877 * We don't technically need to do this, fr_base16_decode
4878 * will find the end on its own.
4879 *
4880 * We do this so we can alloc the correct sized
4881 * output buffer.
4882 */
4883 hex_len = fr_sbuff_adv_past_allowed(&our_in, SIZE_MAX, sbuff_char_class_hex, rules->terminals);
4884 if (hex_len == 0) {
4885 if (fr_value_box_memdup(ctx, dst, dst_enumv, (uint8_t[]){ 0x00 }, 0, false) < 0) return -1;
4886 FR_SBUFF_SET_RETURN(in, &our_in);
4887 }
4888
4889 if ((hex_len & 0x01) != 0) {
4890 fr_strerror_printf("Length of hex string is not even, got %zu bytes", hex_len);
4891 FR_SBUFF_ERROR_RETURN(&our_in);
4892 }
4893
4894 /*
4895 * Pre-allocate the bin buff and initialise the box
4896 */
4897 if (fr_value_box_mem_alloc(ctx, &bin_buff, dst, dst_enumv, (hex_len >> 1), false) < 0) return -1;
4898
4899 /*
4900 * Reset to the start of the hex string
4901 */
4902 fr_sbuff_set(&our_in, &hex_start);
4903
4904 if (unlikely(fr_base16_decode(NULL, &FR_DBUFF_TMP(bin_buff, hex_len), &our_in, false) < 0)) {
4905 talloc_free(bin_buff);
4906 FR_SBUFF_ERROR_RETURN(&our_in);
4907 }
4908
4909 FR_SBUFF_SET_RETURN(in, &our_in);
4910 }
4911
4912 case FR_TYPE_IPV4_ADDR:
4913 {
4914 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
4915 if (!name_len) return 0;
4916
4917 if (fr_inet_pton4(&addr, fr_sbuff_current(in), name_len,
4918 fr_hostname_lookups, false, true) < 0) return -1;
4919
4920 /*
4921 * We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
4922 * print them this way.
4923 */
4924 if (addr.prefix != 32) {
4925 fail_ipv4_prefix:
4926 fr_strerror_printf("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted "
4927 "for non-prefix types", addr.prefix);
4928 return -1;
4929 }
4930
4931 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
4932 }
4933 goto finish;
4934
4936 {
4937 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
4938 if (!name_len) return 0;
4939
4940 if (fr_inet_pton4(&dst->vb_ip, fr_sbuff_current(in), name_len,
4941 fr_hostname_lookups, false, true) < 0) return -1;
4942 }
4943 goto finish;
4944
4945 case FR_TYPE_IPV6_ADDR:
4946 {
4947 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
4948 if (!name_len) return 0;
4949
4950 /*
4951 * Parse scope, too.
4952 */
4953 if (fr_sbuff_next_if_char(&our_in, '%')) {
4954 name_len += fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_uint, rules->terminals);
4955 }
4956
4957 if (fr_inet_pton6(&addr, fr_sbuff_current(in), name_len,
4958 fr_hostname_lookups, false, true) < 0) return -1;
4959
4960 /*
4961 * We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
4962 * print them this way.
4963 */
4964 if (addr.prefix != 128) {
4965 fail_ipv6_prefix:
4966 fr_strerror_printf("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted "
4967 "for non-prefix types", addr.prefix);
4968 return -1;
4969 }
4970
4971 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
4972 }
4973 goto finish;
4974
4976 {
4977 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
4978 if (!name_len) return 0;
4979
4980 if (fr_inet_pton6(&dst->vb_ip, fr_sbuff_current(in), name_len,
4981 fr_hostname_lookups, false, true) < 0) return -1;
4982 }
4983 goto finish;
4984
4986 {
4987 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
4988 if (!name_len) return 0;
4989
4990 /*
4991 * Parse scope, too.
4992 */
4993 if (fr_sbuff_next_if_char(&our_in, '%')) {
4994 name_len += fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_uint, rules->terminals);
4995 }
4996
4997 if (fr_inet_pton(&addr, fr_sbuff_current(in), name_len, AF_UNSPEC,
4998 fr_hostname_lookups, true) < 0) return -1;
4999
5000 if ((addr.af == AF_INET) && (addr.prefix != 32)) {
5001 goto fail_ipv4_prefix;
5002 }
5003
5004 if ((addr.af == AF_INET6) && (addr.prefix != 128)) {
5005 goto fail_ipv6_prefix;
5006 }
5007
5008 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5009 }
5010 goto finish;
5011
5013 {
5014 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5015 if (!name_len) return 0;
5016
5017 if (fr_inet_pton(&dst->vb_ip, fr_sbuff_current(in), name_len, AF_UNSPEC,
5018 fr_hostname_lookups, true) < 0) return -1;
5019 }
5020 goto finish;
5021
5022 case FR_TYPE_UINT8:
5023 case FR_TYPE_UINT16:
5024 case FR_TYPE_UINT32:
5025 case FR_TYPE_UINT64:
5026 case FR_TYPE_INT8:
5027 case FR_TYPE_INT16:
5028 case FR_TYPE_INT32:
5029 case FR_TYPE_INT64:
5030 case FR_TYPE_FLOAT32:
5031 case FR_TYPE_FLOAT64:
5032 return fr_value_box_from_numeric_substr(dst, dst_type, dst_enumv, in, rules, false);
5033
5034 case FR_TYPE_SIZE:
5035 if (fr_size_from_str(&dst->datum.size, &our_in) < 0) return -1;
5036 goto finish;
5037
5038 case FR_TYPE_BOOL:
5039 fr_value_box_init(dst, dst_type, dst_enumv, false);
5040
5041 /*
5042 * Quoted boolean values are "yes", "no", "true", "false"
5043 */
5044 slen = fr_sbuff_out(NULL, &dst->vb_bool, in);
5045 if (slen >= 0) return slen;
5046
5047 /*
5048 * For barewords we also allow 0 for false and any other
5049 * integer value for true.
5050 */
5051 if (!rules->escapes) {
5052 int64_t stmp;
5053 uint64_t utmp;
5054
5055 slen = fr_sbuff_out(NULL, &stmp, in);
5056 if (slen >= 0) {
5057 dst->vb_bool = (stmp != 0);
5058 return slen;
5059 }
5060
5061 slen = fr_sbuff_out(NULL, &utmp, in);
5062 if (slen >= 0) {
5063 dst->vb_bool = (utmp != 0);
5064 return slen;
5065 }
5066 }
5067
5068 fr_strerror_const("Invalid boolean value. Accepted values are "
5069 "\"yes\", \"no\", \"true\", \"false\" or any unquoted integer");
5070
5071 return slen; /* Just whatever the last error offset was */
5072
5073 case FR_TYPE_ETHERNET:
5074 {
5075 uint64_t num;
5076 fr_ethernet_t ether;
5077 fr_dbuff_t dbuff;
5079
5080 fr_dbuff_init(&dbuff, ether.addr, sizeof(ether.addr));
5081
5082 /*
5083 * Convert things which are obviously integers to Ethernet addresses
5084 *
5085 * We assume the number is the decimal
5086 * representation of the ethernet address.
5087 * i.e. the ethernet address converted to a
5088 * number, and printed.
5089 *
5090 * The string gets converted to a network-order
5091 * 8-byte number, and then the lower bytes of
5092 * that get copied to the ethernet address.
5093 *
5094 * Note: We need to check for a terminal sequence
5095 * after the number, else we may just end up
5096 * parsing the first hexit and returning.
5097 *
5098 * i.e. 1c:00:00:00:00 -> 1
5099 */
5100 if ((fr_sbuff_out(NULL, &num, &our_in) > 0) && fr_sbuff_is_terminal(&our_in, rules->terminals)) {
5101 num = htonll(num);
5102
5103 FR_DBUFF_IN_MEMCPY_RETURN(&dbuff, ((uint8_t *) &num) + 2, sizeof(dst->vb_ether));
5104 fr_value_box_ethernet_addr(dst, dst_enumv, &ether, false);
5105
5106 FR_SBUFF_SET_RETURN(in, &our_in);
5107 }
5108
5109 fr_sbuff_set_to_start(&our_in);
5110
5111 fr_base16_decode(&err, &dbuff, &our_in, true);
5112 if (err != FR_SBUFF_PARSE_OK) {
5113 ether_error:
5114 fr_sbuff_parse_error_to_strerror(err);
5115 FR_SBUFF_ERROR_RETURN(&our_in);
5116 }
5117
5118 if (!fr_sbuff_next_if_char(&our_in, ':')) {
5119 ether_sep_error:
5120 fr_strerror_const("Missing separator, expected ':'");
5121 FR_SBUFF_ERROR_RETURN(&our_in);
5122 }
5123
5124 fr_base16_decode(&err, &dbuff, &our_in, true);
5125 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5126
5127 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5128
5129 fr_base16_decode(&err, &dbuff, &our_in, true);
5130 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5131
5132 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5133
5134 fr_base16_decode(&err, &dbuff, &our_in, true);
5135 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5136
5137 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5138
5139 fr_base16_decode(&err, &dbuff, &our_in, true);
5140 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5141
5142 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5143
5144 fr_base16_decode(&err, &dbuff, &our_in, true);
5145 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5146
5147 fr_value_box_ethernet_addr(dst, dst_enumv, (fr_ethernet_t * const)fr_dbuff_start(&dbuff), false);
5148
5149 FR_SBUFF_SET_RETURN(in, &our_in);
5150 }
5151
5152 case FR_TYPE_TIME_DELTA:
5153 fr_value_box_init(dst, FR_TYPE_TIME_DELTA, dst_enumv, false);
5154
5155 slen = fr_time_delta_from_substr(&dst->datum.time_delta, &our_in,
5156 dst_enumv ? dst_enumv->flags.flag_time_res : FR_TIME_RES_SEC,
5157 false, rules->terminals);
5158 if (slen < 0) return slen;
5159 FR_SBUFF_SET_RETURN(in, &our_in);
5160
5161 case FR_TYPE_NULL:
5162 if (!rules->escapes && fr_sbuff_adv_past_str_literal(&our_in, "NULL")) {
5163 fr_value_box_init(dst, dst_type, dst_enumv, false);
5164 FR_SBUFF_SET_RETURN(in, &our_in);
5165 }
5166
5167 fr_strerror_const("Unexpected value for data type NULL");
5168 return -1;
5169
5170 /*
5171 * Dealt with below
5172 */
5173 default:
5174 break;
5175 }
5176
5177 /*
5178 * We may have terminals. If so, respect them.
5179 */
5180 if (rules && rules->terminals) {
5181 size_t len;
5182
5183 len = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(buffer, sizeof(buffer)), &our_in, SIZE_MAX,
5184 rules->terminals, rules->escapes);
5185 if (len >= sizeof(buffer)) goto too_small;
5186
5187 buffer[len] = '\0';
5188
5189 } else {
5190 /*
5191 * It's a fixed size src->dst_type, copy to a temporary buffer and
5192 * \0 terminate.
5193 *
5194 * @todo - note that this brute-force copy means that the input sbuff
5195 * is NOT advanced, and this function will return 0, even though it parsed data!
5196 */
5197 if (fr_sbuff_remaining(in) >= sizeof(buffer)) {
5198 too_small:
5199 fr_strerror_const("Temporary buffer too small");
5200 return -1;
5201 }
5202
5204 buffer[fr_sbuff_remaining(in)] = '\0';
5205 }
5206
5207 switch (dst_type) {
5208 case FR_TYPE_DATE:
5209 {
5210 if (dst_enumv) {
5211 if (fr_unix_time_from_str(&dst->vb_date, buffer, dst_enumv->flags.flag_time_res) < 0) return -1;
5212 } else {
5213 if (fr_unix_time_from_str(&dst->vb_date, buffer, FR_TIME_RES_SEC) < 0) return -1;
5214 }
5215
5216 dst->enumv = dst_enumv;
5217 }
5218 break;
5219
5220 case FR_TYPE_IFID:
5221 if (fr_inet_ifid_pton((void *) dst->vb_ifid, buffer) == NULL) {
5222 fr_strerror_printf("Failed to parse interface-id string \"%s\"", buffer);
5223 return -1;
5224 }
5225 break;
5226
5227 default:
5228 fr_strerror_printf("Cannot parse input as data type %s", fr_type_to_str(dst_type));
5229 return -1;
5230 }
5231
5232finish:
5233 dst->type = dst_type;
5234 dst->tainted = false;
5236
5237 /*
5238 * Fixup enumvs
5239 */
5240 dst->enumv = dst_enumv;
5241 fr_value_box_list_entry_init(dst);
5242
5243 FR_SBUFF_SET_RETURN(in, &our_in);
5244}
5245
5247 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
5248 char const *in, size_t inlen,
5249 fr_sbuff_unescape_rules_t const *erules)
5250{
5251 ssize_t slen;
5252 fr_sbuff_parse_rules_t prules = { .escapes = erules };
5253
5254 slen = fr_value_box_from_substr(ctx, dst, dst_type, dst_enumv, &FR_SBUFF_IN(in, inlen), &prules);
5255 if (slen <= 0) return slen;
5256
5257 if (slen != (ssize_t)inlen) {
5258 fr_strerror_printf("Failed parsing '%s'. %zu bytes of trailing data after string value \"%pV\"",
5259 fr_type_to_str(dst_type),
5260 inlen - slen,
5261 fr_box_strvalue_len(in + slen, inlen - slen));
5262 return (slen - inlen) - 1;
5263 }
5264
5265 return slen;
5266}
5267
5268/** Print one boxed value to a string
5269 *
5270 * This function should primarily be used when a #fr_value_box_t is being
5271 * serialized in some non-standard way, i.e. as a value for a field
5272 * in a database, in all other instances it's better to use
5273 * #fr_value_box_print_quoted.
5274 *
5275 * @note - this function does NOT respect tainting! The escaping rules
5276 * are ONLY for escaping quotation characters, CR, LF, etc.
5277 *
5278 * @param[in] out Where to write the printed string.
5279 * @param[in] data Value box to print.
5280 * @param[in] e_rules To apply to FR_TYPE_STRING types, for escaping quotation characters _only_.
5281 * Is not currently applied to any other box type.
5282 */
5284{
5285 fr_sbuff_t our_out = FR_SBUFF(out);
5286
5287 char buf[1024]; /* Interim buffer to use with poorly behaved printing functions */
5288
5289 if (data->enumv && data->enumv->flags.has_value) {
5290 char const *name;
5291
5293 if (name) {
5294 FR_SBUFF_IN_ESCAPE_BUFFER_RETURN(&our_out, name, NULL);
5295 goto done;
5296 }
5297 }
5298
5299 switch (data->type) {
5300 case FR_TYPE_STRING:
5301 if (data->vb_length) FR_SBUFF_IN_ESCAPE_RETURN(&our_out,
5302 data->vb_strvalue, data->vb_length, e_rules);
5303 break;
5304
5305 case FR_TYPE_OCTETS:
5306 FR_SBUFF_IN_CHAR_RETURN(&our_out, '0', 'x');
5307 if (data->vb_length) FR_SBUFF_RETURN(fr_base16_encode, &our_out,
5308 &FR_DBUFF_TMP(data->vb_octets, data->vb_length));
5309 break;
5310
5311 /*
5312 * We need to use the proper inet_ntop functions for IP
5313 * addresses, else the output might not match output of
5314 * other functions, which makes testing difficult.
5315 *
5316 * An example is tunneled ipv4 in ipv6 addresses.
5317 */
5318 case FR_TYPE_IPV4_ADDR:
5319 case FR_TYPE_IPV6_ADDR:
5321 if (!fr_inet_ntop(buf, sizeof(buf), &data->vb_ip)) return 0;
5322 FR_SBUFF_IN_STRCPY_RETURN(&our_out, buf);
5323 break;
5324
5328 if (!fr_inet_ntop_prefix(buf, sizeof(buf), &data->vb_ip)) return 0;
5329 FR_SBUFF_IN_STRCPY_RETURN(&our_out, buf);
5330 break;
5331
5332 case FR_TYPE_IFID:
5333 if (!fr_inet_ifid_ntop(buf, sizeof(buf), data->vb_ifid)) return 0;
5334 FR_SBUFF_IN_STRCPY_RETURN(&our_out, buf);
5335 break;
5336
5337 case FR_TYPE_ETHERNET:
5338 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%02x:%02x:%02x:%02x:%02x:%02x",
5339 data->vb_ether[0], data->vb_ether[1],
5340 data->vb_ether[2], data->vb_ether[3],
5341 data->vb_ether[4], data->vb_ether[5]);
5342 break;
5343
5344 case FR_TYPE_BOOL:
5345 FR_SBUFF_IN_STRCPY_RETURN(&our_out, data->vb_uint8 ? "yes" : "no");
5346 break;
5347
5348 case FR_TYPE_UINT8:
5349 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", data->vb_uint8);
5350 break;
5351
5352 case FR_TYPE_UINT16:
5353 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", data->vb_uint16);
5354 break;
5355
5356 case FR_TYPE_UINT32:
5357 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", data->vb_uint32);
5358 break;
5359
5360 case FR_TYPE_UINT64:
5361 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%" PRIu64, data->vb_uint64);
5362 break;
5363
5364 case FR_TYPE_INT8:
5365 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%d", data->vb_int8);
5366 break;
5367
5368 case FR_TYPE_INT16:
5369 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%d", data->vb_int16);
5370 break;
5371
5372 case FR_TYPE_INT32:
5373 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%d", data->vb_int32);
5374 break;
5375
5376 case FR_TYPE_INT64:
5377 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%" PRId64, data->vb_int64);
5378 break;
5379
5380 case FR_TYPE_FLOAT32:
5381 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%f", (double) data->vb_float32);
5382 break;
5383
5384 case FR_TYPE_FLOAT64:
5385 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%g", data->vb_float64);
5386 break;
5387
5388 case FR_TYPE_DATE:
5389 {
5391
5392 if (data->enumv) res = data->enumv->flags.flag_time_res;
5393
5394 FR_SBUFF_RETURN(fr_unix_time_to_str, &our_out, data->vb_date, res, true);
5395 break;
5396 }
5397
5398 case FR_TYPE_SIZE:
5399 FR_SBUFF_RETURN(fr_size_to_str, &our_out, data->datum.size);
5400 break;
5401
5402 case FR_TYPE_TIME_DELTA:
5403 {
5405 bool is_unsigned = false;
5406
5407 if (data->enumv) {
5408 res = data->enumv->flags.flag_time_res;
5409 is_unsigned = data->enumv->flags.is_unsigned;
5410 }
5411
5412
5413 FR_SBUFF_RETURN(fr_time_delta_to_str, &our_out, data->vb_time_delta, res, is_unsigned);
5414 }
5415 break;
5416
5417 case FR_TYPE_GROUP:
5418 /*
5419 * If the caller didn't ask to escape binary data
5420 * in 'octets' types, then we force that now.
5421 * Otherwise any 'octets' type which is buried
5422 * inside of a 'group' will get copied verbatim
5423 * from input to output, with no escaping!
5424 */
5425 if (!e_rules || (!e_rules->do_oct && !e_rules->do_hex)) {
5426 e_rules = &fr_value_escape_double;
5427 }
5428
5429 /*
5430 * Represent groups as:
5431 *
5432 * { <value0>, <value1>, { <sub-value0>, <sub-value1>, <sub-valueN> }}
5433 */
5434 FR_SBUFF_IN_CHAR_RETURN(&our_out, '{');
5436 NULL, &our_out, UNCONST(fr_value_box_list_t *, &data->vb_group),
5437 ", ", (sizeof(", ") - 1), e_rules,
5439 FR_SBUFF_IN_CHAR_RETURN(&our_out, '}');
5440 break;
5441
5442 case FR_TYPE_NULL:
5443 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "NULL");
5444 break;
5445 /*
5446 * Don't add default here
5447 */
5448 case FR_TYPE_TLV: /* Not a box type */
5449 case FR_TYPE_STRUCT: /* Not a box type */
5450 case FR_TYPE_VSA: /* Not a box type */
5451 case FR_TYPE_VENDOR: /* Not a box type */
5452 case FR_TYPE_VALUE_BOX:
5453 case FR_TYPE_VOID:
5454 case FR_TYPE_MAX:
5455 (void)fr_cond_assert(0);
5456 return 0;
5457 }
5458
5459done:
5460 FR_SBUFF_SET_RETURN(out, &our_out);
5461}
5462
5463/** Print one boxed value to a string with quotes (where needed)
5464 *
5465 * @param[in] out Where to write the printed string.
5466 * @param[in] data Value box to print.
5467 * @param[in] quote To apply to FR_TYPE_STRING types.
5468 * Is not currently applied to any
5469 * other box type.
5470 */
5472{
5473 fr_sbuff_t our_out = FR_SBUFF(out);
5474
5475 if (quote == T_BARE_WORD) return fr_value_box_print(out, data, NULL);
5476
5477 switch (data->type) {
5478 case FR_TYPE_QUOTED:
5479 FR_SBUFF_IN_CHAR_RETURN(&our_out, fr_token_quote[quote]);
5481 FR_SBUFF_IN_CHAR_RETURN(&our_out, fr_token_quote[quote]);
5482 break;
5483
5484 default:
5485 return fr_value_box_print(out, data, NULL);
5486 }
5487
5488 FR_SBUFF_SET_RETURN(out, &our_out);
5489}
5490
5491/** Concatenate a list of value boxes together
5492 *
5493 * All boxes will be removed from the list.
5494 *
5495 * @param[out] safety if !NULL, the results of tainted / secret / safe_for will be stored here.
5496 * @param[out] sbuff to write the result of the concatenation to.
5497 * @param[in] list to concatenate.
5498 * @param[in] sep Insert a separator between the values.
5499 * @param[in] sep_len Length of the separator.
5500 * @param[in] e_rules To apply to FR_TYPE_STRING types.
5501 * Is not currently applied to any other box type.
5502 * @param[in] proc_action What to do with the boxes in the list once
5503 * they've been processed.
5504 * @param[in] safe_for if value has this safe_for value, don't apply the escape rules.
5505 * for values which are escaped, mash the safe_for value to this.
5506 * @param[in] flatten If true and we encounter a #FR_TYPE_GROUP,
5507 * we concat the contents of its children together.
5508 * If false, the contents will be cast to #FR_TYPE_STRING.
5509 * @return
5510 * - >=0 the number of bytes written to the sbuff.
5511 * - <0 how many additional bytes we would have needed to
5512 * concat the next box.
5513 */
5514ssize_t fr_value_box_list_concat_as_string(fr_value_box_t *safety, fr_sbuff_t *sbuff, fr_value_box_list_t *list,
5515 char const *sep, size_t sep_len, fr_sbuff_escape_rules_t const *e_rules,
5516 fr_value_box_list_action_t proc_action, fr_value_box_safe_for_t safe_for, bool flatten)
5517{
5518 fr_sbuff_t our_sbuff = FR_SBUFF(sbuff);
5519 ssize_t slen;
5520
5521 if (fr_value_box_list_empty(list)) return 0;
5522
5523 if (fr_debug_lvl >= 4) fprintf(stderr, "CONCAT AS STRING");
5524
5525 fr_value_box_list_foreach(list, vb) {
5526 fr_value_box_safe_for_t box_safe_for = vb->safe_for;
5527
5528 if (fr_debug_lvl >= 4) fr_value_box_debug(vb);
5529
5530 switch (vb->type) {
5531 case FR_TYPE_GROUP:
5532 if (!flatten) goto print;
5533 slen = fr_value_box_list_concat_as_string(safety, &our_sbuff, &vb->vb_group,
5534 sep, sep_len, e_rules,
5535 proc_action, safe_for, flatten);
5536 break;
5537
5538 case FR_TYPE_OCTETS:
5539
5540 /*
5541 * Copy the raw string over, if necessary with escaping.
5542 */
5543 if (e_rules && (!fr_value_box_is_safe_for(vb, safe_for) || e_rules->do_oct || e_rules->do_hex)) {
5544 box_safe_for = safe_for;
5545
5546 slen = fr_sbuff_in_escape(&our_sbuff, (char const *)vb->vb_strvalue, vb->vb_length, e_rules);
5547 } else {
5548 slen = fr_sbuff_in_bstrncpy(&our_sbuff, (char const *)vb->vb_strvalue, vb->vb_length);
5549 }
5550 break;
5551
5552 case FR_TYPE_STRING:
5553 if (!fr_value_box_is_safe_for(vb, safe_for) && e_rules) goto print;
5554
5555 slen = fr_sbuff_in_bstrncpy(&our_sbuff, vb->vb_strvalue, vb->vb_length);
5556 break;
5557
5558 case FR_TYPE_NULL: /* Skip null */
5559 continue;
5560
5561 default:
5562 print:
5563 /*
5564 * If we escaped it, set the output safe_for value.
5565 */
5566 if (e_rules) box_safe_for = safe_for;
5567 slen = fr_value_box_print(&our_sbuff, vb, e_rules);
5568 break;
5569 }
5570 if (slen < 0) return slen;
5571
5572 /*
5573 * Add in the separator
5574 */
5575 if (sep && fr_value_box_list_next(list, vb)) {
5576 slen = fr_sbuff_in_bstrncpy(&our_sbuff, sep, sep_len);
5577 if (slen < 0) return slen;
5578 }
5579
5580 /*
5581 * Merge in the safety rules.
5582 */
5583 if (!safety || (vb->type == FR_TYPE_GROUP)) continue;
5584
5585 /*
5586 * We can't call fr_box_safety_merge(), as we may have escaped the input box.
5587 */
5588 if ((safety->safe_for != FR_VALUE_BOX_SAFE_FOR_NONE) &&
5589 (safety->safe_for != box_safe_for)) {
5590 if (safety->safe_for == FR_VALUE_BOX_SAFE_FOR_ANY) {
5591 safety->safe_for = box_safe_for;
5592 } else {
5593 safety->safe_for = FR_VALUE_BOX_SAFE_FOR_NONE;
5594 }
5595 }
5596
5597 safety->tainted |= vb->tainted;
5598 safety->secret |= vb->secret;
5599 }
5600
5601 /*
5602 * Free the boxes last so if there's
5603 * an issue concatenating them, everything
5604 * is still in a known state.
5605 */
5607 if (vb_should_remove(proc_action)) fr_value_box_list_remove(list, vb);
5608 if (vb_should_free_value(proc_action)) fr_value_box_clear_value(vb);
5609 if (vb_should_free(proc_action)) talloc_free(vb);
5610 }}
5611
5612 FR_SBUFF_SET_RETURN(sbuff, &our_sbuff);
5613}
5614
5615/** Concatenate a list of value boxes together
5616 *
5617 * All boxes will be removed from the list.
5618 *
5619 * @param[out] safety if !NULL, the results of tainted / secret / safe_for will be stored here.
5620 * @param[out] dbuff to write the result of the concatenation to.
5621 * @param[in] list to concatenate.
5622 * @param[in] sep Insert a separator between the values.
5623 * @param[in] sep_len Length of the separator.
5624 * @param[in] proc_action What to do with the boxes in the list once
5625 * they've been processed.
5626 * @param[in] flatten If true and we encounter a #FR_TYPE_GROUP,
5627 * we concat the contents of its children together.
5628 * If false, the contents will be cast to #FR_TYPE_OCTETS.
5629 * @return
5630 * - >=0 the number of bytes written to the sbuff.
5631 * - <0 how many additional bytes we would have needed to
5632 * concat the next box.
5633 */
5634ssize_t fr_value_box_list_concat_as_octets(fr_value_box_t *safety, fr_dbuff_t *dbuff, fr_value_box_list_t *list,
5635 uint8_t const *sep, size_t sep_len,
5636 fr_value_box_list_action_t proc_action, bool flatten)
5637{
5638 fr_dbuff_t our_dbuff = FR_DBUFF(dbuff);
5639 TALLOC_CTX *tmp_ctx = NULL;
5640 ssize_t slen;
5641
5642 if (fr_value_box_list_empty(list)) return 0;
5643
5644 fr_value_box_list_foreach(list, vb) {
5645 switch (vb->type) {
5646 case FR_TYPE_GROUP:
5647 if (!flatten) goto cast;
5648 slen = fr_value_box_list_concat_as_octets(safety, &our_dbuff, &vb->vb_group,
5649 sep, sep_len,
5650 proc_action, flatten);
5651 break;
5652
5653 case FR_TYPE_OCTETS:
5654 slen = fr_dbuff_in_memcpy(&our_dbuff, vb->vb_octets, vb->vb_length);
5655 break;
5656
5657 case FR_TYPE_STRING:
5658 slen = fr_dbuff_in_memcpy(&our_dbuff, (uint8_t const *)vb->vb_strvalue, vb->vb_length);
5659 break;
5660
5661 case FR_TYPE_NULL: /* Skip null */
5662 continue;
5663
5664 default:
5665 cast:
5666 {
5667 fr_value_box_t tmp_vb;
5668
5669 if (!tmp_ctx) tmp_ctx = talloc_pool(NULL, 1024);
5670
5671 /*
5672 * Not equivalent to fr_value_box_to_network
5673 */
5674 if (fr_value_box_cast_to_octets(tmp_ctx, &tmp_vb, FR_TYPE_OCTETS, NULL, vb) < 0) {
5675 slen = -1;
5676 goto error;
5677 }
5678
5679 slen = fr_dbuff_in_memcpy(&our_dbuff, tmp_vb.vb_octets, tmp_vb.vb_length);
5680 fr_value_box_clear_value(&tmp_vb);
5681 break;
5682 }
5683 }
5684
5685 if (slen < 0) {
5686 error:
5687 talloc_free(tmp_ctx);
5688 return slen;
5689 }
5690
5691 if (sep && fr_value_box_list_next(list, vb)) {
5692 slen = fr_dbuff_in_memcpy(&our_dbuff, sep, sep_len);
5693 if (slen < 0) goto error;
5694 }
5695
5696 fr_value_box_safety_merge(safety, vb);
5697 }
5698
5699 talloc_free(tmp_ctx);
5700
5701 /*
5702 * Free the boxes last so if there's
5703 * an issue concatenating them, everything
5704 * is still in a known state.
5705 */
5707 if (vb_should_remove(proc_action)) fr_value_box_list_remove(list, vb);
5708 if (vb_should_free_value(proc_action)) fr_value_box_clear_value(vb);
5709 if (vb_should_free(proc_action)) talloc_free(vb);
5710 }}
5711
5712 return fr_dbuff_set(dbuff, &our_dbuff);
5713}
5714
5715/** Concatenate a list of value boxes
5716 *
5717 * @note Will automatically cast all #fr_value_box_t to type specified.
5718 *
5719 * @param[in] ctx to allocate new value buffer in.
5720 * @param[out] out Where to write the resulting box.
5721 * @param[in] list to concatenate together.
5722 * @param[in] type May be #FR_TYPE_STRING or #FR_TYPE_OCTETS, no other types are
5723 * supported.
5724 * @param[in] proc_action What to do with the boxes in the list once
5725 * they've been processed.
5726 * @param[in] flatten If true and we encounter a #FR_TYPE_GROUP,
5727 * we concat the contents of its children together.
5728 * If false, the contents will be cast to the given type.
5729 * @param[in] max_size of the value.
5730 * @return
5731 * - 0 on success.
5732 * - -1 on failure.
5733 */
5735 fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type,
5736 fr_value_box_list_action_t proc_action, bool flatten,
5737 size_t max_size)
5738{
5739 fr_dbuff_t dbuff; /* FR_TYPE_OCTETS */
5740 fr_dbuff_uctx_talloc_t dbuff_tctx;
5741
5742 fr_sbuff_t sbuff; /* FR_TYPE_STRING */
5743 fr_sbuff_uctx_talloc_t sbuff_tctx;
5744
5745 fr_value_box_t *head_vb = fr_value_box_list_head(list);
5746
5747 fr_value_box_entry_t entry;
5748
5749 if (fr_value_box_list_empty(list)) {
5750 fr_strerror_const("Invalid arguments. List contains no elements");
5751 return -1;
5752 }
5753
5754 /*
5755 * Exit quickly if the list is only one box of the correct type and
5756 * out points at that box.
5757 */
5758 if ((fr_value_box_list_num_elements(list) == 1) && (head_vb == out) && (head_vb->type == type)) return 0;
5759
5760 switch (type) {
5761 case FR_TYPE_STRING:
5762 if (unlikely(!fr_sbuff_init_talloc(ctx, &sbuff, &sbuff_tctx, 256, max_size))) return -1;
5763 break;
5764
5765 case FR_TYPE_OCTETS:
5766 if (unlikely(!fr_dbuff_init_talloc(ctx, &dbuff, &dbuff_tctx, 256, max_size))) return -1;
5767 break;
5768
5769 default:
5770 fr_strerror_printf("Invalid argument. Can't concatenate boxes to type %s",
5772 return -1;
5773 }
5774
5775 /*
5776 * Merge all siblings into list head.
5777 *
5778 * This is where the first element in the
5779 * list is the output box.
5780 *
5781 * i.e. we want to merge all its siblings
5782 * into it.
5783 */
5784 if (out == head_vb) {
5785 switch (type) {
5786 case FR_TYPE_STRING:
5787 /*
5788 * Head gets dealt with specially as we don't
5789 * want to free it, and we don't want to free
5790 * the buffer associated with it (just yet).
5791 *
5792 * Note that we don't convert 'octets' to a printable string
5793 * here. Doing so breaks the keyword tests.
5794 */
5795 if (fr_value_box_list_concat_as_string(out, &sbuff, list,
5796 NULL, 0, NULL,
5798 fr_strerror_printf("Concatenation exceeded max_size (%zu)", max_size);
5799 error:
5800 switch (type) {
5801 case FR_TYPE_STRING:
5802 talloc_free(fr_sbuff_buff(&sbuff));
5803 break;
5804
5805 case FR_TYPE_OCTETS:
5806 talloc_free(fr_dbuff_buff(&dbuff));
5807 break;
5808
5809 default:
5810 break;
5811 }
5812 return -1;
5813 }
5814
5815 /*
5816 * Concat the rest of the children...
5817 */
5818 if (fr_value_box_list_concat_as_string(out, &sbuff, list,
5819 NULL, 0, NULL,
5820 proc_action, FR_VALUE_BOX_SAFE_FOR_ANY, flatten) < 0) {
5821 fr_value_box_list_insert_head(list, head_vb);
5822 goto error;
5823 }
5824 (void)fr_sbuff_trim_talloc(&sbuff, SIZE_MAX);
5826 if (fr_value_box_bstrndup(ctx, out, NULL, fr_sbuff_buff(&sbuff), fr_sbuff_used(&sbuff), out->tainted) < 0) goto error;
5827 break;
5828
5829 case FR_TYPE_OCTETS:
5830 if (fr_value_box_list_concat_as_octets(out, &dbuff, list,
5831 NULL, 0,
5832 FR_VALUE_BOX_LIST_REMOVE, flatten) < 0) goto error;
5833
5834 if (fr_value_box_list_concat_as_octets(out, &dbuff, list,
5835 NULL, 0,
5836 proc_action, flatten) < 0) {
5837 fr_value_box_list_insert_head(list, head_vb);
5838 goto error;
5839 }
5840 (void)fr_dbuff_trim_talloc(&dbuff, SIZE_MAX);
5842 if (fr_value_box_memdup(ctx, out, NULL, fr_dbuff_buff(&dbuff), fr_dbuff_used(&dbuff), out->tainted) < 0) goto error;
5843 break;
5844
5845 default:
5846 break;
5847 }
5848
5849 fr_value_box_list_insert_head(list, out);
5850
5851 /*
5852 * Merge all the boxes in the list into
5853 * a single contiguous buffer.
5854 *
5855 * This deals with an unrelated out and list
5856 * and also where list is the children of
5857 * out.
5858 */
5859 } else {
5860 switch (type) {
5861 case FR_TYPE_STRING:
5862 if (fr_value_box_list_concat_as_string(out, &sbuff, list,
5863 NULL, 0, NULL,
5864 proc_action, FR_VALUE_BOX_SAFE_FOR_ANY, flatten) < 0) goto error;
5865 (void)fr_sbuff_trim_talloc(&sbuff, SIZE_MAX);
5866
5867 entry = out->entry;
5868 if (fr_value_box_bstrndup(ctx, out, NULL, fr_sbuff_buff(&sbuff), fr_sbuff_used(&sbuff), out->tainted) < 0) goto error;
5869 out->entry = entry;
5870 break;
5871
5872 case FR_TYPE_OCTETS:
5873 if (fr_value_box_list_concat_as_octets(out, &dbuff, list,
5874 NULL, 0,
5875 proc_action, flatten) < 0) goto error;
5876 (void)fr_dbuff_trim_talloc(&dbuff, SIZE_MAX);
5877
5878 entry = out->entry;
5879 if (fr_value_box_memdup(ctx, out, NULL, fr_dbuff_buff(&dbuff), fr_dbuff_used(&dbuff), out->tainted) < 0) goto error;
5880 out->entry = entry;
5881 break;
5882
5883 default:
5884 break;
5885 }
5886 }
5887
5888 return 0;
5889}
5890
5891/** Escape a single value box in place
5892 *
5893 * @note Applies recursively to the children of group boxes.
5894 *
5895 * @param[in] vb to escape.
5896 * @param[in] escape escape definition to apply to the value box.
5897 * @param[in] uctx user context to pass to the escape function.
5898 * @return
5899 * - 0 on success.
5900 * - -1 on failure.
5901 */
5903{
5904 int ret;
5905
5906 switch (vb->type) {
5907 case FR_TYPE_GROUP:
5908 return fr_value_box_list_escape_in_place(&vb->vb_group, escape, uctx);
5909
5910 case FR_TYPE_NULL:
5911 case FR_TYPE_TLV:
5912 case FR_TYPE_STRUCT:
5913 case FR_TYPE_VSA:
5914 case FR_TYPE_VENDOR:
5915 case FR_TYPE_VALUE_BOX:
5916 case FR_TYPE_VOID:
5917 case FR_TYPE_MAX:
5918 fr_strerror_printf("Cannot escape data type '%s'", fr_type_to_str(vb->type));
5919 return -1;
5920
5921 default:
5922 break;
5923 }
5924
5925 if (!escape->always_escape && fr_value_box_is_safe_for(vb, escape->safe_for)) return 0;
5926
5927 ret = escape->func(vb, uctx);
5928 if (unlikely(ret < 0)) return ret;
5929
5930 vb->safe_for = escape->safe_for;
5931 vb->tainted = false;
5932
5933 return 0;
5934}
5935
5936/** Escape a list of value boxes in place
5937 *
5938 * @note Applies recursively to the children of group boxes.
5939 *
5940 * @note on error, the list may be left in an inconsistent/partially escaped state.
5941 *
5942 * @param[in] list to escape.
5943 * @param[in] escape escape definition to apply to the value box.
5944 * @param[in] uctx user context to pass to the escape function.
5945 * @return
5946 * - 0 on success.
5947 * - -1 on failure.
5948 */
5949int fr_value_box_list_escape_in_place(fr_value_box_list_t *list, fr_value_box_escape_t const *escape, void *uctx)
5950{
5951 int ret = 0;
5952
5953 fr_value_box_list_foreach(list, vb) {
5954 ret = fr_value_box_escape_in_place(vb, escape, uctx);
5955 if (unlikely(ret < 0)) return ret;
5956 }
5957
5958 return ret;
5959}
5960
5961/** Removes a single layer of nesting, moving all children into the parent list
5962 *
5963 * @param[in] ctx to reparent children in if steal is true.
5964 * @param[in] list to flatten.
5965 * @param[in] steal whether to change the talloc ctx of children.
5966 * @param[in] free whether to free any group boxes which have had
5967 * their children removed.
5968 */
5969void fr_value_box_flatten(TALLOC_CTX *ctx, fr_value_box_list_t *list, bool steal, bool free)
5970{
5971 fr_value_box_list_foreach_safe(list, child) {
5972 if (!fr_type_is_structural(child->type)) continue;
5973
5974 fr_value_box_list_foreach_safe(&child->vb_group, grandchild) {
5975 fr_value_box_list_remove(&child->vb_group, grandchild);
5976 if (steal) talloc_steal(ctx, grandchild);
5977 fr_value_box_list_insert_before(list, child, grandchild);
5978 }}
5979
5980 if (free) talloc_free(child);
5981 }}
5982}
5983
5984/** Concatenate the string representations of a list of value boxes together
5985 *
5986 * @param[in] ctx to allocate the buffer in.
5987 * @param[in] list of value boxes.
5988 * @param[in] delim to insert between value box values.
5989 * @param[in] e_rules to control escaping of the concatenated elements.
5990 * @return
5991 * - NULL on error.
5992 * - The concatenation of the string values of the value box list on success.
5993 */
5994char *fr_value_box_list_aprint(TALLOC_CTX *ctx, fr_value_box_list_t const *list, char const *delim,
5995 fr_sbuff_escape_rules_t const *e_rules)
5996{
5997 fr_value_box_t const *vb = fr_value_box_list_head(list);
5998 char *aggr, *td = NULL;
5999 TALLOC_CTX *pool = NULL;
6000
6001 if (!vb) return NULL;
6002
6003 fr_value_box_aprint(ctx, &aggr, vb, e_rules);
6004 if (!aggr) return NULL;
6005 if (!fr_value_box_list_next(list, vb)) return aggr;
6006
6007 /*
6008 * If we're aggregating more values,
6009 * allocate a temporary pool.
6010 */
6011 pool = talloc_pool(NULL, 255);
6012 if (delim) td = talloc_typed_strdup(pool, delim);
6013
6014 while ((vb = fr_value_box_list_next(list, vb))) {
6015 char *str, *new_aggr;
6016
6017 fr_value_box_aprint(pool, &str, vb, e_rules);
6018 if (!str) continue;
6019
6020 new_aggr = talloc_buffer_append_variadic_buffer(ctx, aggr, 2, td, str);
6021 if (unlikely(!new_aggr)) {
6022 talloc_free(aggr);
6023 talloc_free(pool);
6024 return NULL;
6025 }
6026 aggr = new_aggr;
6027 talloc_free(str);
6028 }
6029 talloc_free(pool);
6030
6031 return aggr;
6032}
6033
6034/** Concatenate the string representations of a list of value boxes together hiding "secret" values
6035 *
6036 * @param[in] ctx to allocate the buffer in.
6037 * @param[in] list of value boxes.
6038 * @param[in] delim to insert between value box values.
6039 * @param[in] e_rules to control escaping of the concatenated elements.
6040 * @return
6041 * - NULL on error.
6042 * - The concatenation of the string values of the value box list on success.
6043 */
6044char *fr_value_box_list_aprint_secure(TALLOC_CTX *ctx, fr_value_box_list_t const *list, char const *delim,
6045 fr_sbuff_escape_rules_t const *e_rules)
6046{
6047 fr_value_box_t const *vb = fr_value_box_list_head(list);
6048 char *aggr, *td = NULL;
6049 TALLOC_CTX *pool = NULL;
6050
6051 if (!vb) return NULL;
6052
6054 aggr = talloc_typed_strdup(ctx, "<<< secret >>>");
6055 } else {
6056 fr_value_box_aprint(ctx, &aggr, vb, e_rules);
6057 }
6058 if (!aggr) return NULL;
6059 if (!fr_value_box_list_next(list, vb)) return aggr;
6060
6061 /*
6062 * If we're aggregating more values,
6063 * allocate a temporary pool.
6064 */
6065 pool = talloc_pool(NULL, 255);
6066 if (delim) td = talloc_typed_strdup(pool, delim);
6067
6068 while ((vb = fr_value_box_list_next(list, vb))) {
6069 char *str, *new_aggr;
6070
6072 str = talloc_typed_strdup(pool, "<<< secret >>>");
6073 } else {
6074 fr_value_box_aprint(pool, &str, vb, e_rules);
6075 }
6076 if (!str) continue;
6077
6078 new_aggr = talloc_buffer_append_variadic_buffer(ctx, aggr, 2, td, str);
6079 if (unlikely(!new_aggr)) {
6080 talloc_free(aggr);
6081 talloc_free(pool);
6082 return NULL;
6083 }
6084 aggr = new_aggr;
6085 talloc_free(str);
6086 }
6087 talloc_free(pool);
6088
6089 return aggr;
6090}
6091
6092/** Hash the contents of a value box
6093 *
6094 */
6096{
6097 switch (vb->type) {
6098 case FR_TYPE_FIXED_SIZE:
6099 return fr_hash(fr_value_box_raw(vb, vb->type),
6100 fr_value_box_field_sizes[vb->type]);
6101
6102 case FR_TYPE_STRING:
6103 return fr_hash(vb->vb_strvalue, vb->vb_length);
6104
6105 case FR_TYPE_OCTETS:
6106 return fr_hash(vb->vb_octets, vb->vb_length);
6107
6108 default:
6109 break;
6110 }
6111
6112 return 0;
6113}
6114
6115/** Do a full copy of a list of value boxes
6116 *
6117 * @param[in] ctx to allocate boxes in.
6118 * @param[out] out Where to write the head of the new list.
6119 * @param[in] in boxes to copy.
6120 * @return
6121 * - A duplicate list of value boxes, allocated in the context of 'ctx'
6122 * - NULL on error, or empty input list.
6123 */
6124int fr_value_box_list_acopy(TALLOC_CTX *ctx, fr_value_box_list_t *out, fr_value_box_list_t const *in)
6125{
6126 fr_value_box_t const *in_p = NULL;
6127
6128 while ((in_p = fr_value_box_list_next(in, in_p))) {
6129 fr_value_box_t *n = NULL;
6130
6132 if (!n) {
6133 error:
6134 fr_value_box_list_talloc_free(out);
6135 return -1;
6136 }
6137
6138 if (fr_value_box_copy(n, n, in_p) < 0) goto error;
6139 fr_dlist_insert_tail(fr_value_box_list_dlist_head(out), n);
6140 }
6141
6142 return 0;
6143}
6144
6145/** Check to see if any list members (or their children) are tainted
6146 *
6147 * @param[in] head of list to check.
6148 * @return
6149 * - true if a list member is tainted.
6150 * - false if no list members are tainted.
6151 */
6152bool fr_value_box_list_tainted(fr_value_box_list_t const *head)
6153{
6154 fr_value_box_t *vb = NULL;
6155
6156 while ((vb = fr_value_box_list_next(head, vb))) {
6157 if (fr_type_is_group(vb->type) && fr_value_box_list_tainted(&vb->vb_group)) return true;
6158 if (vb->tainted) return true;
6159 }
6160
6161 return false;
6162}
6163
6164/** Taint every list member (and their children)
6165 *
6166 * @param[in] head of list.
6167 */
6168void fr_value_box_list_taint(fr_value_box_list_t *head)
6169{
6170 fr_value_box_t *vb = NULL;
6171
6172 while ((vb = fr_value_box_list_next(head, vb))) {
6173 if (fr_type_is_group(vb->type)) fr_value_box_list_taint(&vb->vb_group);
6175 vb->tainted = true;
6176 }
6177}
6178
6179/** Untaint every list member (and their children)
6180 *
6181 * @param[in] head of list.
6182 */
6183void fr_value_box_list_untaint(fr_value_box_list_t *head)
6184{
6185 fr_value_box_t *vb = NULL;
6186
6187 while ((vb = fr_value_box_list_next(head, vb))) {
6188 if (fr_type_is_group(vb->type)) fr_value_box_list_untaint(&vb->vb_group);
6189 vb->tainted = false;
6190 }
6191}
6192
6193/** Validation function to check that a fr_value_box_t is correctly initialised
6194 *
6195 */
6196void fr_value_box_verify(char const *file, int line, fr_value_box_t const *vb)
6197{
6198DIAG_OFF(nonnull-compare)
6199 /*
6200 * nonnull only does something if we're building
6201 * with ubsan... We still want to assert event
6202 * if we're building without sanitizers.
6203 */
6204 fr_fatal_assert_msg(vb, "CONSISTENCY CHECK FAILED %s[%i]: fr_value_box_t pointer was NULL", file, line);
6205DIAG_ON(nonnull-compare)
6206
6207 if (vb->talloced) vb = talloc_get_type_abort_const(vb, fr_value_box_t);
6208
6209#ifndef NDEBUG
6210 fr_fatal_assert_msg(vb->magic == FR_VALUE_BOX_MAGIC, "CONSISTENCY CHECK FAILED %s[%i]: fr_value_box_t magic "
6211 "incorrect, expected %" PRIx64 ", got %" PRIx64, file, line, FR_VALUE_BOX_MAGIC, vb->magic);
6212#endif
6213 switch (vb->type) {
6214 case FR_TYPE_STRING:
6215 fr_fatal_assert_msg(vb->vb_strvalue, "CONSISTENCY CHECK FAILED %s[%d]: fr_value_box_t strvalue field "
6216 "was NULL", file, line);
6217 fr_fatal_assert_msg(vb->vb_strvalue[vb->vb_length] == '\0',
6218 "CONSISTENCY CHECK FAILED %s[%i]: fr_value_box_t strvalue field "
6219 "not null terminated", file, line);
6220 if (vb->talloced) {
6221 size_t len = talloc_array_length(vb->vb_strvalue);
6222
6223 /* We always \0 terminate to be safe, even though most things should use the len field */
6224 if (len <= vb->vb_length) {
6225 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: Expected fr_value_box_t->vb_strvalue talloc buffer "
6226 "len >= %zu, got %zu",
6227 file, line, vb->vb_length + 1, len);
6228 }
6229 }
6230 break;
6231
6232 case FR_TYPE_OCTETS:
6233 fr_fatal_assert_msg(vb->vb_octets, "CONSISTENCY CHECK FAILED %s[%d]: fr_value_box_t octets field "
6234 "was NULL", file, line);
6235 break;
6236
6237 case FR_TYPE_VOID:
6238 fr_fatal_assert_msg(vb->vb_void, "CONSISTENCY CHECK FAILED %s[%d]: fr_value_box_t ptr field "
6239 "was NULL", file, line);
6240 break;
6241
6242 case FR_TYPE_GROUP:
6243 fr_value_box_list_verify(file, line, &vb->vb_group);
6244 break;
6245
6246 default:
6247 break;
6248 }
6249}
6250
6251void fr_value_box_list_verify(char const *file, int line, fr_value_box_list_t const *list)
6252{
6254}
6255
6256/** Mark a value-box as "safe", of a particular type.
6257 *
6258 */
6260{
6261 /*
6262 * Don't over-ride value-boxes which are already safe, unless we want to mark them as being
6263 * completely unsafe.
6264 */
6265 if ((vb->safe_for == FR_VALUE_BOX_SAFE_FOR_ANY) &&
6266 (safe_for != FR_VALUE_BOX_SAFE_FOR_NONE)) {
6267 fr_assert(!vb->tainted);
6268 return;
6269 }
6270
6271 vb->safe_for = safe_for;
6272}
6273
6274/** Mark a value-box as "unsafe"
6275 *
6276 * This always succeeds, and there are no side effects.
6277 */
6279{
6280 vb->safe_for = FR_VALUE_BOX_SAFE_FOR_NONE;
6281}
6282
6283/** Set the escaped flag for all value boxes in a list
6284 *
6285 * @note Only operates on a single level.
6286 *
6287 * @param[in] list to operate on.
6288 * @param[in] safe_for value to set.
6289 */
6290void fr_value_box_list_mark_safe_for(fr_value_box_list_t *list, fr_value_box_safe_for_t safe_for)
6291{
6292 fr_value_box_list_foreach(list, vb) {
6293 /*
6294 * Don't over-ride value-boxes which are already safe.
6295 */
6296 if (vb->safe_for == FR_VALUE_BOX_SAFE_FOR_ANY) {
6297 fr_assert(!vb->tainted);
6298
6299 } else {
6300 vb->safe_for = safe_for;
6301 }
6302 }
6303}
6304
6305/** Copy the safety values from one box to another.
6306 *
6307 */
6309{
6310 if (out == in) return;
6311
6312 out->safe_for = in->safe_for;
6313 out->tainted = in->tainted;
6314 out->secret = in->secret;
6315}
6316
6317/** Copy the safety values from one box to another.
6318 *
6319 * But note that we have changed the output format, so we reset the "safe_for" value to NONE.
6320 */
6322{
6323 out->safe_for = FR_VALUE_BOX_SAFE_FOR_NONE;
6324 out->tainted = in->tainted;
6325 out->secret = in->secret;
6326}
6327
6328/** Merge safety results.
6329 */
6331{
6332 if (out == in) return;
6333
6334 /*
6335 * If we're already at no safety, then we don't need to do anything.
6336 *
6337 * Otherwise we update the safety only if we need to change it.
6338 */
6339 if ((out->safe_for != FR_VALUE_BOX_SAFE_FOR_NONE) &&
6340 (out->safe_for != in->safe_for)) {
6341 /*
6342 * If the output is anything, then the input is more restrictive, so we switch to that.
6343 *
6344 * Otherwise the values are different. Either it's X/Y, or NONE/X, or X/NONE. In which
6345 * case the answer is always NONE.
6346 */
6347 if (out->safe_for == FR_VALUE_BOX_SAFE_FOR_ANY) {
6348 out->safe_for = in->safe_for;
6349
6350 } else {
6351 out->safe_for = FR_VALUE_BOX_SAFE_FOR_NONE;
6352 }
6353 }
6354
6355 out->tainted |= in->tainted;
6356 out->secret |= in->secret;
6357}
6358
6359
6360/** Check truthiness of values.
6361 *
6362 * The casting rules for expressions / conditions are slightly
6363 * different than fr_value_box_cast(). Largely because that
6364 * function is used to parse configuration files, and parses "yes
6365 * / no" and "true / false" strings, even if there's no
6366 * fr_dict_attr_t passed to it.
6367 */
6369{
6370 fr_value_box_t box;
6371
6372 switch (in->type) {
6373 case FR_TYPE_NULL:
6375 return false;
6376
6377 case FR_TYPE_GROUP:
6378 return (fr_value_box_list_num_elements(&in->vb_group) > 0);
6379
6380 case FR_TYPE_BOOL:
6381 return in->vb_bool;
6382
6383 case FR_TYPE_STRING:
6384 case FR_TYPE_OCTETS:
6385 return (in->vb_length > 0);
6386
6387 case FR_TYPE_IPV4_ADDR:
6388 case FR_TYPE_IPV6_ADDR:
6389 return !fr_ipaddr_is_inaddr_any(&in->vb_ip);
6390
6393 return !((in->vb_ip.prefix == 0) && fr_ipaddr_is_inaddr_any(&in->vb_ip));
6394
6395 default:
6397 (void) fr_value_box_cast(NULL, &box, FR_TYPE_BOOL, NULL, in);
6398 return box.vb_bool;
6399 }
6400}
6401
6402#define INFO_INDENT(_fmt, ...) FR_FAULT_LOG("%*s"_fmt, depth * 2, " ", ## __VA_ARGS__)
6403
6404static void _fr_value_box_debug(fr_value_box_t const *vb, int depth, int idx);
6405static void _fr_value_box_list_debug(fr_value_box_list_t const *head, int depth)
6406{
6407 int i = 0;
6408
6409 INFO_INDENT("{");
6411 INFO_INDENT("}");
6412}
6413
6414/** Print a list of value boxes as info messages
6415 *
6416 * @note Call directly from the debugger
6417 */
6418void fr_value_box_list_debug(fr_value_box_list_t const *head)
6419{
6421}
6422
6423static void _fr_value_box_debug(fr_value_box_t const *vb, int depth, int idx)
6424{
6425 char *value;
6426
6427 if (fr_type_is_structural(vb->type)) {
6428 _fr_value_box_list_debug(&vb->vb_group, depth + 1);
6429 return;
6430 }
6431
6432 fr_value_box_aprint(NULL, &value, vb, NULL);
6433 if (idx >= 0) {
6434 INFO_INDENT("[%d] (%s) %s", idx, fr_type_to_str(vb->type), value);
6435 INFO_INDENT(" %s %s %lx",
6436 vb->secret ? "s" : "-",
6437 vb->tainted ? "t" : "-",
6438 vb->safe_for);
6439 } else {
6440 INFO_INDENT("(%s) %s", fr_type_to_str(vb->type), value);
6441 INFO_INDENT(" %s %s %lx",
6442 vb->secret ? "s" : "-",
6443 vb->tainted ? "t" : "-",
6444 vb->safe_for);
6445 }
6447}
6448
6449/** Print the value of a box as info messages
6450 *
6451 * @note Call directly from the debugger
6452 */
6454{
6455 _fr_value_box_debug(vb, 0, -1);
6456}
static int const char char buffer[256]
Definition acutest.h:576
int const char * file
Definition acutest.h:702
va_end(args)
int n
Definition acutest.h:577
static int const char * fmt
Definition acutest.h:573
int const char int line
Definition acutest.h:702
va_start(args, fmt)
#define fr_base16_encode(_out, _in)
Definition base16.h:57
#define fr_base16_decode(_err, _out, _in, _no_trailing)
Definition base16.h:95
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define DIAG_ON(_x)
Definition build.h:460
#define SIZEOF_MEMBER(_t, _m)
Definition build.h:338
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:112
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define DIAG_OFF(_x)
Definition build.h:459
static fr_atomic_queue_t * aq
static size_t min(size_t x, size_t y)
Definition dbuff.c:66
int fr_dbuff_trim_talloc(fr_dbuff_t *dbuff, size_t len)
Trim a talloced dbuff to the minimum length required to represent the contained string.
Definition dbuff.c:297
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h:767
#define FR_DBUFF_OUT_UINT64V_RETURN(_num, _dbuff_or_marker, _len)
Read bytes from a dbuff or marker and interpret them as a network order unsigned integer.
Definition dbuff.h:1858
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
Definition dbuff.h:1004
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
Definition dbuff.h:354
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:898
#define FR_DBUFF_OUT_INT64V_RETURN(_num, _dbuff_or_marker, _len)
Read bytes from a dbuff or marker and interpret them as a network order unsigned integer.
Definition dbuff.h:1898
#define fr_dbuff_buff(_dbuff_or_marker)
Return the underlying buffer in a dbuff or one of marker.
Definition dbuff.h:882
#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen)
Copy exactly _outlen bytes from the dbuff.
Definition dbuff.h:1732
#define FR_DBUFF_MEMSET_RETURN(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c returning if there is insufficient space.
Definition dbuff.h:1508
#define FR_DBUFF_OUT_MEMCPY_RETURN(_out, _dbuff_or_marker, _outlen)
Copy outlen bytes from the dbuff returning if there's insufficient data in the dbuff.
Definition dbuff.h:1752
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1382
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
Definition dbuff.h:1350
#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff returning if there is insufficient space.
Definition dbuff.h:1585
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:222
#define FR_DBUFF_OUT_RETURN(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type returning if there is insufficient data.
Definition dbuff.h:1818
static fr_dbuff_t * fr_dbuff_init_talloc(TALLOC_CTX *ctx, fr_dbuff_t *dbuff, fr_dbuff_uctx_talloc_t *tctx, size_t init, size_t max)
Initialise a special dbuff which automatically extends as additional data is written.
Definition dbuff.h:411
#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1472
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:514
#define fr_fatal_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:191
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition debug.h:216
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:156
#define fr_fatal_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:184
static fr_slen_t err
Definition dict.h:831
bool const fr_dict_enum_allowed_chars[UINT8_MAX+1]
Characters that are allowed in dictionary enumeration value names.
Definition dict_util.c:72
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:235
char const * fr_dict_enum_name_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the name of an enum value in a fr_dict_attr_t.
Definition dict_util.c:3389
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition dict_util.c:3402
#define da_is_length_field(_da)
Definition dict.h:159
@ FLAG_LENGTH_UINT8
string / octets type is prefixed by uint8 of length
Definition dict.h:153
@ FLAG_LENGTH_UINT16
string / octets type is prefixed by uint16 of length
Definition dict.h:154
static fr_slen_t in
Definition dict.h:831
Value of an enumerated attribute.
Definition dict.h:231
Test enumeration values.
Definition dict_test.h:92
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition dlist.h:378
uint32_t fr_hash(void const *data, size_t size)
Definition hash.c:812
free(array)
int fr_ipaddr_is_prefix(fr_ipaddr_t const *ipaddr)
Determine if an address is a prefix.
Definition inet.c:125
char * fr_inet_ntop_prefix(char out[static FR_IPADDR_PREFIX_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
Print a fr_ipaddr_t as a CIDR style network prefix.
Definition inet.c:1073
int fr_inet_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask)
Parse an IPv6 address or IPv6 prefix in presentation format (and others)
Definition inet.c:629
bool fr_hostname_lookups
hostname -> IP lookups?
Definition inet.c:52
int fr_inet_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser.
Definition inet.c:778
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
Definition inet.c:62
char * fr_inet_ntop(char out[static FR_IPADDR_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
Print the address portion of a fr_ipaddr_t.
Definition inet.c:1018
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1346
char * fr_inet_ifid_ntop(char *out, size_t outlen, uint8_t const *ifid)
Print an interface-id in standard colon notation.
Definition inet.c:1099
uint8_t * fr_inet_ifid_pton(uint8_t out[static 8], char const *ifid_str)
Convert interface-id in colon notation to 8 byte binary form.
Definition inet.c:1113
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition inet.h:69
int af
Address family.
Definition inet.h:64
uint8_t addr[6]
Ethernet address.
Definition inet.h:46
Struct to represent an ethernet address.
Definition inet.h:45
IPv4/6 prefix.
talloc_free(reap)
int fr_debug_lvl
Definition log.c:43
#define fr_multiply(_out, _a, _b)
Multiplies two integers together.
Definition math.h:118
static const uint8_t * zero
Definition md4.c:358
unsigned short uint16_t
size_t fr_sbuff_out_unescape_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
fr_type_t
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_FLOAT32
Single precision floating point.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_MAX
Number of defined data types.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_VALUE_BOX
A boxed value.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_VOID
User data.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_IFID
Interface ID.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
@ FR_TYPE_FLOAT64
Double precision floating point.
unsigned int uint32_t
int fr_inet_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask_bits)
long int ssize_t
unsigned char uint8_t
ssize_t fr_slen_t
unsigned long int size_t
#define UINT8_MAX
fr_sbuff_parse_error_t
@ FR_SBUFF_PARSE_ERROR_NOT_FOUND
String does not contain a token matching the output type.
@ FR_SBUFF_PARSE_OK
No error.
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
int fr_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
Do a comparison of two authentication digests by comparing the FULL data.
Definition misc.c:472
void * memset_explicit(void *ptr, int ch, size_t len)
Definition missing.c:620
static uint64_t fr_nbo_to_uint64(uint8_t const data[static sizeof(uint64_t)])
Read an unsigned 64bit integer from wire format (big endian)
Definition nbo.h:177
static void fr_nbo_from_uint64(uint8_t out[static sizeof(uint64_t)], uint64_t num)
Write out an unsigned 64bit integer in wire format (big endian)
Definition nbo.h:72
char * fr_vasprintf(TALLOC_CTX *ctx, char const *fmt, va_list ap)
Definition print.c:851
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:80
static uint32_t mask
Definition rbmonkey.c:39
static char const * name
int fr_sbuff_trim_talloc(fr_sbuff_t *sbuff, size_t len)
Trim a talloced sbuff to the minimum length required to represent the contained string.
Definition sbuff.c:419
size_t fr_sbuff_adv_past_allowed(fr_sbuff_t *sbuff, size_t len, bool const allowed[static UINT8_MAX+1], fr_sbuff_term_t const *tt)
Wind position past characters in the allowed set.
Definition sbuff.c:1777
ssize_t fr_sbuff_in_escape(fr_sbuff_t *sbuff, char const *in, size_t inlen, fr_sbuff_escape_rules_t const *e_rules)
Print an escaped string to an sbuff.
Definition sbuff.c:1620
bool const sbuff_char_class_hex[UINT8_MAX+1]
Definition sbuff.c:94
bool const sbuff_char_class_uint[UINT8_MAX+1]
Definition sbuff.c:60
bool const sbuff_char_class_hostname[UINT8_MAX+1]
Definition sbuff.c:82
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
Definition sbuff.c:2152
ssize_t fr_sbuff_in_bstrncpy(fr_sbuff_t *sbuff, char const *str, size_t len)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1480
size_t fr_sbuff_adv_until(fr_sbuff_t *sbuff, size_t len, fr_sbuff_term_t const *tt, char escape_chr)
Wind position until we hit a character in the terminal set.
Definition sbuff.c:1852
size_t fr_sbuff_out_bstrncpy(fr_sbuff_t *out, fr_sbuff_t *in, size_t len)
Copy as many bytes as possible from a sbuff to a sbuff.
Definition sbuff.c:723
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
Definition sbuff.c:2088
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_adv_past_str_literal(_sbuff, _needle)
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define fr_sbuff_set(_dst, _src)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_adv_past_strcase_literal(_sbuff, _needle)
#define fr_sbuff_current(_sbuff_or_marker)
char chr
Character at the start of an escape sequence.
Definition sbuff.h:204
#define FR_SBUFF_IN_ESCAPE_BUFFER_RETURN(...)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition sbuff.h:192
char const * name
Name for rule set to aid we debugging.
Definition sbuff.h:202
#define FR_SBUFF_IN_STRCPY_LITERAL_RETURN(_sbuff, _str)
#define fr_sbuff_extend(_sbuff_or_marker)
#define fr_sbuff_buff(_sbuff_or_marker)
#define FR_SBUFF_RETURN(_func, _sbuff,...)
#define FR_SBUFF_ERROR_RETURN(_sbuff_or_marker)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define FR_SBUFF_IN_SPRINTF_RETURN(...)
#define SBUFF_CHAR_UNPRINTABLES_EXTENDED
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_out(_err, _out, _in)
#define FR_SBUFF_IN_ESCAPE_RETURN(...)
#define fr_sbuff_remaining(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define SBUFF_CHAR_UNPRINTABLES_LOW
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_TERM(_str)
Initialise a terminal structure with a single string.
Definition sbuff.h:180
#define FR_SBUFF_IN_STRCPY_RETURN(...)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Talloc sbuff extension structure.
Definition sbuff.h:139
Set of parsing rules for *unescape_until functions.
fr_slen_t fr_size_from_str(size_t *out, fr_sbuff_t *in)
Parse a size string with optional unit.
Definition size.c:40
fr_slen_t fr_size_to_str(fr_sbuff_t *out, size_t in)
Print a size string with unit.
Definition size.c:155
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
PRIVATE void float64()
fr_aka_sim_id_type_t type
char * talloc_buffer_append_variadic_buffer(TALLOC_CTX *ctx, char *to, int argc,...)
Concatenate to + ...
Definition talloc.c:696
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:564
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition talloc.c:445
#define talloc_get_type_abort_const
Definition talloc.h:282
fr_slen_t fr_time_delta_from_substr(fr_time_delta_t *out, fr_sbuff_t *in, fr_time_res_t hint, bool no_trailing, fr_sbuff_term_t const *tt)
Create fr_time_delta_t from a string.
Definition time.c:214
int fr_unix_time_from_str(fr_unix_time_t *date, char const *date_str, fr_time_res_t hint)
Convert string in various formats to a fr_unix_time_t.
Definition time.c:838
int64_t fr_time_scale(int64_t t, fr_time_res_t hint)
Scale an input time to NSEC, clamping it at max / min.
Definition time.c:727
fr_slen_t fr_time_delta_to_str(fr_sbuff_t *out, fr_time_delta_t delta, fr_time_res_t res, bool is_unsigned)
Print fr_time_delta_t to a string with an appropriate suffix.
Definition time.c:479
fr_slen_t fr_unix_time_to_str(fr_sbuff_t *out, fr_unix_time_t time, fr_time_res_t res, bool utc)
Convert unix time to string.
Definition time.c:1166
int64_t const fr_time_multiplier_by_res[]
Definition time.c:32
static fr_time_delta_t fr_time_delta_from_integer(bool *overflow, int64_t integer, fr_time_res_t res)
Definition time.h:548
static int64_t fr_time_delta_to_integer(fr_time_delta_t delta, fr_time_res_t res)
Definition time.h:627
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
static int8_t fr_time_delta_cmp(fr_time_delta_t a, fr_time_delta_t b)
Compare two fr_time_delta_t values.
Definition time.h:930
#define fr_time_delta_isneg(_a)
Definition time.h:291
#define fr_time_delta_wrap(_time)
Definition time.h:152
#define fr_unix_time_wrap(_time)
Definition time.h:160
fr_time_res_t
The base resolution for print parse operations.
Definition time.h:48
@ FR_TIME_RES_SEC
Definition time.h:50
static fr_unix_time_t fr_unix_time_from_integer(bool *overflow, int64_t integer, fr_time_res_t res)
Definition time.h:411
#define NSEC
Definition time.h:379
static int8_t fr_unix_time_cmp(fr_unix_time_t a, fr_unix_time_t b)
Compare two fr_unix_time_t values.
Definition time.h:944
static uint64_t fr_unix_time_unwrap(fr_unix_time_t time)
Definition time.h:161
static int64_t fr_unix_time_to_integer(fr_unix_time_t delta, fr_time_res_t res)
Definition time.h:486
const char fr_token_quote[T_TOKEN_LAST]
Convert tokens back to a quoting character.
Definition token.c:156
enum fr_token fr_token_t
@ T_SINGLE_QUOTED_STRING
Definition token.h:122
@ T_BARE_WORD
Definition token.h:120
@ T_BACK_QUOTED_STRING
Definition token.h:123
@ T_OP_NE
Definition token.h:97
@ T_OP_REG_EQ
Definition token.h:102
@ T_DOUBLE_QUOTED_STRING
Definition token.h:121
@ T_OP_CMP_EQ
Definition token.h:106
@ T_OP_LE
Definition token.h:100
@ T_OP_GE
Definition token.h:98
@ T_OP_GT
Definition token.h:99
@ T_SOLIDUS_QUOTED_STRING
Definition token.h:124
@ T_OP_LT
Definition token.h:101
@ T_OP_REG_NE
Definition token.h:103
#define T_TOKEN_LAST
Definition token.h:129
static fr_slen_t head
Definition xlat.h:418
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:577
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define FR_TYPE_VARIABLE_SIZE
Definition types.h:291
#define FR_TYPE_QUOTED
Definition types.h:292
#define FR_TYPE_STRUCTURAL_EXCEPT_GROUP
Definition types.h:295
#define fr_type_is_non_leaf(_x)
Definition types.h:373
#define fr_type_is_group(_x)
Definition types.h:355
#define fr_type_is_variable_size(_x)
Definition types.h:367
#define fr_type_is_structural(_x)
Definition types.h:371
#define FR_TYPE_NON_LEAF
Definition types.h:298
#define fr_type_is_fixed_size(_x)
Definition types.h:366
#define FR_TYPE_STRUCTURAL
Definition types.h:296
#define fr_type_is_ip(_x)
Definition types.h:364
#define FR_TYPE_INTEGER_EXCEPT_BOOL
Definition types.h:283
#define FR_TYPE_IP
Definition types.h:288
#define FR_TYPE_INTEGER
Definition types.h:284
#define fr_type_is_leaf(_x)
Definition types.h:372
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
#define FR_TYPE_NUMERIC
Definition types.h:286
#define FR_TYPE_FIXED_SIZE
Definition types.h:290
int fr_value_box_bstrndup_dbuff(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Definition value.c:4202
void fr_value_box_list_verify(char const *file, int line, fr_value_box_list_t const *list)
Definition value.c:6251
static void _fr_value_box_list_debug(fr_value_box_list_t const *head, int depth)
Definition value.c:6405
static void _fr_value_box_debug(fr_value_box_t const *vb, int depth, int idx)
Definition value.c:6423
void fr_value_box_memdup_buffer_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, bool tainted)
Assign a talloced buffer to a box, but don't copy it.
Definition value.c:4517
size_t const fr_value_box_field_sizes[]
How many bytes wide each of the value data fields are.
Definition value.c:149
fr_sbuff_escape_rules_t fr_value_escape_double
Definition value.c:350
int fr_value_box_hton(fr_value_box_t *dst, fr_value_box_t const *src)
Performs byte order reversal for types that need it.
Definition value.c:1231
size_t fr_value_box_network_length(fr_value_box_t const *value)
Get the size of the value held by the fr_value_box_t.
Definition value.c:1325
int fr_value_box_vasprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted, char const *fmt, va_list ap)
Print a formatted string using our internal printf wrapper and assign it to a value box.
Definition value.c:4013
void fr_value_box_debug(fr_value_box_t const *vb)
Print the value of a box as info messages.
Definition value.c:6453
#define INFO_INDENT(_fmt,...)
Definition value.c:6402
void fr_value_box_mark_unsafe(fr_value_box_t *vb)
Mark a value-box as "unsafe".
Definition value.c:6278
ssize_t fr_value_box_list_concat_as_string(fr_value_box_t *safety, fr_sbuff_t *sbuff, fr_value_box_list_t *list, char const *sep, size_t sep_len, fr_sbuff_escape_rules_t const *e_rules, fr_value_box_list_action_t proc_action, fr_value_box_safe_for_t safe_for, bool flatten)
Concatenate a list of value boxes together.
Definition value.c:5514
fr_sbuff_escape_rules_t fr_value_escape_single
Definition value.c:388
int fr_value_box_strtrim(TALLOC_CTX *ctx, fr_value_box_t *vb)
Trim the length of the string buffer to match the length of the C string.
Definition value.c:3983
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
Definition value.c:6095
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
Definition value.c:5283
fr_sbuff_parse_rules_t const value_parse_rules_single_3quoted
Definition value.c:580
static fr_slen_t fr_value_box_from_numeric_substr(fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules, bool tainted)
Convert integer encoded as string to a fr_value_box_t type.
Definition value.c:4586
static int fr_value_box_cast_to_strvalue(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert any supported type to a string.
Definition value.c:2209
fr_sbuff_parse_rules_t const value_parse_rules_double_unquoted
Definition value.c:484
char * fr_value_box_list_aprint_secure(TALLOC_CTX *ctx, fr_value_box_list_t const *list, char const *delim, fr_sbuff_escape_rules_t const *e_rules)
Concatenate the string representations of a list of value boxes together hiding "secret" values.
Definition value.c:6044
fr_sbuff_parse_rules_t const value_parse_rules_solidus_quoted
Definition value.c:559
ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Decode a fr_value_box_t from serialized binary data.
Definition value.c:1754
int fr_value_box_mem_alloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv, size_t len, bool tainted)
Pre-allocate an octets buffer for filling by the caller.
Definition value.c:4322
int fr_value_box_memdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, bool tainted)
Copy a talloced buffer to a fr_value_box_t.
Definition value.c:4477
#define network_min_size(_x)
Sanity checks.
Definition value.c:107
int fr_value_box_bstrdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated talloced buffer to a fr_value_box_t.
Definition value.c:4238
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
Definition value.c:3370
int fr_value_box_asprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted, char const *fmt,...)
Print a formatted string using our internal printf wrapper and assign it to a value box.
Definition value.c:4044
fr_sbuff_parse_rules_t const * value_parse_rules_unquoted_char[UINT8_MAX]
Definition value.c:516
fr_sbuff_parse_rules_t const * value_parse_rules_quoted[T_TOKEN_LAST]
Parse rules for quoted strings.
Definition value.c:606
char * fr_value_box_list_aprint(TALLOC_CTX *ctx, fr_value_box_list_t const *list, char const *delim, fr_sbuff_escape_rules_t const *e_rules)
Concatenate the string representations of a list of value boxes together.
Definition value.c:5994
int fr_value_box_mem_realloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, size_t len)
Change the length of a buffer already allocated to a value box.
Definition value.c:4355
static size_t const fr_value_box_network_sizes[FR_TYPE_MAX+1][2]
Definition value.c:109
static int fr_value_box_cast_to_float(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert any value to a floating point value.
Definition value.c:3246
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:676
#define SIGN_BIT_HIGH(_int, _len)
size_t const fr_value_box_offsets[]
Where the value starts in the fr_value_box_t.
Definition value.c:189
fr_sbuff_parse_rules_t const * value_parse_rules_quoted_char[UINT8_MAX]
Definition value.c:614
#define CAST_IP_FIX_COMBO
Definition value.c:2351
void fr_value_box_list_untaint(fr_value_box_list_t *head)
Untaint every list member (and their children)
Definition value.c:6183
fr_sbuff_parse_rules_t const value_parse_rules_bareword_unquoted
Default formatting rules.
Definition value.c:480
static int fr_value_box_cast_to_ipv4addr(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert any supported type to an IPv4 address.
Definition value.c:2383
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition value.c:3759
fr_sbuff_parse_rules_t const value_parse_rules_single_unquoted
Definition value.c:488
int fr_value_box_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b)
Compare two attributes using an operator.
Definition value.c:929
int fr_value_box_list_escape_in_place(fr_value_box_list_t *list, fr_value_box_escape_t const *escape, void *uctx)
Escape a list of value boxes in place.
Definition value.c:5949
fr_sbuff_unescape_rules_t fr_value_unescape_solidus
Definition value.c:296
bool fr_value_box_is_truthy(fr_value_box_t const *in)
Check truthiness of values.
Definition value.c:6368
int fr_value_box_cast_in_place(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
Convert one type of fr_value_box_t to another in place.
Definition value.c:3591
fr_sbuff_parse_rules_t const value_parse_rules_single_quoted
Definition value.c:553
static uint8_t const v4_v6_map[]
v4 to v6 mapping prefix
Definition value.c:2195
fr_sbuff_unescape_rules_t * fr_value_unescape_by_char[UINT8_MAX+1]
Definition value.c:343
void fr_value_box_list_debug(fr_value_box_list_t const *head)
Print a list of value boxes as info messages.
Definition value.c:6418
void fr_value_box_memdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Assign a buffer to a box, but don't copy it.
Definition value.c:4499
fr_sbuff_escape_rules_t fr_value_escape_solidus
Definition value.c:398
void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
Perform a shallow copy of a value_box.
Definition value.c:3864
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules)
Definition value.c:5246
ssize_t fr_value_box_list_concat_as_octets(fr_value_box_t *safety, fr_dbuff_t *dbuff, fr_value_box_list_t *list, uint8_t const *sep, size_t sep_len, fr_value_box_list_action_t proc_action, bool flatten)
Concatenate a list of value boxes together.
Definition value.c:5634
static int fr_value_box_cast_to_octets(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert any supported type to octets.
Definition value.c:2260
void fr_value_box_increment(fr_value_box_t *vb)
Increment a boxed value.
Definition value.c:4533
fr_sbuff_escape_rules_t * fr_value_escape_by_quote[T_TOKEN_LAST]
Definition value.c:441
void _fr_value_box_mark_safe_for(fr_value_box_t *vb, fr_value_box_safe_for_t safe_for)
Mark a value-box as "safe", of a particular type.
Definition value.c:6259
size_t fr_value_str_unescape(fr_sbuff_t *out, fr_sbuff_t *in, size_t inlen, char quote)
Convert a string value with escape sequences into its binary form.
Definition value.c:1128
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:3700
void fr_value_box_verify(char const *file, int line, fr_value_box_t const *vb)
Validation function to check that a fr_value_box_t is correctly initialised.
Definition value.c:6196
fr_sbuff_parse_rules_t const * value_parse_rules_3quoted[T_TOKEN_LAST]
Definition value.c:622
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
Definition value.c:3957
#define network_max_size(_x)
Definition value.c:108
#define COMPARE(_type)
void fr_value_box_strdup_shallow_replace(fr_value_box_t *vb, char const *src, ssize_t len)
Free the existing buffer (if talloced) associated with the valuebox, and replace it with a new one.
Definition value.c:4082
ssize_t fr_value_box_print_quoted(fr_sbuff_t *out, fr_value_box_t const *data, fr_token_t quote)
Print one boxed value to a string with quotes (where needed)
Definition value.c:5471
fr_sbuff_parse_rules_t const value_parse_rules_double_3quoted
Definition value.c:574
static int fr_value_box_cast_to_integer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert any value to a signed or unsigned integer.
Definition value.c:3144
fr_sbuff_escape_rules_t fr_value_escape_unprintables
Definition value.c:455
static int fr_value_box_cast_to_ipv6prefix(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert any supported type to an IPv6 address.
Definition value.c:2735
void fr_value_box_safety_copy_changed(fr_value_box_t *out, fr_value_box_t const *in)
Copy the safety values from one box to another.
Definition value.c:6321
fr_sbuff_escape_rules_t fr_value_escape_backtick
Definition value.c:419
int fr_value_box_ipaddr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, fr_ipaddr_t const *ipaddr, bool tainted)
Assign a fr_value_box_t value from an fr_ipaddr_t.
Definition value.c:3649
void fr_value_box_list_taint(fr_value_box_list_t *head)
Taint every list member (and their children)
Definition value.c:6168
static int fr_value_box_cidr_cmp_op(fr_token_t op, int bytes, uint8_t a_net, uint8_t const *a, uint8_t b_net, uint8_t const *b)
Definition value.c:807
static void fr_value_box_copy_meta(fr_value_box_t *dst, fr_value_box_t const *src)
Copy flags and type data from one value box to another.
Definition value.c:638
void fr_value_box_list_mark_safe_for(fr_value_box_list_t *list, fr_value_box_safe_for_t safe_for)
Set the escaped flag for all value boxes in a list.
Definition value.c:6290
fr_sbuff_escape_rules_t * fr_value_escape_by_char[UINT8_MAX+1]
Definition value.c:448
static int fr_value_box_fixed_size_from_octets(fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert octets to a fixed size value box value.
Definition value.c:2147
static int fr_value_box_cast_to_bool(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert any supported type to a bool.
Definition value.c:2897
fr_sbuff_unescape_rules_t fr_value_unescape_backtick
Definition value.c:317
int fr_value_unbox_ipaddr(fr_ipaddr_t *dst, fr_value_box_t *src)
Unbox an IP address performing a type check.
Definition value.c:3681
fr_sbuff_parse_rules_t const value_parse_rules_bareword_quoted
Definition value.c:524
void fr_value_box_safety_merge(fr_value_box_t *out, fr_value_box_t const *in)
Merge safety results.
Definition value.c:6330
fr_sbuff_parse_rules_t const value_parse_rules_backtick_3quoted
Definition value.c:592
static uint64_t const fr_value_box_integer_max[]
Definition value.c:226
void fr_value_box_strdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a buffer containing a nul terminated string to a box, but don't copy it.
Definition value.c:4066
fr_sbuff_parse_rules_t const value_parse_rules_solidus_unquoted
Definition value.c:492
#define RETURN(_type)
fr_sbuff_parse_rules_t const value_parse_rules_backtick_quoted
Definition value.c:565
fr_sbuff_parse_rules_t const * value_parse_rules_unquoted[T_TOKEN_LAST]
Parse rules for non-quoted strings.
Definition value.c:508
static int fr_value_box_cast_to_ipv4prefix(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert any supported type to an IPv6 address.
Definition value.c:2500
static int fr_value_box_cast_to_ethernet(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert any supported type to an ethernet address.
Definition value.c:2836
fr_sbuff_unescape_rules_t fr_value_unescape_single
Definition value.c:285
void fr_value_box_safety_copy(fr_value_box_t *out, fr_value_box_t const *in)
Copy the safety values from one box to another.
Definition value.c:6308
fr_sbuff_parse_rules_t const value_parse_rules_backtick_unquoted
Definition value.c:496
fr_sbuff_parse_rules_t const value_parse_rules_double_quoted
Definition value.c:547
int fr_value_box_bstr_alloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv, size_t len, bool tainted)
Alloc and assign an empty \0 terminated string to a fr_value_box_t.
Definition value.c:4101
fr_sbuff_unescape_rules_t * fr_value_unescape_by_quote[T_TOKEN_LAST]
Definition value.c:336
#define SIGN_PROMOTE(_int, _len)
fr_sbuff_parse_rules_t const value_parse_rules_solidus_3quoted
Definition value.c:586
int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
Copy value data verbatim moving any buffers to the specified context.
Definition value.c:3888
int fr_value_box_to_key(uint8_t **out, size_t *outlen, fr_value_box_t const *value)
Get a key from a value box.
Definition value.c:2084
void fr_value_box_flatten(TALLOC_CTX *ctx, fr_value_box_list_t *list, bool steal, bool free)
Removes a single layer of nesting, moving all children into the parent list.
Definition value.c:5969
int fr_value_box_list_acopy(TALLOC_CTX *ctx, fr_value_box_list_t *out, fr_value_box_list_t const *in)
Do a full copy of a list of value boxes.
Definition value.c:6124
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:3742
bool fr_value_box_list_tainted(fr_value_box_list_t const *head)
Check to see if any list members (or their children) are tainted.
Definition value.c:6152
ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
Encode a single value box, serializing its contents in generic network format.
Definition value.c:1404
static int64_t const fr_value_box_integer_min[]
Definition value.c:246
int fr_value_box_bstr_realloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, size_t len)
Change the length of a buffer already allocated to a value box.
Definition value.c:4134
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
Definition value.c:4178
int fr_value_box_memdup_dbuff(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Definition value.c:4444
int fr_regex_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b)
Compare two boxes using an operator.
Definition regex.c:1392
fr_sbuff_unescape_rules_t fr_value_unescape_double
Definition value.c:266
int fr_value_box_bstrdup_buffer_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a talloced buffer containing a nul terminated string to a box, but don't copy it.
Definition value.c:4283
size_t fr_value_substr_unescape(fr_sbuff_t *out, fr_sbuff_t *in, size_t inlen, char quote)
Convert a string value with escape sequences into its binary form.
Definition value.c:1201
fr_sbuff_escape_rules_t fr_value_escape_secret
Escape secret fields by simply mashing all data to '.
Definition value.c:381
ssize_t fr_value_box_from_substr(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules)
Convert string value to a fr_value_box_t type.
Definition value.c:4686
int fr_value_box_escape_in_place(fr_value_box_t *vb, fr_value_box_escape_t const *escape, void *uctx)
Escape a single value box in place.
Definition value.c:5902
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
Definition value.c:4262
static int fr_value_box_cast_to_ipv6addr(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert any supported type to an IPv6 address.
Definition value.c:2618
int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Copy a buffer to a fr_value_box_t.
Definition value.c:4419
static int fr_value_box_cast_integer_to_integer(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert any signed or unsigned integer type to any other signed or unsigned integer type.
Definition value.c:2987
int fr_value_box_list_concat_in_place(TALLOC_CTX *ctx, fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type, fr_value_box_list_action_t proc_action, bool flatten, size_t max_size)
Concatenate a list of value boxes.
Definition value.c:5734
fr_value_box_list_action_t
Actions to perform when we process a box in a list.
Definition value.h:226
@ FR_VALUE_BOX_LIST_NONE
Do nothing to processed boxes.
Definition value.h:227
@ FR_VALUE_BOX_LIST_REMOVE
Remove the box from the input list.
Definition value.h:228
#define vb_should_free(_action)
Definition value.h:235
#define fr_value_box_list_foreach_safe(_list_head, _iter)
Definition value.h:218
#define vb_ether
Definition value.h:260
#define vb_date
Definition value.h:277
#define vb_int64
Definition value.h:272
#define vb_octets
Definition value.h:253
#define vb_should_free_value(_action)
Definition value.h:236
#define vb_should_remove(_action)
Definition value.h:237
#define vb_int32
Definition value.h:271
static int fr_value_box_memcpy_out(void *out, fr_value_box_t const *vb)
Copy the value of a value box to a field in a C struct.
Definition value.h:779
#define vb_int16
Definition value.h:270
static fr_slen_t fr_value_box_aprint(TALLOC_CTX *ctx, char **out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules) 1(fr_value_box_print
#define vb_uint8
Definition value.h:263
#define vb_length
Definition value.h:283
#define vb_int8
Definition value.h:269
static fr_slen_t data
Definition value.h:1274
static bool fr_value_box_contains_secret(fr_value_box_t const *box)
Definition value.h:1086
#define vb_float64
Definition value.h:275
#define FR_VALUE_BOX_NET_ERROR
Special value to indicate fr_value_box_from_network experienced a general error.
Definition value.h:1029
static uint8_t * fr_value_box_raw(fr_value_box_t const *vb, fr_type_t type)
Return a pointer to the "raw" value from a value-box.
Definition value.h:755
#define fr_box_strvalue_len(_val, _len)
Definition value.h:297
#define FR_VALUE_BOX_MAGIC
Definition value.h:91
#define fr_value_box_init_null(_vb)
Initialise an empty/null box that will be filled later.
Definition value.h:604
#define fr_value_box_is_safe_for(_box, _safe_for)
Definition value.h:1070
#define vb_ip
Definition value.h:257
static size_t char fr_sbuff_t size_t inlen
Definition value.h:1012
fr_value_box_safe_for_t safe_for
Definition value.h:666
#define vb_uint16
Definition value.h:264
#define vb_bool
Definition value.h:262
#define vb_size
Definition value.h:279
#define FR_VALUE_BOX_SAFE_FOR_NONE
Definition value.h:165
uintptr_t fr_value_box_safe_for_t
Escaping that's been applied to a value box.
Definition value.h:155
#define vb_strvalue
Definition value.h:252
#define vb_uint32
Definition value.h:265
int nonnull(2, 5))
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:643
#define vb_ifid
Definition value.h:259
#define vb_time_delta
Definition value.h:281
fr_value_box_escape_func_t func
Definition value.h:665
static always_inline int fr_value_box_ethernet_addr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, fr_ethernet_t const *src, bool tainted)
Definition value.h:838
#define vb_float32
Definition value.h:274
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:598
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:217
#define FR_VALUE_BOX_NET_OOM
Special value to indicate fr_value_box_from_network hit an out of memory error.
Definition value.h:1033
#define vb_uint64
Definition value.h:266
static size_t char ** out
Definition value.h:1012
#define FR_VALUE_BOX_SAFE_FOR_ANY
Definition value.h:166