The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
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: 426224fca7b63284060024598884ec454215fc48 $")
46
47#define _VALUE_PRIVATE
48#include <freeradius-devel/util/value.h>
49#undef _VALUE_PRIVATE
50
51#include <freeradius-devel/util/base16.h>
52#include <freeradius-devel/util/size.h>
53
54#include <math.h>
55#include <float.h>
56
57/** Sanity checks
58 *
59 * There should never be an instance where these fail.
60 */
61static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_ipv4addr) == 4,
62 "in_addr.s_addr has unexpected length");
63static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_ipv6addr) == 16,
64 "in6_addr.s6_addr has unexpected length");
65static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_ifid) == 8,
66 "vb_ifid has unexpected length");
67static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_ether) == 6,
68 "vb_ether has unexpected length");
69
70static_assert(SIZEOF_MEMBER(fr_value_box_t, datum.boolean) == 1,
71 "datum.boolean has unexpected length");
72static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_uint8) == 1,
73 "vb_uint8 has unexpected length");
74static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_uint16) == 2,
75 "vb_uint16 has unexpected length");
76static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_uint32) == 4,
77 "vb_uint32 has unexpected length");
78static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_uint64) == 8,
79 "vb_uint64 has unexpected length");
80
81static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_int8) == 1,
82 "vb_int8 has unexpected length");
83static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_int16) == 2,
84 "vb_int16 has unexpected length");
85static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_int32) == 4,
86 "vb_int32 has unexpected length");
87static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_int64) == 8,
88 "vb_int64 has unexpected length");
89
90static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_float32) == 4,
91 "vb_float32 has unexpected length");
92static_assert(SIZEOF_MEMBER(fr_value_box_t, vb_float64) == 8,
93 "vb_float64 has unexpected length");
94
95
96#if defined(WITH_VERIFY_PTR) || !defined(NDEBUG)
97#define VERIFY_IS_SET(_vb) UNCONST(fr_value_box_t *, _vb)->verified
98#define VERIFY_SET(_vb) UNCONST(fr_value_box_t *, _vb)->verified = true
99#define VERIFY_CLEAR(_vb) UNCONST(fr_value_box_t *, _vb)->verified = false
100#else
101#define VERIFY_IS_SET(_vb) (0)
102#define VERIFY_SET(_vb) do { } while (0)
103#define VERIFY_CLEAR(_vb) do { } while (0)
104#endif
105
106/** How many bytes on-the-wire would a #fr_value_box_t value consume
107 *
108 * This is for the generic NETWORK format. For field sizes in the in-memory
109 * structure use #fr_value_box_field_sizes.
110 *
111 * @note Don't use this array directly when determining the length
112 * that would be consumed by the on-the-wire representation.
113 * Use #fr_value_box_network_length instead, as that deals with variable
114 * length attributes too.
115 */
116#define network_min_size(_x) (fr_value_box_network_sizes[_x][0])
117#define network_max_size(_x) (fr_value_box_network_sizes[_x][1])
118static size_t const fr_value_box_network_sizes[FR_TYPE_MAX + 1][2] = {
119 [FR_TYPE_NULL] = {~0, 0},
120
121 [FR_TYPE_STRING] = {0, ~0},
122 [FR_TYPE_OCTETS] = {0, ~0},
123
124 [FR_TYPE_IPV4_ADDR] = {4, 4},
125 [FR_TYPE_IPV4_PREFIX] = {5, 5},
126 [FR_TYPE_IPV6_ADDR] = {16, 17},
127 [FR_TYPE_IPV6_PREFIX] = {17, 18},
128 [FR_TYPE_COMBO_IP_ADDR] = {4, 17},
129 [FR_TYPE_COMBO_IP_PREFIX] = {16, 18},
130 [FR_TYPE_IFID] = {8, 8},
131 [FR_TYPE_ETHERNET] = {6, 6},
132
133 [FR_TYPE_BOOL] = {1, 1},
134 [FR_TYPE_UINT8] = {1, 1},
135 [FR_TYPE_UINT16] = {2, 2},
136 [FR_TYPE_UINT32] = {4, 4},
137 [FR_TYPE_UINT64] = {8, 8},
138
139 [FR_TYPE_INT8] = {1, 1},
140 [FR_TYPE_INT16] = {2, 2},
141 [FR_TYPE_INT32] = {4, 4},
142 [FR_TYPE_INT64] = {8, 8},
143
144 [FR_TYPE_SIZE] = {8, 8},
145
146 [FR_TYPE_FLOAT32] = {4, 4},
147 [FR_TYPE_FLOAT64] = {8, 8},
148
149 [FR_TYPE_DATE] = {2, 8}, //!< 2, 4, or 8 only
150 [FR_TYPE_TIME_DELTA] = {2, 8}, //!< 2, 4, or 8 only
151
152 [FR_TYPE_ATTR] = {1, ~0},
153
154 [FR_TYPE_MAX] = {~0, 0} //!< Ensure array covers all types.
155};
156
157/** How many bytes wide each of the value data fields are
158 *
159 * This is useful when copying a value from a fr_value_box_t to a memory
160 * location passed as a void *.
161 */
162size_t const fr_value_box_field_sizes[] = {
165
174
175 [FR_TYPE_BOOL] = SIZEOF_MEMBER(fr_value_box_t, datum.boolean),
180
185
188
190
191 [FR_TYPE_TIME_DELTA] = SIZEOF_MEMBER(fr_value_box_t, datum.time_delta),
193
195
197
198 [FR_TYPE_MAX] = 0 //!< Ensure array covers all types.
199};
200
201/** Where the value starts in the #fr_value_box_t
202 *
203 */
204size_t const fr_value_box_offsets[] = {
207
214 [FR_TYPE_IFID] = offsetof(fr_value_box_t, vb_ifid),
216
217 [FR_TYPE_BOOL] = offsetof(fr_value_box_t, vb_bool),
222
223 [FR_TYPE_INT8] = offsetof(fr_value_box_t, vb_int8),
227
230
231 [FR_TYPE_DATE] = offsetof(fr_value_box_t, vb_date),
232
234 [FR_TYPE_SIZE] = offsetof(fr_value_box_t, vb_size),
235 [FR_TYPE_ATTR] = offsetof(fr_value_box_t, vb_attr),
236
237 [FR_TYPE_VALUE_BOX] = 0,
238
239 [FR_TYPE_MAX] = 0 //!< Ensure array covers all types.
240};
241
242static uint64_t const fr_value_box_integer_max[] = {
243 [FR_TYPE_BOOL] = true,
245 [FR_TYPE_UINT16] = UINT16_MAX,
246 [FR_TYPE_UINT32] = UINT32_MAX,
247 [FR_TYPE_UINT64] = UINT64_MAX,
248
249 [FR_TYPE_INT8] = INT8_MAX,
250 [FR_TYPE_INT16] = INT16_MAX,
251 [FR_TYPE_INT32] = INT32_MAX,
252 [FR_TYPE_INT64] = INT64_MAX,
253
254 [FR_TYPE_DATE] = UINT64_MAX,
255 [FR_TYPE_TIME_DELTA] = INT64_MAX,
256
257 [FR_TYPE_SIZE] = SIZE_MAX,
258
259 [FR_TYPE_MAX] = 0 //!< Ensure array covers all types.
260};
261
262static int64_t const fr_value_box_integer_min[] = {
263 [FR_TYPE_BOOL] = false,
264 [FR_TYPE_UINT8] = 0,
265 [FR_TYPE_UINT16] = 0,
266 [FR_TYPE_UINT32] = 0,
267 [FR_TYPE_UINT64] = 0,
268
269 [FR_TYPE_INT8] = INT8_MIN,
270 [FR_TYPE_INT16] = INT16_MIN,
271 [FR_TYPE_INT32] = INT32_MIN,
272 [FR_TYPE_INT64] = INT64_MIN,
273
274 [FR_TYPE_DATE] = 0,
275 [FR_TYPE_TIME_DELTA] = INT64_MIN,
276
277 [FR_TYPE_SIZE] = 0,
278
279 [FR_TYPE_MAX] = 0 //!< Ensure array covers all types.
280};
281
283 .name = "double",
284 .chr = '\\',
285 .subs = {
286 ['"'] = '"', /* Quoting char */
287 ['%'] = '%', /* xlat expansions */
288 ['\\'] = '\\',
289 ['a'] = '\a',
290 ['b'] = '\b',
291 ['e'] = '\\',
292 ['n'] = '\n',
293 ['r'] = '\r',
294 ['t'] = '\t',
295 ['v'] = '\v'
296 },
297 .do_hex = true,
298 .do_oct = true
299};
300
302 .name = "single",
303 .chr = '\\',
304 .subs = {
305 ['\''] = '\'', /* Quoting char */
306 ['\\'] = '\\'
307 },
308 .do_hex = false,
309 .do_oct = false
310};
311
313 .name = "solidus",
314 .chr = '\\',
315 .subs = {
316 ['%'] = '%', /* xlat expansions */
317 ['/'] = '/', /* Quoting char */
318 ['a'] = '\a',
319 ['b'] = '\b',
320 ['e'] = '\\',
321 ['n'] = '\n',
322 ['r'] = '\r',
323 ['t'] = '\t',
324 ['v'] = '\v'
325 },
326 .skip = {
327 ['\\'] = '\\' /* Leave this for the regex library */
328 },
329 .do_hex = true,
330 .do_oct = true
331};
332
334 .name = "backtick",
335 .chr = '\\',
336 .subs = {
337 ['%'] = '%', /* xlat expansions */
338 ['\\'] = '\\',
339 ['`'] = '`', /* Quoting char */
340 ['a'] = '\a',
341 ['b'] = '\b',
342 ['e'] = '\\',
343 ['n'] = '\n',
344 ['r'] = '\r',
345 ['t'] = '\t',
346 ['v'] = '\v'
347 },
348 .do_hex = true,
349 .do_oct = true
350};
351
358
365
367 .name = "double",
368 .chr = '\\',
369 .subs = {
370 ['"'] = '"', /* Quoting char */
371 ['%'] = '%', /* xlat expansions */
372 ['\\'] = '\\',
373 ['\a'] = 'a',
374 ['\b'] = 'b',
375 ['\n'] = 'n',
376 ['\r'] = 'r',
377 ['\t'] = 't',
378 ['\v'] = 'v'
379 },
380 .esc = {
383 },
384 .do_utf8 = true,
385 .do_oct = true
386};
387
388DIAG_OFF_OPTIONAL(gnu-designator)
389
390/** Escape secret fields by simply mashing all data to '.'
391 *
392 * The length of the secret still leaks, but that is likely fine. Fixing that is more work.
393 *
394 */
396 .name = "secret",
397 .subs = {
398 [ 0 ... 255 ] = '.',
399 },
400};
401
403 .name = "single",
404 .chr = '\\',
405 .subs = {
406 ['\''] = '\'', /* Quoting char */
407 ['\\'] = '\\'
408 },
409 .do_utf8 = true,
410};
411
413 .name = "solidus",
414 .chr = '\\',
415 .subs = {
416 ['%'] = '%', /* xlat expansions */
417 ['/'] = '/', /* Quoting char */
418 ['\a'] = 'a',
419 ['\b'] = 'b',
420 ['\n'] = 'n',
421 ['\r'] = 'r',
422 ['\t'] = 't',
423 ['\v'] = 'v'
424 },
425 .esc = {
428 },
429 .do_utf8 = true,
430 .do_oct = true
431};
432
434 .name = "backtick",
435 .chr = '\\',
436 .subs = {
437 ['%'] = '%', /* xlat expansions */
438 ['\\'] = '\\',
439 ['`'] = '`', /* Quoting char */
440 ['\a'] = 'a',
441 ['\b'] = 'b',
442 ['\n'] = 'n',
443 ['\r'] = 'r',
444 ['\t'] = 't',
445 ['\v'] = 'v'
446 },
447 .esc = {
450 },
451 .do_utf8 = true,
452 .do_oct = true
453};
454
461
468
470 .name = "unprintables",
471 .chr = '\\',
472 .subs = {
473 ['\\'] = '\\',
474 },
475 .esc = {
478 },
479 .do_utf8 = true,
480 .do_oct = true
481};
482
483
484/** @name Produce a #tmpl_t from a string or substring
485 *
486 * @{
487 */
488
489/* clang-format off */
490/** Default formatting rules
491 *
492 * Control token termination, escaping and how the tmpl is printed.
493 */
494fr_sbuff_parse_rules_t const value_parse_rules_bareword_unquoted = {
495
496};
497
498fr_sbuff_parse_rules_t const value_parse_rules_double_unquoted = {
499 .escapes = &fr_value_unescape_double
500};
501
502fr_sbuff_parse_rules_t const value_parse_rules_single_unquoted = {
503 .escapes = &fr_value_unescape_single
504};
505
506fr_sbuff_parse_rules_t const value_parse_rules_solidus_unquoted = {
507 .escapes = &fr_value_unescape_solidus
508};
509
510fr_sbuff_parse_rules_t const value_parse_rules_backtick_unquoted = {
512};
513
514/** Parse rules for non-quoted strings
515 *
516 * These parse rules should be used for processing escape sequences in
517 * data from external data sources like SQL databases and REST APIs.
518 *
519 * They do not include terminals to stop parsing as it assumes the values
520 * are discrete, and not wrapped in quotes.
521 */
529
537
538fr_sbuff_parse_rules_t const value_parse_rules_bareword_quoted = {
539 .escapes = &(fr_sbuff_unescape_rules_t){
540 .chr = '\\',
541 /*
542 * Allow barewords to contain whitespace
543 * if they're escaped.
544 */
545 .subs = {
546 ['\t'] = '\t',
547 ['\n'] = '\n',
548 [' '] = ' '
549 },
550 .do_hex = false,
551 .do_oct = false
552 },
553 .terminals = &FR_SBUFF_TERMS(
554 L(""),
555 L("\t"),
556 L("\n"),
557 L(" ")
558 )
559};
560
561fr_sbuff_parse_rules_t const value_parse_rules_double_quoted = {
562 .escapes = &fr_value_unescape_double,
563 .terminals = &FR_SBUFF_TERMS(
564 L(""), L("\n"), L("\r"), L("\""))
565};
566
567fr_sbuff_parse_rules_t const value_parse_rules_single_quoted = {
568 .escapes = &fr_value_unescape_single,
569 .terminals = &FR_SBUFF_TERMS(
570 L(""), L("\n"), L("\r"), L("'"))
571};
572
573fr_sbuff_parse_rules_t const value_parse_rules_solidus_quoted = {
574 .escapes = &fr_value_unescape_solidus,
575 .terminals = &FR_SBUFF_TERMS(
576 L(""), L("\n"), L("\r"), L("/"))
577};
578
579fr_sbuff_parse_rules_t const value_parse_rules_backtick_quoted = {
580 .escapes = &fr_value_unescape_backtick,
581 .terminals = &FR_SBUFF_TERMS(
582 L(""), L("\n"), L("\r"), L("`"))
583};
584
585/*
586 * And triple-quoted versions of the above.
587 */
588fr_sbuff_parse_rules_t const value_parse_rules_double_3quoted = {
589 .escapes = &fr_value_unescape_double,
590 .terminals = &FR_SBUFF_TERMS(
591 L(""), L("\n"), L("\r"), L("\"\"\""))
592};
593
594fr_sbuff_parse_rules_t const value_parse_rules_single_3quoted = {
595 .escapes = &fr_value_unescape_single,
596 .terminals = &FR_SBUFF_TERMS(
597 L(""), L("\n"), L("\r"), L("'''"))
598};
599
600fr_sbuff_parse_rules_t const value_parse_rules_solidus_3quoted = {
601 .escapes = &fr_value_unescape_solidus,
602 .terminals = &FR_SBUFF_TERMS(
603 L(""), L("\n"), L("\r"), L("///"))
604};
605
606fr_sbuff_parse_rules_t const value_parse_rules_backtick_3quoted = {
607 .escapes = &fr_value_unescape_backtick,
608 .terminals = &FR_SBUFF_TERMS(
609 L(""), L("\n"), L("\r"), L("```"))
610};
611
612/** Parse rules for quoted strings
613 *
614 * These parse rules should be used for internal parsing functions that
615 * are working with configuration files.
616 *
617 * They include appropriate quote terminals to force functions parsing
618 * quoted strings to return when they reach a quote character.
619 */
627
635
643
644/* clang-format on */
645/** @} */
646
647/** Copy flags and type data from one value box to another
648 *
649 * @param[in] dst to copy flags to
650 * @param[in] src of data.
651 */
652static inline void fr_value_box_copy_meta(fr_value_box_t *dst, fr_value_box_t const *src)
653{
654 switch (src->type) {
656 dst->vb_length = src->vb_length;
657 break;
658 /*
659 * Not 100% sure this should be done here
660 * but if the intent is to make a null
661 * box usable, then we need to do this
662 * somewhere.
663 */
664 case FR_TYPE_GROUP:
665 fr_value_box_list_init(&dst->vb_group);
666 break;
667
668 case FR_TYPE_NUMERIC:
669 case FR_TYPE_IP:
670 case FR_TYPE_IFID:
671 case FR_TYPE_ETHERNET:
672 case FR_TYPE_ATTR:
673 case FR_TYPE_NULL:
674 case FR_TYPE_VOID:
678 break;
679
680 case FR_TYPE_TLV:
681 case FR_TYPE_STRUCT:
682 case FR_TYPE_VSA:
683 case FR_TYPE_VENDOR:
684 case FR_TYPE_UNION:
685 case FR_TYPE_MAX:
686 fr_assert(0);
687 break;
688 }
689
690#ifndef NDEBUG
691 dst->magic = FR_VALUE_BOX_MAGIC;
692#endif
693#if defined(WITH_VERIFY_PTR) || !defined(NDEBUG)
694 dst->file = src->file;
695 dst->line = src->line;
696#endif
697
698 dst->enumv = src->enumv;
699 dst->type = src->type;
700 dst->tainted = src->tainted;
701 dst->vb_safefor = src->vb_safefor;
702 dst->vb_secret = src->vb_secret;
703 fr_value_box_list_entry_init(dst);
704
705 /*
706 * We have no idea if this is true, but we can't _guarantee_ it. So we clear the flag.
707 */
708 dst->talloced = false;
709}
710
711/** Compare two floating point numbers for equality.
712 *
713 * We're not _quite_ supposed to use DBL_EPSILON here, and are instead supposed to choose our own epsilon.
714 * But this is good enough for most purposed.
715 */
716static fr_cmp_ret_t float_cmp(double a, double b)
717{
718 double sum, diff;
719
720 /*
721 * Handles the best cast scenario.
722 */
723DIAG_OFF(float-equal)
724 if (a == b) return CMP_EQ;
725DIAG_ON(float-equal)
726
727 diff = fabs(a - b);
728
729 /*
730 * One of the numbers is zero. The other might be close to zero, in which case it might as well
731 * be zero.
732 *
733 * Otherwise, the non-zero number is far from zero, and we can just compare them.
734 */
735 if ((fpclassify(a) == FP_ZERO) || (fpclassify(b) == FP_ZERO)) {
736 check:
737 if (diff < DBL_EPSILON) return CMP_EQ;
738
739 return CMP(a, b);
740 }
741
742 /*
743 * Get the rough scale of the two numbers.
744 */
745 sum = fabs(a) + fabs(b);
746
747 /*
748 * The two numbers are not zero, but both are close to it.
749 */
750 if (sum < DBL_MIN) goto check;
751
752 /*
753 * Get the relative differences. This check also handles overflow of sum.
754 */
755 if ((diff / fmin(sum, DBL_MAX)) < DBL_EPSILON) return CMP_EQ;
756
757 return CMP(a, b);
758}
759
760/** Compare two values
761 *
762 * @param[in] a Value to compare.
763 * @param[in] b Value to compare.
764 * @return
765 * - CMP_LT if a is less than b.
766 * - CMP_EQ if both are equal.
767 * - CMP_GT if a is more than b.
768 * - CMP_ERR if the values are not comparable, retrieve the error with fr_strerror.
769 */
771{
772 if (a->type != b->type) {
773 fr_strerror_printf("%s: Can't compare values of different types", __FUNCTION__);
774 return CMP_ERR;
775 }
776
777 /*
778 * After doing the previous check for special comparisons,
779 * do the per-type comparison here.
780 */
781 switch (a->type) {
783 /*
784 * Note that we do NOT check a->vb_secret or b->vb_secret. This function is used to sort pairs
785 * and sets of value-boxes. The fr_digest_cmp() function returns 0..255 no matter what
786 * the two inputs are. So it can't be used in a stable sort.
787 */
788 return MEMCMP_FIELDS(a, b, datum.ptr, vb_length);
789
790 /*
791 * Short-hand for simplicity.
792 */
793#define RETURN(_type) return CMP(a->datum._type, b->datum._type)
794#define COMPARE(_type) return CMP(memcmp(&a->datum._type, &b->datum._type, sizeof(a->datum._type)), 0)
795
796 case FR_TYPE_BOOL:
797 RETURN(boolean);
798
799 case FR_TYPE_DATE:
800 return fr_unix_time_cmp(a->datum.date, b->datum.date);
801
802 case FR_TYPE_UINT8:
803 RETURN(uint8);
804
805 case FR_TYPE_UINT16:
806 RETURN(uint16);
807
808 case FR_TYPE_UINT32:
809 RETURN(uint32);
810
811 case FR_TYPE_UINT64:
812 RETURN(uint64);
813
814 case FR_TYPE_INT8:
815 RETURN(int8);
816
817 case FR_TYPE_INT16:
818 RETURN(int16);
819
820 case FR_TYPE_INT32:
821 RETURN(int32);
822
823 case FR_TYPE_INT64:
824 RETURN(int64);
825
826 case FR_TYPE_SIZE:
827 RETURN(size);
828
830 return fr_time_delta_cmp(a->datum.time_delta, b->datum.time_delta);
831
832 case FR_TYPE_FLOAT32:
833 return float_cmp((double) a->vb_float32, (double) b->vb_float32);
834
835 case FR_TYPE_FLOAT64:
836 return float_cmp(a->vb_float64, b->vb_float64);
837
838 case FR_TYPE_ETHERNET:
839 COMPARE(ether);
840
847 return fr_ipaddr_cmp(&a->vb_ip, &b->vb_ip);
848
849 case FR_TYPE_IFID:
850 COMPARE(ifid);
851
852 case FR_TYPE_NULL: /* NULLs are not comparable */
853 fr_strerror_const("NULL values are not comparable");
854 return CMP_ERR;
855
856 case FR_TYPE_ATTR:
857 /*
858 * @todo - this makes things _distinct_, but doesn't provide a _full_ order. We
859 * generally don't need a full ordering for attributes.
860 *
861 * The need to call fr_dict_attr_cmp() here is for comparing raw / unknown attributes
862 * which come from xlats. Unknown / raw attributes which are in policies are added to
863 * the dictionaries when the server starts, and are thus known.
864 */
865 return fr_dict_attr_cmp(a->vb_attr, b->vb_attr);
866
867 case FR_TYPE_VOID:
868 return CMP(a->vb_void, b->vb_void);
869
874 case FR_TYPE_MAX:
875 break;
876
877 /*
878 * Do NOT add a default here, as new types are added
879 * static analysis will warn us they're not handled
880 */
881 }
882
883 (void)fr_cond_assert(0); /* invalud type for leaf comparison */
884 fr_strerror_printf("Invalid type %s for leaf comparison", fr_type_to_str(a->type));
885 return CMP_ERR;
886}
887
888/*
889 * We leverage the fact that IPv4 and IPv6 prefixes both
890 * have the same format:
891 *
892 * reserved, prefix-len, data...
893 */
894static int fr_value_box_cidr_cmp_op(fr_token_t op, int bytes,
895 uint8_t a_net, uint8_t const *a,
896 uint8_t b_net, uint8_t const *b)
897{
898 int i, common;
900
901 /*
902 * Handle the case of netmasks being identical.
903 */
904 if (a_net == b_net) {
905 int compare;
906
907 compare = memcmp(a, b, bytes);
908
909 /*
910 * If they're identical return true for
911 * identical.
912 */
913 if ((compare == 0) &&
914 ((op == T_OP_CMP_EQ) ||
915 (op == T_OP_LE) ||
916 (op == T_OP_GE))) {
917 return true;
918 }
919
920 /*
921 * Everything else returns false.
922 *
923 * 10/8 == 24/8 --> false
924 * 10/8 <= 24/8 --> false
925 * 10/8 >= 24/8 --> false
926 */
927 return false;
928 }
929
930 /*
931 * Netmasks are different. That limits the
932 * possible results, based on the operator.
933 */
934 switch (op) {
935 case T_OP_CMP_EQ:
936 return false;
937
938 case T_OP_NE:
939 return true;
940
941 case T_OP_LE:
942 case T_OP_LT: /* 192/8 < 192.168/16 --> false */
943 if (a_net < b_net) {
944 return false;
945 }
946 break;
947
948 case T_OP_GE:
949 case T_OP_GT: /* 192/16 > 192.168/8 --> false */
950 if (a_net > b_net) {
951 return false;
952 }
953 break;
954
955 default:
956 return false;
957 }
958
959 if (a_net < b_net) {
960 common = a_net;
961 } else {
962 common = b_net;
963 }
964
965 /*
966 * Do the check uint8 by uint8. If the bytes are
967 * identical, it MAY be a match. If they're different,
968 * it is NOT a match.
969 */
970 i = 0;
971 while (i < bytes) {
972 /*
973 * All leading bytes are identical.
974 */
975 if (common == 0) return true;
976
977 /*
978 * Doing bitmasks takes more work.
979 */
980 if (common < 8) break;
981
982 if (a[i] != b[i]) return false;
983
984 common -= 8;
985 i++;
986 continue;
987 }
988
989 mask = 1;
990 mask <<= (8 - common);
991 mask--;
992 mask = ~mask;
993
994 if ((a[i] & mask) == ((b[i] & mask))) {
995 return true;
996 }
997
998 return false;
999}
1000
1001/*
1002 * So we don't have to include <util/regex.h> in a recursive fashion.
1003 */
1004extern int fr_regex_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b);
1005
1006/** Compare two attributes using an operator
1007 *
1008 * @param[in] op to use in comparison.
1009 * @param[in] a Value to compare.
1010 * @param[in] b Value to compare.
1011 * @return
1012 * - 1 if true
1013 * - 0 if false
1014 * - -1 on failure.
1015 * - < -1 on failure.
1016 */
1018{
1019 int compare = 0;
1020
1021 if (unlikely((op == T_OP_REG_EQ) || (op == T_OP_REG_NE))) return fr_regex_cmp_op(op, a, b);
1022
1025
1026 switch (a->type) {
1027 case FR_TYPE_IPV4_ADDR:
1028 switch (b->type) {
1030 if (b->vb_ip.af != AF_INET) goto fail_cmp_v4;
1032
1033 case FR_TYPE_IPV4_ADDR: /* IPv4 and IPv4 */
1034 goto cmp;
1035
1037 if (b->vb_ip.af != AF_INET) goto fail_cmp_v4;
1039
1040 case FR_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
1041 return fr_value_box_cidr_cmp_op(op, 4, 32, (uint8_t const *) &a->vb_ipv4addr,
1042 b->vb_ip.prefix, (uint8_t const *) &b->vb_ipv4addr);
1043
1044 default:
1045 fail_cmp_v4:
1046 fr_strerror_const("Cannot compare IPv4 with IPv6 address");
1047 return -1;
1048 }
1049
1050 case FR_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
1051 cmp_prefix_v4:
1052 switch (b->type) {
1054 if (b->vb_ip.af != AF_INET) goto fail_cmp_v4;
1056
1057 case FR_TYPE_IPV4_ADDR:
1058 return fr_value_box_cidr_cmp_op(op, 4, a->vb_ip.prefix,
1059 (uint8_t const *) &a->vb_ipv4addr,
1060 32, (uint8_t const *) &b->vb_ip.addr.v4);
1061
1063 if (b->vb_ip.af != AF_INET) goto fail_cmp_v4;
1065
1066 case FR_TYPE_IPV4_PREFIX: /* IPv4 Prefix and IPv4 Prefix */
1067 return fr_value_box_cidr_cmp_op(op, 4, a->vb_ip.prefix,
1068 (uint8_t const *) &a->vb_ipv4addr,
1069 b->vb_ip.prefix, (uint8_t const *) &b->vb_ipv4addr);
1070
1071 default:
1072 fr_strerror_const("Cannot compare IPv4 with IPv6 address");
1073 return -1;
1074 }
1075
1076 case FR_TYPE_IPV6_ADDR:
1077 switch (b->type) {
1079 if (b->vb_ip.af != AF_INET6) goto fail_cmp_v6;
1081
1082 case FR_TYPE_IPV6_ADDR: /* IPv6 and IPv6 */
1083 goto cmp;
1084
1086 if (b->vb_ip.af != AF_INET6) goto fail_cmp_v6;
1088
1089 case FR_TYPE_IPV6_PREFIX: /* IPv6 and IPv6 Preifx */
1090 return fr_value_box_cidr_cmp_op(op, 16, 128, (uint8_t const *) &a->vb_ip.addr.v6,
1091 b->vb_ip.prefix, (uint8_t const *) &b->vb_ip.addr.v6);
1092
1093 default:
1094 fail_cmp_v6:
1095 fr_strerror_const("Cannot compare IPv6 with IPv4 address");
1096 return -1;
1097 }
1098
1100 cmp_prefix_v6:
1101 switch (b->type) {
1103 if (b->vb_ip.af != AF_INET6) goto fail_cmp_v6;
1105
1106 case FR_TYPE_IPV6_ADDR: /* IPv6 Prefix and IPv6 */
1107 return fr_value_box_cidr_cmp_op(op, 16, a->vb_ip.prefix,
1108 (uint8_t const *) &a->vb_ip.addr.v6,
1109 128, (uint8_t const *) &b->vb_ip.addr.v6);
1110
1112 if (b->vb_ip.af != AF_INET6) goto fail_cmp_v6;
1114
1115 case FR_TYPE_IPV6_PREFIX: /* IPv6 Prefix and IPv6 */
1116 return fr_value_box_cidr_cmp_op(op, 16, a->vb_ip.prefix,
1117 (uint8_t const *) &a->vb_ip.addr.v6,
1118 b->vb_ip.prefix, (uint8_t const *) &b->vb_ip.addr.v6);
1119
1120 default:
1121 fr_strerror_const("Cannot compare IPv6 with IPv4 address");
1122 return -1;
1123 }
1124
1126 if (a->vb_ip.af != b->vb_ip.af) goto fail_cmp_v4; /* as good as any */
1127
1128 goto cmp;
1129
1131 if (a->vb_ip.af != b->vb_ip.af) goto fail_cmp_v4; /* as good as any */
1132
1133 if (a->vb_ip.af == AF_INET) goto cmp_prefix_v4;
1134
1135 goto cmp_prefix_v6;
1136
1137 case FR_TYPE_NUMERIC:
1138 case FR_TYPE_IFID:
1139 case FR_TYPE_ETHERNET:
1141 case FR_TYPE_ATTR:
1142 case FR_TYPE_NULL:
1143 cmp:
1144 compare = fr_value_box_cmp(a, b);
1145 if (unlikely(compare == CMP_ERR)) return -1;
1146 break;
1147
1148 case FR_TYPE_GROUP:
1149 case FR_TYPE_TLV:
1150 case FR_TYPE_STRUCT:
1151 case FR_TYPE_VSA:
1152 case FR_TYPE_VENDOR:
1153 case FR_TYPE_UNION:
1154 case FR_TYPE_INTERNAL:
1155 fr_assert(0);
1156 return -1;
1157 }
1158
1159 /*
1160 * Now do the operator comparison.
1161 */
1162 switch (op) {
1163 case T_OP_CMP_EQ:
1164 return (compare == 0);
1165
1166 case T_OP_NE:
1167 return (compare != 0);
1168
1169 case T_OP_LT:
1170 return (compare < 0);
1171
1172 case T_OP_GT:
1173 return (compare > 0);
1174
1175 case T_OP_LE:
1176 return (compare <= 0);
1177
1178 case T_OP_GE:
1179 return (compare >= 0);
1180
1181 default:
1182 return 0;
1183 }
1184}
1185
1186/** Convert a string value with escape sequences into its binary form
1187 *
1188 * The quote character determines the escape sequences recognised.
1189 *
1190 * - Literal mode ("'" quote char) will unescape:
1191 @verbatim
1192 - \\ - Literal backslash.
1193 - <quote> - The quotation char.
1194 @endverbatim
1195 * - Expanded mode ('"' quote char) will also unescape:
1196 @verbatim
1197 - \a - Alert.
1198 - \b - Backspace.
1199 - \e - Escape character i.e. (\‍)
1200 - \r - Carriage return.
1201 - \n - Newline.
1202 - \t - Tab.
1203 - \v - Vertical tab
1204 - <oct> - An octal escape sequence.
1205 - \x<hex> - A hex escape sequence.
1206 @endverbatim
1207 * - Backtick mode ('`' quote char) identical to expanded mode.
1208 * - Regex mode ('/') identical to expanded mode but two successive
1209 * backslashes will be interpreted as an escape sequence, but not
1210 * unescaped, so that they will be passed to the underlying regex
1211 * library.
1212 * - Verbatim mode ('\0' quote char) copies in to out verbatim.
1213 *
1214 * @note The resulting output may contain embedded \0s.
1215 * @note Unrecognised escape sequences will be copied verbatim.
1216 * @note In and out may point to the same underlying buffer.
1217 * @note Copying will stop early if an unescaped instance of the
1218 * quoting char is found in the input buffer.
1219 *
1220 * @param[out] len Number of bytes written to out. May be NULL.
1221 * @param[out] out Where to write the unescaped string.
1222 * @param[in] in The string to unescape.
1223 * @param[in] max Maximum number of input bytes to consume. Pass SIZE_MAX
1224 * to consume all data in the input buffer.
1225 * @param[in] quote Character around the string, determines unescaping mode.
1226 *
1227 * @return
1228 * - FR_SBUFF_OK on success, including when the input was empty.
1229 * - FR_SBUFF_ERR_NO_SPACE out filled before the input was consumed.
1230 * - FR_SBUFF_ERR_EXTEND in's extend callback failed.
1231 */
1233{
1234 switch (quote) {
1235 default:
1236 break;
1237
1238 case '"':
1240
1241 case '\'':
1243
1244 case '`':
1246
1247 case '/':
1249 }
1250
1251 return fr_sbuff_out_bstrncpy(len, out, in, max);
1252}
1253
1254/** Convert a string value with escape sequences into its binary form
1255 *
1256 * The quote character determines the escape sequences recognised.
1257 *
1258 * - Literal mode ("'" quote char) will unescape:
1259 @verbatim
1260 - \\ - Literal backslash.
1261 - <quote> - The quotation char.
1262 @endverbatim
1263 * - Expanded mode ('"' quote char) will also unescape:
1264 @verbatim
1265 - \a - Alert.
1266 - \b - Backspace.
1267 - \e - Escape character i.e. (\‍)
1268 - \r - Carriage return.
1269 - \n - Newline.
1270 - \t - Tab.
1271 - \v - Vertical tab
1272 - <oct> - An octal escape sequence.
1273 - \x<hex> - A hex escape sequence.
1274 @endverbatim
1275 * - Backtick mode ('`' quote char) identical to expanded mode.
1276 * - Regex mode ('/') identical to expanded mode but two successive
1277 * backslashes will be interpreted as an escape sequence, but not
1278 * unescaped, so that they will be passed to the underlying regex
1279 * library.
1280 * - Verbatim mode ('\0' quote char) copies in to out verbatim.
1281 *
1282 * @note The resulting output may contain embedded \0s.
1283 * @note Unrecognised escape sequences will be copied verbatim.
1284 * @note In and out may point to the same underlying buffer.
1285 * @note Copying will stop early if an unescaped instance of the
1286 * quoting char is found in the input buffer.
1287 *
1288 * @param[out] len Number of bytes written to out. May be NULL.
1289 * @param[out] out Where to write the unescaped string.
1290 * @param[in] in The string to unescape.
1291 * @param[in] max Maximum number of input bytes to consume. Pass SIZE_MAX
1292 * to consume all data in the input buffer.
1293 * @param[in] quote Character around the string, determines unescaping mode.
1294 *
1295 * @return
1296 * - FR_SBUFF_OK on success, including when the input was empty.
1297 * - FR_SBUFF_ERR_NO_SPACE out filled before the input was consumed.
1298 * - FR_SBUFF_ERR_EXTEND in's extend callback failed.
1299 */
1301{
1302 switch (quote) {
1303 default:
1304 break;
1305
1306 case '"':
1308
1309 case '\'':
1311
1312 case '`':
1314
1315 case '/':
1317 }
1318
1319 return fr_sbuff_out_bstrncpy(len, out, in, max);
1320}
1321
1322/** Performs byte order reversal for types that need it
1323 *
1324 * @param[in] dst Where to write the result. May be the same as src.
1325 * @param[in] src #fr_value_box_t containing an uint32 value.
1326 * @return
1327 * - 0 on success.
1328 * - -1 on failure.
1329 */
1331{
1332 switch (src->type) {
1333 case FR_TYPE_INT16:
1334 case FR_TYPE_INT32:
1335 case FR_TYPE_INT64:
1336 case FR_TYPE_UINT16:
1337 case FR_TYPE_UINT32:
1338 case FR_TYPE_UINT64:
1339 case FR_TYPE_FLOAT32:
1340 case FR_TYPE_FLOAT64:
1341 case FR_TYPE_DATE:
1342 case FR_TYPE_TIME_DELTA:
1343 break;
1344
1345 case FR_TYPE_BOOL:
1346 case FR_TYPE_UINT8:
1347 case FR_TYPE_INT8:
1348 case FR_TYPE_IPV4_ADDR:
1350 case FR_TYPE_IPV6_ADDR:
1354 case FR_TYPE_IFID:
1355 case FR_TYPE_ETHERNET:
1356 case FR_TYPE_SIZE:
1357 if (unlikely(fr_value_box_copy(NULL, dst, src) < 0)) return -1;
1358 return 0;
1359
1360 case FR_TYPE_NULL:
1362 return 0;
1363
1364 case FR_TYPE_ATTR:
1365 case FR_TYPE_OCTETS:
1366 case FR_TYPE_STRING:
1367 case FR_TYPE_INTERNAL:
1368 case FR_TYPE_STRUCTURAL:
1369 fr_assert_fail(NULL);
1370 return -1; /* shouldn't happen */
1371 }
1372
1373 /*
1374 * If we're not just flipping in place
1375 * initialise the destination box
1376 * with similar meta data as the src.
1377 *
1378 * Don't use the copy meta data function
1379 * here as that doesn't initialise the
1380 * destination box.
1381 */
1382 if (dst != src) fr_value_box_init(dst, src->type, src->enumv, src->tainted);
1383
1384 switch (src->type) {
1385 case FR_TYPE_UINT16:
1386 dst->vb_uint16 = htons(src->vb_uint16);
1387 break;
1388
1389 case FR_TYPE_UINT32:
1390 case FR_TYPE_FLOAT32: /* same offset and size as uint32 */
1391 dst->vb_uint32 = htonl(src->vb_uint32);
1392 break;
1393
1394 case FR_TYPE_UINT64:
1395 case FR_TYPE_FLOAT64: /* same offset and size as uint64 */
1396 dst->vb_uint64 = htonll(src->vb_uint64);
1397 break;
1398
1399 case FR_TYPE_INT16:
1400 dst->vb_int16 = htons(src->vb_int16);
1401 break;
1402
1403 case FR_TYPE_INT32:
1404 dst->vb_int32 = htonl(src->vb_int32);
1405 break;
1406
1407 case FR_TYPE_INT64:
1408 dst->vb_int64 = htonll(src->vb_int64);
1409 break;
1410
1411 case FR_TYPE_DATE:
1412 dst->vb_date = fr_unix_time_wrap(htonll(fr_unix_time_unwrap(src->vb_date)));
1413 break;
1414
1415 case FR_TYPE_TIME_DELTA:
1416 dst->vb_time_delta = fr_time_delta_wrap(htonll(fr_time_delta_unwrap(src->vb_time_delta)));
1417 break;
1418
1419 default:
1420 fr_assert_fail(NULL);
1421 return -1; /* shouldn't happen */
1422 }
1423
1424 return 0;
1425}
1426
1427/** Get the size of the value held by the fr_value_box_t
1428 *
1429 * This is the length of the NETWORK presentation
1430 */
1432{
1433 switch (value->type) {
1435 if (value->enumv) {
1436 /*
1437 * Fixed-width fields.
1438 */
1439 if (value->enumv->flags.length) {
1440 return value->enumv->flags.length;
1441 }
1442
1443 /*
1444 * Clamp length at maximum we're allowed to encode.
1445 */
1446 if (da_is_length_field8(value->enumv)) {
1447 if (value->vb_length > UINT8_MAX) return UINT8_MAX;
1448
1449 } else if (da_is_length_field16(value->enumv)) {
1450 if (value->vb_length > UINT16_MAX) return UINT16_MAX;
1451 }
1452 }
1453 return value->vb_length;
1454
1455 /*
1456 * These can have different encodings, depending on the underlying protocol.
1457 */
1458 case FR_TYPE_DATE:
1459 case FR_TYPE_TIME_DELTA:
1460 if (value->enumv) return value->enumv->flags.length;
1462
1463 default:
1464 fr_assert(network_min_size(value->type) != 0);
1465 return network_min_size(value->type);
1466
1467 case FR_TYPE_TLV:
1468 case FR_TYPE_STRUCT:
1469 case FR_TYPE_VSA:
1470 case FR_TYPE_VENDOR:
1471 case FR_TYPE_INTERNAL:
1472 fr_assert(0);
1473 return -1;
1474 }
1475}
1476
1477/** Encode the scope_id of an IPv6 address or prefix as one byte
1478 *
1479 * The network format gives the scope_id one byte, but fr_ipaddr_t holds the
1480 * scope_id in a uint32_t. The function fails for a scope_id above 255 rather
1481 * than truncating the scope_id.
1482 */
1484{
1485 if (value->vb_ip.scope_id > UINT8_MAX) {
1486 fr_strerror_printf("IPv6 scope_id %u is too large to encode in one byte", value->vb_ip.scope_id);
1487 return -1;
1488 }
1489
1490 FR_DBUFF_IN_BYTES_RETURN(dbuff, (uint8_t) value->vb_ip.scope_id);
1491 return 0;
1492}
1493
1494/** Encode a single value box, serializing its contents in generic network format
1495 *
1496 * The serialized form of #fr_value_box_t may not match the requirements of your protocol
1497 * completely. In cases where they do not, you should overload specific types in the
1498 * function calling #fr_value_box_to_network.
1499 *
1500 * The general serialization rules are:
1501 *
1502 * - Octets are encoded in binary form (not hex).
1503 * - Strings are encoded without the trailing \0 byte.
1504 * - Integers are encoded big-endian.
1505 * - Bools are encoded using one byte, with value 0x00 (false) or 0x01 (true).
1506 * - Signed integers are encoded two's complement, with the MSB as the sign bit.
1507 * Byte order is big-endian.
1508 * - Network addresses are encoded big-endian.
1509 * - IPv4 prefixes are encoded with 1 byte for the prefix, then 4 bytes of address.
1510 * - IPv6 prefixes are encoded with 1 byte for the scope_id, 1 byte for the prefix,
1511 * and 16 bytes of address.
1512 * - Floats are encoded in IEEE-754 format with a big-endian byte order. We rely
1513 * on the fact that the C standards require floats to be represented in IEEE-754
1514 * format in memory.
1515 * - Dates are encoded as 16/32/64-bit unsigned UNIX timestamps.
1516 * - time_deltas are encoded as 16/32/64-bit signed integers.
1517 *
1518 * #FR_TYPE_SIZE is not encodable, as it is system specific.
1519 *
1520 * This function will not encode structural types (TLVs, VSAs etc...). These are usually
1521 * specific to the protocol anyway.
1522 *
1523 * All of the dictionary rules are respected. string/octets can have
1524 * a fixed length (which is zero-padded if necessary), or can have an
1525 * 8/16-bit "length" prefix.
1526 *
1527 * @param[out] dbuff Where to write serialized data.
1528 * @param[in] value to encode.
1529 * @return
1530 * - 0 no bytes were written.
1531 * - >0 the number of bytes written to out.
1532 * - <0 the number of bytes we'd need in dbuff to complete the operation.
1533 */
1535{
1536 size_t min, max;
1537 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1538
1539 /*
1540 * We cannot encode structural types here.
1541 */
1542 if (!fr_type_is_leaf(value->type)) {
1543 unsupported:
1544 fr_strerror_printf("%s: Cannot encode type \"%s\"",
1545 __FUNCTION__,
1546 fr_type_to_str(value->type));
1548 }
1549
1550 /*
1551 * Variable length types
1552 */
1553 switch (value->type) {
1554 case FR_TYPE_OCTETS:
1555 case FR_TYPE_STRING:
1556 max = value->vb_length;
1557
1558 /*
1559 * Sometimes variable length *inside* the server
1560 * has maximum length on the wire.
1561 */
1562 if (value->enumv) {
1563 if (value->enumv->flags.length) {
1564 /*
1565 * The field is fixed size, and the data is smaller than that, We zero-pad the field.
1566 */
1567 if (max < value->enumv->flags.length) {
1568 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *)value->datum.ptr, max);
1569 FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, value->enumv->flags.length - max);
1570 return fr_dbuff_set(dbuff, &work_dbuff);
1571
1572 } else if (max > value->enumv->flags.length) {
1573 /*
1574 * Truncate the input to the maximum allowed length.
1575 */
1576 max = value->enumv->flags.length;
1577 }
1578
1579 } else if (da_is_length_field8(value->enumv)) {
1580 /*
1581 * Truncate the output to the max allowed for this field and encode the length.
1582 */
1583 if (max > UINT8_MAX) max = UINT8_MAX;
1584 FR_DBUFF_IN_RETURN(&work_dbuff, (uint8_t) max);
1585
1586 } else if (da_is_length_field16(value->enumv)) {
1587
1588 if (max > UINT16_MAX) max = UINT16_MAX;
1589 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t) max);
1590 }
1591 }
1592
1593 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *)value->datum.ptr, max);
1594 return fr_dbuff_set(dbuff, &work_dbuff);
1595
1596 /*
1597 * The data can be encoded in a variety of widths.
1598 */
1599 case FR_TYPE_DATE:
1600 case FR_TYPE_TIME_DELTA:
1601 if (value->enumv) {
1602 min = value->enumv->flags.length;
1603 } else {
1604 min = 4;
1605 }
1606 break;
1607
1608 default:
1609 fr_assert(network_min_size(value->type) != 0);
1610 min = network_min_size(value->type);
1611 break;
1612
1613 case FR_TYPE_TLV:
1614 case FR_TYPE_STRUCT:
1615 case FR_TYPE_VSA:
1616 case FR_TYPE_VENDOR:
1617 case FR_TYPE_INTERNAL:
1618 fr_assert(0);
1619 return -1;
1620 }
1621
1622 /*
1623 * We have to encode actual data here.
1624 */
1625 fr_assert(min > 0);
1626
1627 switch (value->type) {
1628 case FR_TYPE_IPV4_ADDR:
1629 ipv4addr:
1630 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff,
1631 (uint8_t const *)&value->vb_ipv4addr,
1632 sizeof(value->vb_ipv4addr));
1633 break;
1634 /*
1635 * Needs special mangling
1636 */
1638 ipv4prefix:
1639 FR_DBUFF_IN_RETURN(&work_dbuff, value->vb_ip.prefix);
1640 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff,
1641 (uint8_t const *)&value->vb_ipv4addr,
1642 sizeof(value->vb_ipv4addr));
1643 break;
1644
1645 case FR_TYPE_IPV6_ADDR:
1646 ipv6addr:
1647 if (value->vb_ip.scope_id > 0) {
1648 if (value_box_ipv6_scope_id_to_network(&work_dbuff, value) < 0) return -1;
1649 }
1650 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value->vb_ipv6addr, sizeof(value->vb_ipv6addr));
1651 break;
1652
1654 ipv6prefix:
1655 if (value->vb_ip.scope_id > 0) {
1656 if (value_box_ipv6_scope_id_to_network(&work_dbuff, value) < 0) return -1;
1657 }
1658 FR_DBUFF_IN_RETURN(&work_dbuff, value->vb_ip.prefix);
1659 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value->vb_ipv6addr, sizeof(value->vb_ipv6addr));
1660 break;
1661
1662 case FR_TYPE_BOOL:
1663 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, value->datum.boolean);
1664 break;
1665
1667 switch (value->vb_ip.af) {
1668 case AF_INET:
1669 goto ipv4addr;
1670
1671 case AF_INET6:
1672 goto ipv6addr;
1673
1674 default:
1675 break;
1676 }
1677
1678 fr_strerror_const("Combo IP value missing af");
1679 return 0;
1680
1682 switch (value->vb_ip.af) {
1683 case AF_INET:
1684 goto ipv4prefix;
1685
1686 case AF_INET6:
1687 goto ipv6prefix;
1688
1689 default:
1690 break;
1691 }
1692
1693 fr_strerror_const("Combo IP value missing af");
1694 return 0;
1695
1696 /*
1697 * Already in network byte-order
1698 */
1699 case FR_TYPE_IFID:
1700 case FR_TYPE_ETHERNET:
1701 case FR_TYPE_UINT8:
1702 case FR_TYPE_INT8:
1704 break;
1705
1706 /*
1707 * Needs a bytesex operation
1708 */
1709 case FR_TYPE_UINT16:
1710 case FR_TYPE_UINT32:
1711 case FR_TYPE_UINT64:
1712 case FR_TYPE_INT16:
1713 case FR_TYPE_INT32:
1714 case FR_TYPE_INT64:
1715 case FR_TYPE_FLOAT32:
1716 case FR_TYPE_FLOAT64:
1717 {
1718 fr_value_box_t tmp;
1719
1720 fr_value_box_hton(&tmp, value);
1721
1722 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, fr_value_box_raw(&tmp, value->type), min);
1723 }
1724 break;
1725
1726 case FR_TYPE_ATTR:
1727 {
1728 fr_value_box_t tmp, base;
1729
1730 /*
1731 * For now, we only encode at depth 1. The protocol-specific encoders need to do
1732 * something special for attributes at other depths.
1733 */
1734 if (value->vb_attr->depth != 1) {
1735 fr_strerror_printf("Unsupported depth '%u' for encoding attribute %s",
1736 value->vb_attr->depth, value->vb_attr->name);
1737 return 0;
1738 }
1739
1740 switch (value->vb_attr->flags.length) {
1741 case 1:
1742 if (value->vb_attr->attr > UINT8_MAX) {
1743 too_large:
1744 fr_strerror_printf("Attribute %s number %u is too large to encode in %d byte(s)",
1745 value->vb_attr->name, value->vb_attr->attr, value->vb_attr->flags.length);
1746 return 0;
1747 }
1748 fr_value_box_init(&base, FR_TYPE_UINT8, NULL, false);
1749 base.vb_uint8 = value->vb_attr->attr;
1750 break;
1751
1752 case 2:
1753 if (value->vb_attr->attr > UINT16_MAX) goto too_large;
1754 fr_value_box_init(&base, FR_TYPE_UINT16, NULL, false);
1755 base.vb_uint16 = value->vb_attr->attr;
1756 break;
1757
1758 case 4:
1759 fr_value_box_init(&base, FR_TYPE_UINT32, NULL, false);
1760 base.vb_uint32 = value->vb_attr->attr;
1761 break;
1762
1763 default:
1764 fr_strerror_printf("Unsupported length '%d' for decoding attribute %s",
1765 value->vb_attr->flags.length, value->vb_attr->name);
1766 return 0;
1767 }
1768
1769 fr_value_box_hton(&tmp, &base);
1770
1771 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, fr_value_box_raw(&tmp, tmp.type), min);
1772 }
1773 break;
1774
1775 /*
1776 * Dates and deltas are stored internally as
1777 * 64-bit nanoseconds. We have to convert to the
1778 * network format. First by resolution (ns, us,
1779 * ms, s), and then by size (16/32/64-bit).
1780 */
1781 case FR_TYPE_DATE:
1782 {
1783 uint64_t date = 0;
1784 fr_time_res_t res;
1785
1786 if (!value->enumv) {
1787 res = FR_TIME_RES_SEC;
1788 } else {
1789 res = (fr_time_res_t)value->enumv->flags.flag_time_res;
1790 }
1791 date = fr_unix_time_to_integer(value->vb_date, res);
1792
1793 if (!value->enumv) {
1794 goto date_size4;
1795
1796 } else switch (value->enumv->flags.length) {
1797 case 2:
1798 if (date > UINT16_MAX) date = UINT16_MAX;
1799 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t) date);
1800 break;
1801
1802 date_size4:
1803 case 4:
1804 if (date > UINT32_MAX) date = UINT32_MAX;
1805 FR_DBUFF_IN_RETURN(&work_dbuff, (uint32_t) date);
1806 break;
1807
1808 case 8:
1809 FR_DBUFF_IN_RETURN(&work_dbuff, date);
1810 break;
1811
1812 default:
1813 goto unsupported;
1814 }
1815
1816 }
1817 break;
1818
1819 case FR_TYPE_TIME_DELTA:
1820 {
1821 int64_t date = 0; /* may be negative */
1823 if (value->enumv) res = (fr_time_res_t)value->enumv->flags.flag_time_res;
1824
1825 date = fr_time_delta_to_integer(value->vb_time_delta, res);
1826
1827 if (!value->enumv) {
1828 goto delta_size4;
1829
1830 } else if (!value->enumv->flags.is_unsigned) {
1831 switch (value->enumv->flags.length) {
1832 case 2:
1833 if (date < INT16_MIN) {
1834 date = INT16_MIN;
1835 } else if (date > INT16_MAX) {
1836 date = INT16_MAX;
1837 }
1838 FR_DBUFF_IN_RETURN(&work_dbuff, (int16_t)date);
1839 break;
1840
1841 delta_size4:
1842 case 4:
1843 if (date < INT32_MIN) {
1844 date = INT32_MIN;
1845 } else if (date > INT32_MAX) {
1846 date = INT32_MAX;
1847 }
1848 FR_DBUFF_IN_RETURN(&work_dbuff, (int32_t)date);
1849 break;
1850
1851 case 8:
1852 FR_DBUFF_IN_RETURN(&work_dbuff, (int64_t)date);
1853 break;
1854
1855 default:
1856 goto unsupported;
1857 }
1858 } else { /* time delta is unsigned! */
1859 switch (value->enumv->flags.length) {
1860 case 2:
1861 if (date < 0) {
1862 date = 0;
1863 } else if (date > UINT16_MAX) {
1864 date = UINT16_MAX;
1865 }
1866 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t)date);
1867 break;
1868
1869 case 4:
1870 if (date < 0) {
1871 date = 0;
1872 } else if (date > UINT32_MAX) {
1873 date = UINT32_MAX;
1874 }
1875 FR_DBUFF_IN_RETURN(&work_dbuff, (uint32_t)date);
1876 break;
1877
1878 case 8:
1879 FR_DBUFF_IN_RETURN(&work_dbuff, (uint64_t)date);
1880 break;
1881
1882 default:
1883 goto unsupported;
1884 }
1885 }
1886 }
1887 break;
1888
1889 case FR_TYPE_OCTETS:
1890 case FR_TYPE_STRING:
1891 case FR_TYPE_SIZE:
1892 case FR_TYPE_NON_LEAF:
1893 goto unsupported;
1894 }
1895
1896 return fr_dbuff_set(dbuff, &work_dbuff);
1897}
1898
1899/** Decode a #fr_value_box_t from serialized binary data
1900 *
1901 * The general deserialization rules are:
1902 *
1903 * - Octets are decoded in binary form (not hex).
1904 * - Strings are decoded without the trailing \0 byte. Strings must consist only of valid UTF8 chars.
1905 * - Integers are decoded big-endian.
1906 * - Bools are decoded using one byte, with value 0x00 (false) or 0x01 (true).
1907 * - Signed integers are decoded two's complement, with the MSB as the sign bit.
1908 * Byte order is big-endian.
1909 * - Network addresses are decoded big-endian.
1910 * - IPv4 prefixes are decoded with 1 byte for the prefix, then 4 bytes of address.
1911 * - IPv6 prefixes are decoded with 1 byte for the scope_id, 1 byte for the prefix,
1912 * and 16 bytes of address.
1913 * - Floats are decoded in IEEE-754 format with a big-endian byte order. We rely
1914 * on the fact that the C standards require floats to be represented in IEEE-754
1915 * format in memory.
1916 * - Dates are decoded as 32bit unsigned UNIX timestamps.
1917 *
1918 * All of the dictionary rules are respected. string/octets can have
1919 * a fixed length, or can have an 8/16-bit "length" prefix. If the
1920 * enumv is not an array, then the input # len MUST be the correct size
1921 * (not too large or small), otherwise an error is returned.
1922 *
1923 * If the enumv is an array, then the input must have the minimum
1924 * length, and the number of bytes decoded is capped at the maximum
1925 * length allowed to be decoded. This behavior allows the caller to
1926 * decode an array of values simply by calling this function in a
1927 * loop.
1928 *
1929 * @param[in] ctx Where to allocate any talloc buffers required.
1930 * @param[out] dst value_box to write the result to.
1931 * @param[in] type to decode data to.
1932 * @param[in] enumv Aliases for values.
1933 * @param[in] dbuff Binary data to decode.
1934 * @param[in] len Length of data to decode. For fixed length types we only
1935 * decode complete values.
1936 * @param[in] tainted Whether the value came from a trusted source.
1937 * @return
1938 * - >= 0 The number of bytes consumed.
1939 * - <0 - The negative offset where the error occurred.
1940 * - FR_VALUE_BOX_NET_OOM (negative value) - Out of memory.
1941 */
1943 fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv,
1944 fr_dbuff_t *dbuff, size_t len,
1945 bool tainted)
1946{
1947 size_t min, max;
1948 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1949
1952
1953 fr_assert(max > 0);
1954
1955 if (len < min) {
1956 fr_strerror_printf("Got truncated value parsing type \"%s\". "
1957 "Expected length >= %zu bytes, got %zu bytes",
1959 min, len);
1960 return -(min);
1961 }
1962
1963 /*
1964 * For array entries, we only decode one value at a time.
1965 */
1966 if (len > max) {
1967 if (enumv && !enumv->flags.array) {
1968 fr_strerror_printf("Found trailing garbage parsing type \"%s\". "
1969 "Expected length <= %zu bytes, got %zu bytes",
1971 max, len);
1972 return -(max);
1973 }
1974
1975 len = max;
1976 }
1977
1978 /*
1979 * String / octets are special.
1980 */
1982 size_t newlen = len;
1983 size_t offset = 0;
1984
1985 /*
1986 * Decode fixed-width fields.
1987 */
1988 if (enumv) {
1989 if (enumv->flags.length) {
1990 newlen = enumv->flags.length;
1991
1992 } else if (da_is_length_field8(enumv)) {
1993 uint8_t num = 0;
1994
1995 FR_DBUFF_OUT_RETURN(&num, &work_dbuff);
1996 newlen = num;
1997 offset = 1;
1998
1999 } else if (da_is_length_field16(enumv)) {
2000 uint16_t num = 0;
2001
2002 FR_DBUFF_OUT_RETURN(&num, &work_dbuff);
2003 newlen = num;
2004 offset = 2;
2005 }
2006 }
2007
2008 /*
2009 * If we need more data than exists, that's an error.
2010 *
2011 * Otherwise, bound the decoding to the count we found.
2012 */
2013 if (newlen > len) return -(newlen + offset);
2014 len = newlen;
2015
2016 switch (type) {
2017 case FR_TYPE_STRING:
2018 if (fr_value_box_bstrndup_dbuff(ctx, dst, enumv, &work_dbuff, len, tainted) < 0) {
2019 return FR_VALUE_BOX_NET_OOM;
2020 }
2021 return fr_dbuff_set(dbuff, &work_dbuff);
2022
2023 case FR_TYPE_OCTETS:
2024 if (fr_value_box_memdup_dbuff(ctx, dst, enumv, &work_dbuff, len, tainted) < 0) {
2025 return FR_VALUE_BOX_NET_OOM;
2026 }
2027 return fr_dbuff_set(dbuff, &work_dbuff);
2028
2029 default:
2030 return -1;
2031 }
2032 }
2033
2034 /*
2035 * Pre-Initialise box for non-variable types
2036 */
2037 fr_value_box_init(dst, type, enumv, tainted);
2038 switch (type) {
2039 /*
2040 * Already in network byte order
2041 */
2042 case FR_TYPE_IPV4_ADDR:
2043 ipv4addr:
2044 dst->vb_ip = (fr_ipaddr_t){
2045 .af = AF_INET,
2046 .prefix = 32,
2047 };
2048 FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *)&dst->vb_ip.addr.v4, &work_dbuff, len);
2049 break;
2050
2052 ipv4prefix:
2053 dst->vb_ip = (fr_ipaddr_t){
2054 .af = AF_INET,
2055 };
2056 FR_DBUFF_OUT_RETURN(&dst->vb_ip.prefix, &work_dbuff);
2057 FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *)&dst->vb_ip.addr.v4, &work_dbuff, len - 1);
2058 break;
2059
2060 case FR_TYPE_IPV6_ADDR:
2061 ipv6addr:
2062 dst->vb_ip = (fr_ipaddr_t){
2063 .af = AF_INET6,
2064 .scope_id = 0,
2065 .prefix = 128
2066 };
2067 if (len == max) {
2068 uint8_t scope_id = 0;
2069
2070 FR_DBUFF_OUT_RETURN(&scope_id, &work_dbuff);
2071 dst->vb_ip.scope_id = scope_id;
2072 len--;
2073 }
2074 FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *)&dst->vb_ip.addr.v6, &work_dbuff, len);
2075 break;
2076
2078 ipv6prefix:
2079 dst->vb_ip = (fr_ipaddr_t){
2080 .af = AF_INET6,
2081 .scope_id = 0,
2082 };
2083 if (len == max) {
2084 uint8_t scope_id = 0;
2085
2086 FR_DBUFF_OUT_RETURN(&scope_id, &work_dbuff);
2087 dst->vb_ip.scope_id = scope_id;
2088 len--;
2089 }
2090 FR_DBUFF_OUT_RETURN(&dst->vb_ip.prefix, &work_dbuff);
2091 FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *)&dst->vb_ip.addr.v6, &work_dbuff, len - 1);
2092 break;
2093
2096 (len <= network_max_size(FR_TYPE_IPV6_ADDR))) goto ipv6addr; /* scope is optional */
2097 else if ((len >= network_min_size(FR_TYPE_IPV4_ADDR)) &&
2098 (len <= network_max_size(FR_TYPE_IPV4_ADDR))) goto ipv4addr;
2099
2100 fr_strerror_const("Invalid combo ip address value");
2101 return -1;
2102
2105 (len <= network_max_size(FR_TYPE_IPV6_PREFIX))) goto ipv6prefix; /* scope is optional */
2106 else if ((len >= network_min_size(FR_TYPE_IPV4_PREFIX)) &&
2107 (len <= network_max_size(FR_TYPE_IPV4_PREFIX))) goto ipv4prefix;
2108
2109 fr_strerror_const("Invalid combo ip prefix value");
2110 return -1;
2111
2112 case FR_TYPE_BOOL:
2113 {
2114 uint8_t val = 0;
2115
2116 FR_DBUFF_OUT_RETURN(&val, &work_dbuff);
2117 dst->datum.boolean = (val != 0);
2118 }
2119 break;
2120
2121 case FR_TYPE_IFID:
2122 case FR_TYPE_ETHERNET:
2124 break;
2125
2126 case FR_TYPE_UINT8:
2127 FR_DBUFF_OUT_RETURN(&dst->vb_uint8, &work_dbuff);
2128 break;
2129
2130 case FR_TYPE_UINT16:
2131 FR_DBUFF_OUT_RETURN(&dst->vb_uint16, &work_dbuff);
2132 break;
2133
2134 case FR_TYPE_UINT32:
2135 FR_DBUFF_OUT_RETURN(&dst->vb_uint32, &work_dbuff);
2136 break;
2137
2138 case FR_TYPE_UINT64:
2139 FR_DBUFF_OUT_RETURN(&dst->vb_uint64, &work_dbuff);
2140 break;
2141
2142 case FR_TYPE_INT8:
2143 FR_DBUFF_OUT_RETURN(&dst->vb_int8, &work_dbuff);
2144 break;
2145
2146 case FR_TYPE_INT16:
2147 FR_DBUFF_OUT_RETURN(&dst->vb_int16, &work_dbuff);
2148 break;
2149
2150 case FR_TYPE_INT32:
2151 FR_DBUFF_OUT_RETURN(&dst->vb_int32, &work_dbuff);
2152 break;
2153
2154 case FR_TYPE_INT64:
2155 FR_DBUFF_OUT_RETURN(&dst->vb_int64, &work_dbuff);
2156 break;
2157
2158 case FR_TYPE_FLOAT32:
2159 FR_DBUFF_OUT_RETURN(&dst->vb_float32, &work_dbuff);
2160 break;
2161
2162 case FR_TYPE_FLOAT64:
2163 FR_DBUFF_OUT_RETURN(&dst->vb_float64, &work_dbuff);
2164 break;
2165
2166 case FR_TYPE_ATTR:
2167 if (!enumv) {
2168 fr_strerror_const("No enumv (i.e. root) passed to fr_value_box_from_network for type 'attribute'");
2169 return -1;
2170 }
2171
2172 /*
2173 * Decode the number, and see if we can create a
2174 * matching attribute.
2175 */
2176 {
2177 unsigned int num;
2178 uint8_t num8;
2179 uint16_t num16;
2180 uint32_t num32;
2181
2182 switch (enumv->flags.length) {
2183 case 1:
2184 FR_DBUFF_OUT_RETURN(&num8, &work_dbuff);
2185 num = num8;
2186 break;
2187
2188 case 2:
2189 FR_DBUFF_OUT_RETURN(&num16, &work_dbuff);
2190 num = num16;
2191 break;
2192
2193 case 4:
2194 FR_DBUFF_OUT_RETURN(&num32, &work_dbuff);
2195 num = num32;
2196 break;
2197
2198 default:
2199 fr_strerror_const("Unsupported parent length");
2200 return -1;
2201 }
2202
2203 dst->vb_attr = fr_dict_attr_child_by_num(enumv, num);
2204 if (!dst->vb_attr) {
2205 dst->vb_attr = fr_dict_attr_unknown_raw_afrom_num(ctx, enumv, num);
2206 if (!dst->vb_attr) return -1;
2207 }
2208
2209 break;
2210 }
2211
2212 /*
2213 * Dates and deltas are stored internally as
2214 * 64-bit nanoseconds. We have to convert from
2215 * the network format. First by size
2216 * (16/32/64-bit), and then by resolution (ns,
2217 * us, ms, s).
2218 */
2219 case FR_TYPE_DATE:
2220 {
2221 size_t length = 4;
2222 fr_time_res_t precision = FR_TIME_RES_SEC;
2223 uint64_t date;
2224
2225 if (enumv) {
2226 length = enumv->flags.length;
2227 precision = (fr_time_res_t)enumv->flags.flag_time_res;
2228 }
2229
2230 /*
2231 * Input data doesn't match what we were told we
2232 * need.
2233 */
2234 if (len > length) return -(length);
2235
2236 dst->enumv = enumv;
2237
2238 FR_DBUFF_OUT_UINT64V_RETURN(&date, &work_dbuff, length);
2239
2240 if (!fr_multiply(&date, date, fr_time_multiplier_by_res[precision])) {
2241 fr_strerror_const("date would overflow");
2242 return -1;
2243 }
2244
2245 dst->vb_date = fr_unix_time_wrap(date);
2246 }
2247 break;
2248
2249 case FR_TYPE_TIME_DELTA:
2250 {
2251 size_t length = 4;
2252 fr_time_res_t precision = FR_TIME_RES_SEC;
2253 int64_t date;
2254
2255 if (enumv) {
2256 length = enumv->flags.length;
2257 precision = (fr_time_res_t)enumv->flags.flag_time_res;
2258 }
2259
2260 /*
2261 * Input data doesn't match what we were told we
2262 * need.
2263 */
2264 if (len > length) return -(length);
2265
2266 dst->enumv = enumv;
2267
2268 if (!enumv || !enumv->flags.is_unsigned) {
2269 FR_DBUFF_OUT_INT64V_RETURN(&date, &work_dbuff, length);
2270 } else {
2271 uint64_t tmp;
2272
2273 /*
2274 * Else it's an unsigned time delta, but
2275 * we do have to clamp it at the max
2276 * value for a signed 64-bit integer.
2277 */
2278 FR_DBUFF_OUT_UINT64V_RETURN(&tmp, &work_dbuff, length);
2279
2280 if (tmp > INT64_MAX) tmp = INT64_MAX;
2281
2282 date = tmp;
2283 }
2284
2285 dst->vb_time_delta = fr_time_delta_wrap(fr_time_scale(date, precision));
2286 }
2287 break;
2288
2289 case FR_TYPE_STRING:
2290 case FR_TYPE_OCTETS:
2291 break; /* Already dealt with */
2292
2293 case FR_TYPE_SIZE:
2294 case FR_TYPE_NON_LEAF:
2295 fr_strerror_printf("Cannot decode type \"%s\" - Is not a value",
2297 return -1;
2298 }
2299
2300 return fr_dbuff_set(dbuff, &work_dbuff);
2301}
2302
2310
2312 [FR_TYPE_IPV4_ADDR] = {
2313 AF_INET, 32, 32, 0, 4,
2314 },
2315
2317 AF_INET, 0, 32, 0, 4,
2318 },
2319
2320 [FR_TYPE_IPV6_ADDR] = {
2321 AF_INET6, 128, 128, 16, 16,
2322 },
2323
2325 AF_INET6, 0, 128, 0, 16,
2326 },
2327};
2328
2329/** Decode a #fr_value_box_t of type IP address / prefix.
2330 *
2331 * This function also gets passed a prefix length, and is a bit more
2332 * forgiving that fr_value_box_from_network().
2333 *
2334 * @param[out] dst value_box to write the result to.
2335 * @param[in] type to decode data to.
2336 * @param[in] enumv Aliases for values.
2337 * @param[in] prefix_len for prefix types
2338 * @param[in] data Binary data to decode.
2339 * @param[in] data_len Length of data to decode.
2340 * @param[in] fixed is this a fixed size, or a variable one?
2341 * @param[in] tainted Whether the value came from a trusted source.
2342 * @return
2343 * - >= 0 The number of bytes consumed.
2344 * - <0 - an error occurred.
2345 */
2347 int prefix_len, uint8_t const *data, size_t data_len,
2348 bool fixed, bool tainted)
2349{
2350 switch (type) {
2351 case FR_TYPE_IPV4_ADDR:
2353 case FR_TYPE_IPV6_ADDR:
2355 break;
2356
2357 default:
2358 fr_strerror_printf("Invalid data type '%s' passed to IP address decode function",
2360 return -1;
2361 }
2362
2363 /*
2364 * Check the allowed values for prefix length.
2365 */
2366 if (prefix_len < ipaddr_sizes[type].prefix_min) {
2367 fr_strerror_printf("Invalid prefix length %d, expected at least %d",
2368 prefix_len, ipaddr_sizes[type].prefix_min);
2369 return -1;
2370 }
2371
2372 if (prefix_len > ipaddr_sizes[type].prefix_max) {
2373 fr_strerror_printf("Invalid prefix length '%d', expected no more than %d",
2374 prefix_len, ipaddr_sizes[type].prefix_max);
2375 return -1;
2376 }
2377
2378 /*
2379 * It's a prefix data type. Verify that the prefix length doesn't require more bytes than we
2380 * have.
2381 *
2382 * @todo - some protocols allow a larger prefix, and then set the extra bytes to zero. <sigh>
2383 */
2384 if (!ipaddr_sizes[type].addr_min) {
2385 if (fr_bytes_from_bits(prefix_len) > data_len) {
2386 fr_strerror_printf("Invalid prefix length '%d' - it requires %u bytes of data, and there are only %zu bytes of data",
2387 prefix_len, fr_bytes_from_bits(prefix_len), data_len);
2388 return -1;
2389 }
2390 }
2391
2392 /*
2393 * Check how much data is in the buffer.
2394 */
2395 if (data_len < ipaddr_sizes[type].addr_min) {
2396 fr_strerror_printf("Invalid address length '%zu', expected at least %zu",
2397 data_len, ipaddr_sizes[type].addr_min);
2398 return -1;
2399 }
2400
2401 /*
2402 * Do various checks for the size.
2403 */
2404 if (enumv && enumv->flags.array) {
2405 /*
2406 * If this field is part of an array, then it has to be fixed size.
2407 */
2408 data_len = ipaddr_sizes[type].addr_max;
2409
2410 } else if (fixed) {
2411 /*
2412 * If it's fixed size, it must be the maximum size.
2413 */
2414 if (data_len != ipaddr_sizes[type].addr_max) {
2415 fr_strerror_printf("Invalid address length '%zu', expected at exactly %zu",
2416 data_len, ipaddr_sizes[type].addr_max);
2417 return -1;
2418 }
2419
2420 /*
2421 * There is more data in the array - limit what we read to the size of the address.
2422 */
2423 data_len = ipaddr_sizes[type].addr_max;
2424
2425 } else if (data_len > ipaddr_sizes[type].addr_max) {
2426 fr_strerror_printf("Invalid address length '%zu', expected no more than %zu",
2427 data_len, ipaddr_sizes[type].addr_max);
2428 return -1;
2429 }
2430
2431 fr_value_box_init(dst, type, enumv, tainted);
2432 dst->vb_ip = (fr_ipaddr_t) {
2433 .af = ipaddr_sizes[type].af,
2434 .prefix = prefix_len,
2435 /* automatically initialize vp_ip.addr to all zeros */
2436 };
2437
2438 if (!data_len) return 0;
2439
2440 fr_assert(data_len <= sizeof(dst->vb_ip.addr));
2441
2442 memcpy((uint8_t *) &dst->vb_ip.addr, data, data_len);
2443
2444 /*
2445 * @todo - maybe it's an error to have bits set outsize of the prefix length.
2446 */
2447 fr_ipaddr_mask(&dst->vb_ip, prefix_len);
2448
2449 return data_len;
2450}
2451
2452/** Decode a #fr_value_box_t from a C type in memory
2453 *
2454 * We ignore arrays
2455 *
2456 * @param[in] ctx Where to allocate any talloc buffers required.
2457 * @param[out] dst value_box to write the result to.
2458 * @param[in] type to decode data to.
2459 * @param[in] enumv Aliases for values.
2460 * @param[in] src raw pointer to the (possibly unaligned) source
2461 * @param[in] len Length of data to decode. For fixed length types we only
2462 * decode complete values.
2463 * @return
2464 * - >= 0 The number of bytes consumed.
2465 * - <0 an error occured
2466 */
2468 fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv,
2469 void const *src, size_t len)
2470{
2471 switch (type) {
2473 case FR_TYPE_FLOAT32:
2474 case FR_TYPE_FLOAT64:
2476 fr_strerror_printf("Invalid size passed for type %s - expected %zu got %zu",
2478 return -1;
2479 }
2480
2481 fr_value_box_init(dst, type, enumv, false);
2482 memcpy(&dst->datum, src, len);
2483 break;
2484
2485 case FR_TYPE_IPV4_ADDR:
2486 if (len != sizeof(struct in_addr)) {
2487 fr_strerror_printf("Invalid size passed for type %s - expected %zu got %zu",
2488 fr_type_to_str(type), sizeof(struct in_addr), len);
2489 return -1;
2490 }
2491
2492 fr_value_box_init(dst, type, enumv, false);
2493 memcpy(&dst->vb_ipv4addr, src, len);
2494 break;
2495
2496 case FR_TYPE_IPV6_ADDR:
2497 if (len != sizeof(struct in6_addr)) {
2498 fr_strerror_printf("Invalid size passed for type %s - expected %zu got %zu",
2499 fr_type_to_str(type), sizeof(struct in6_addr), len);
2500 return -1;
2501 }
2502
2503 fr_value_box_init(dst, type, enumv, false);
2504 memcpy(&dst->vb_ipv6addr, src, len);
2505 break;
2506
2507 case FR_TYPE_STRING:
2508 return fr_value_box_bstrndup(ctx, dst, enumv, src, len, false);
2509
2510 case FR_TYPE_OCTETS:
2511 return fr_value_box_memdup(ctx, dst, enumv, src, len, false);
2512
2513 default:
2514 fr_strerror_printf("Unsupported data type %s",
2516 return -1;
2517 }
2518
2519 return len;
2520}
2521
2522
2523/** Get a key from a value box
2524 *
2525 * @param[in,out] out - set to a small buffer on input. If the callback has more data
2526 * than is available here, the callback can update "out" to point elsewhere
2527 * @param[in,out] outlen The number of bits available in the initial buffer. On output,
2528 * the number of bits available in the key
2529 * @param[in] value the value box which contains the key
2530 * @return
2531 * - <0 on error
2532 * - 0 on success
2533 */
2535{
2536 ssize_t slen;
2537 fr_dbuff_t dbuff;
2538
2539 switch (value->type) {
2540 case FR_TYPE_BOOL:
2541 if (*outlen < 8) return -1;
2542
2543 *out[0] = (value->vb_bool) << 7;
2544 *outlen = 1;
2545 break;
2546
2548 if (*outlen < (fr_value_box_network_sizes[value->type][1] * 8)) return -1;
2549
2550 /*
2551 * Integers are put into network byte order.
2552 */
2553 fr_dbuff_init(&dbuff, *out, *outlen >> 3);
2554
2555 slen = fr_value_box_to_network(&dbuff, value);
2556 if (slen < 0) return -1;
2557 *outlen = slen * 8; /* bits not bytes */
2558 break;
2559
2560 case FR_TYPE_IP:
2561 /*
2562 * IPs are already in network byte order.
2563 */
2564 *out = UNCONST(uint8_t *, &value->vb_ip.addr);
2565 *outlen = value->vb_ip.prefix;
2566 break;
2567
2568 case FR_TYPE_STRING:
2569 case FR_TYPE_OCTETS:
2570 *out = value->datum.ptr;
2571 *outlen = value->vb_length * 8;
2572 break;
2573
2574 case FR_TYPE_ETHERNET:
2575 *out = UNCONST(uint8_t *, &value->vb_ether[0]);
2576 *outlen = sizeof(value->vb_ether) * 8;
2577 break;
2578
2579 default:
2580 fr_strerror_printf("Invalid data type '%s' for getting key",
2581 fr_type_to_str(value->type));
2582 return -1;
2583 }
2584
2585 return 0;
2586}
2587
2588/** Convert octets to a fixed size value box value
2589 *
2590 * All fixed size types are allowed.
2591 *
2592 * @param dst Where to write result of casting.
2593 * @param dst_type to cast to.
2594 * @param dst_enumv enumeration values.
2595 * @param src Input data.
2596 */
2598 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2599 fr_value_box_t const *src)
2600{
2601 uint8_t *ptr;
2602
2603 if (!fr_type_is_fixed_size(dst_type)) if (!fr_cond_assert(false)) return -1;
2604
2605 if (src->vb_length > network_max_size(dst_type)) {
2606 fr_strerror_printf("Invalid cast from %s to %s. Source length %zu is greater than "
2607 "destination type size %zu",
2608 fr_type_to_str(src->type),
2609 fr_type_to_str(dst_type),
2610 src->vb_length,
2611 network_max_size(dst_type));
2612 return -1;
2613 }
2614
2615 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2616
2617 /*
2618 * No data to copy means just reset it to zero.
2619 */
2620 if (!src->vb_length) return 0;
2621
2622 ptr = (uint8_t *) &dst->datum;
2623
2624 /*
2625 * If the source is too small, just left-fill with zeroes.
2626 */
2627 if (src->vb_length < network_min_size(dst_type)) {
2628 ptr += network_min_size(dst_type) - src->vb_length;
2629 }
2630
2631 /*
2632 * Copy the raw octets into the datum of a value_box
2633 * inverting bytesex for uint32s (if LE).
2634 */
2635 switch (dst->type) {
2636 default:
2637 memcpy(ptr, src->vb_octets, src->vb_length);
2638 fr_value_box_hton(dst, dst);
2639 break;
2640
2641 case FR_TYPE_BOOL:
2642 dst->vb_bool = (src->vb_octets[0] != 0);
2643 break;
2644 }
2645
2646 return 0;
2647}
2648
2649/** v4 to v6 mapping prefix
2650 *
2651 * Part of the IPv6 range is allocated to represent IPv4 addresses.
2652 */
2653static uint8_t const v4_v6_map[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2654 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
2655
2656
2657/** Convert any supported type to a string
2658 *
2659 * All non-structural types are allowed.
2660 *
2661 * @param ctx unused.
2662 * @param dst Where to write result of casting.
2663 * @param dst_type to cast to.
2664 * @param dst_enumv enumeration values.
2665 * @param src Input data.
2666 */
2667static inline int fr_value_box_cast_to_strvalue(TALLOC_CTX *ctx, fr_value_box_t *dst,
2668 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2669 fr_value_box_t const *src)
2670{
2671 if (!fr_cond_assert(dst_type == FR_TYPE_STRING)) return -1;
2672
2673 fr_value_box_init(dst, FR_TYPE_STRING, dst_enumv, false);
2674
2675 switch (src->type) {
2676 /*
2677 * An explicit `null` has no representation to cast from.
2678 * Refuse rather than silently coerce to an empty string.
2679 */
2680 case FR_TYPE_NULL:
2681 fr_strerror_const("Cannot cast null to a string");
2682 return -1;
2683
2684 /*
2685 * The presentation format of octets is hex
2686 * What we actually want here is the raw string
2687 */
2688 case FR_TYPE_OCTETS:
2689 if (fr_value_box_bstrndup(ctx, dst, dst_enumv,
2690 (char const *)src->vb_octets, src->vb_length, src->tainted) < 0) return -1;
2691 fr_value_box_safety_copy(dst, src); /* After bstrndup, which resets the safety */
2692 return 0;
2693
2694 case FR_TYPE_GROUP:
2696 dst, UNCONST(fr_value_box_list_t *, &src->vb_group),
2699 SIZE_MAX);
2700
2701 /*
2702 * Get the presentation format
2703 */
2704 default:
2705 {
2706 char *str;
2707
2708 fr_value_box_aprint(ctx, &str, src, NULL);
2709 if (unlikely(!str)) return -1;
2710
2712 return fr_value_box_bstrdup_buffer_shallow(NULL, dst, dst_enumv, str, src->tainted);
2713 }
2714 }
2715}
2716
2717/** Convert any supported type to octets
2718 *
2719 * All non-structural types are allowed.
2720 *
2721 * @param ctx unused.
2722 * @param dst Where to write result of casting.
2723 * @param dst_type to cast to.
2724 * @param dst_enumv enumeration values.
2725 * @param src Input data.
2726 */
2727static inline int fr_value_box_cast_to_octets(TALLOC_CTX *ctx, fr_value_box_t *dst,
2728 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2729 fr_value_box_t const *src)
2730{
2731 if (!fr_cond_assert(dst_type == FR_TYPE_OCTETS)) return -1;
2732
2733 fr_value_box_init(dst, FR_TYPE_OCTETS, dst_enumv, false);
2735
2736 switch (src->type) {
2737 /*
2738 * An explicit `null` has no representation to cast from.
2739 * Refuse rather than silently coerce to zero-length octets.
2740 */
2741 case FR_TYPE_NULL:
2742 fr_strerror_const("Cannot cast null to octets");
2743 return -1;
2744
2745 /*
2746 * <string> (excluding terminating \0)
2747 */
2748 case FR_TYPE_STRING:
2749 if (fr_value_box_memdup(ctx, dst, dst_enumv,
2750 (uint8_t const *)src->vb_strvalue, src->vb_length, src->tainted) < 0) return -1;
2751 fr_value_box_safety_copy(dst, src); /* After memdup, which resets the safety */
2752 return 0;
2753
2754 case FR_TYPE_GROUP:
2756 dst, UNCONST(fr_value_box_list_t *, &src->vb_group),
2759 SIZE_MAX);
2760 /*
2761 * <4 bytes address>
2762 */
2763 case FR_TYPE_IPV4_ADDR:
2764 return fr_value_box_memdup(ctx, dst, dst_enumv,
2765 (uint8_t const *)&src->vb_ipv4addr,
2766 sizeof(src->vb_ipv4addr), src->tainted);
2767
2768 /*
2769 * <1 uint8 prefix> + <4 bytes address>
2770 */
2772 {
2773 uint8_t *bin;
2774
2775 if (fr_value_box_mem_alloc(ctx, &bin, dst, dst_enumv,
2776 sizeof(src->vb_ipv4addr) + 1, src->tainted) < 0) return -1;
2777
2778 bin[0] = src->vb_ip.prefix;
2779 memcpy(&bin[1], (uint8_t const *)&src->vb_ipv4addr, sizeof(src->vb_ipv4addr));
2780 }
2781 return 0;
2782
2783 /*
2784 * <16 bytes address>
2785 */
2786 case FR_TYPE_IPV6_ADDR:
2787 return fr_value_box_memdup(ctx, dst, dst_enumv,
2788 (uint8_t const *)src->vb_ipv6addr,
2789 sizeof(src->vb_ipv6addr), src->tainted);
2790
2791 /*
2792 * <1 uint8 prefix> + <1 uint8 scope> + <16 bytes address>
2793 */
2795 {
2796 uint8_t *bin;
2797
2798 if (src->vb_ip.scope_id > UINT8_MAX) {
2799 fr_strerror_printf("IPv6 scope_id %u is too large to encode in one byte", src->vb_ip.scope_id);
2800 return -1;
2801 }
2802
2803 if (fr_value_box_mem_alloc(ctx, &bin, dst, dst_enumv,
2804 sizeof(src->vb_ipv6addr) + 2, src->tainted) < 0) return -1;
2805 bin[0] = (uint8_t) src->vb_ip.scope_id;
2806 bin[1] = src->vb_ip.prefix;
2807 memcpy(&bin[2], src->vb_ipv6addr, sizeof(src->vb_ipv6addr));
2808 }
2809 return 0;
2810
2811 /*
2812 * Get the raw binary in memory representation
2813 */
2814 case FR_TYPE_NUMERIC:
2815 {
2816 fr_value_box_t tmp;
2817
2818 fr_value_box_hton(&tmp, src); /* Flip any numeric representations */
2819 return fr_value_box_memdup(ctx, dst, dst_enumv,
2820 fr_value_box_raw(&tmp, src->type),
2821 fr_value_box_field_sizes[src->type], src->tainted);
2822 }
2823
2824 case FR_TYPE_TLV:
2825 case FR_TYPE_STRUCT:
2826 case FR_TYPE_VSA:
2827 case FR_TYPE_VENDOR:
2828 case FR_TYPE_UNION:
2829 case FR_TYPE_INTERNAL:
2830 case FR_TYPE_ATTR:
2831 case FR_TYPE_COMBO_IP_ADDR: /* the types should have been realized to ipv4 / ipv6 */
2833 case FR_TYPE_OCTETS: /* handled above*/
2834 break;
2835
2836
2837 /* Not the same talloc_memdup call as above. The above memdup reads data from the dst */
2838 case FR_TYPE_IFID:
2839 case FR_TYPE_ETHERNET:
2840 return fr_value_box_memdup(ctx, dst, dst_enumv,
2841 fr_value_box_raw(src, src->type),
2842 fr_value_box_field_sizes[src->type], src->tainted);
2843 }
2844
2845 fr_assert(0);
2846 return -1;
2847}
2848
2849#define CAST_IP_FIX_COMBO \
2850 case FR_TYPE_COMBO_IP_ADDR: \
2851 if (src->vb_ip.af == AF_INET) { \
2852 src_type = FR_TYPE_IPV4_ADDR; \
2853 } else if (src->vb_ip.af == AF_INET6) { \
2854 src_type = FR_TYPE_IPV6_ADDR; \
2855 } \
2856 break; \
2857 case FR_TYPE_COMBO_IP_PREFIX: \
2858 if (src->vb_ip.af == AF_INET) { \
2859 src_type = FR_TYPE_IPV4_PREFIX; \
2860 } else if (src->vb_ip.af == AF_INET6) { \
2861 src_type = FR_TYPE_IPV6_PREFIX; \
2862 } \
2863 break
2864
2865
2867{
2868 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2869 fr_type_to_str(src),
2870 fr_type_to_str(dst));
2871 return -1;
2872}
2873
2874
2875/** Convert any supported type to an IPv4 address
2876 *
2877 * Allowed input types are:
2878 * - FR_TYPE_IPV6_ADDR (with v4 prefix).
2879 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2880 * - FR_TYPE_IPV6_PREFIX (with v4 prefix and 128bit mask).
2881 * - FR_TYPE_OCTETS (of length 4).
2882 * - FR_TYPE_UINT32
2883 *
2884 * @param ctx unused.
2885 * @param dst Where to write result of casting.
2886 * @param dst_type to cast to.
2887 * @param dst_enumv enumeration values.
2888 * @param src Input data.
2889 */
2890static inline int fr_value_box_cast_to_ipv4addr(TALLOC_CTX *ctx, fr_value_box_t *dst,
2891 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2892 fr_value_box_t const *src)
2893{
2894 fr_type_t src_type = src->type;
2895
2896 fr_assert(dst_type == FR_TYPE_IPV4_ADDR);
2898
2899 switch (src_type) {
2900 case FR_TYPE_STRING:
2901 if (fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2902 src->vb_strvalue, src->vb_length,
2903 NULL) < 0) {
2904 return -1;
2905 }
2906 return 0;
2907
2909
2910 default:
2911 break;
2912 }
2913
2914 /*
2915 * Pre-initialise box for non-variable types
2916 */
2917 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2918 dst->vb_ip.af = AF_INET;
2919 dst->vb_ip.prefix = 32;
2920 dst->vb_ip.scope_id = 0;
2921
2922 switch (src_type) {
2923 case FR_TYPE_IPV6_ADDR:
2924 if (memcmp(src->vb_ipv6addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
2925 bad_v6_prefix_map:
2926 fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
2927 fr_type_to_str(src->type),
2928 fr_type_to_str(dst_type));
2929 return -1;
2930 }
2931
2932 memcpy(&dst->vb_ip.addr.v4, &src->vb_ipv6addr[sizeof(v4_v6_map)],
2933 sizeof(dst->vb_ip.addr.v4));
2934
2935 break;
2936
2938 if (src->vb_ip.prefix != 32) {
2939 fr_strerror_printf("Invalid cast from %s to %s. Only /32 (not %i/) prefixes may be "
2940 "cast to IP address types",
2941 fr_type_to_str(src->type),
2942 fr_type_to_str(dst_type),
2943 src->vb_ip.prefix);
2944 return -1;
2945 }
2947
2948 case FR_TYPE_IPV4_ADDR: /* Needed for handling combo addresses */
2949 memcpy(&dst->vb_ip.addr.v4, &src->vb_ip.addr.v4, sizeof(dst->vb_ip.addr.v4));
2950 break;
2951
2953 if (src->vb_ip.prefix != 128) {
2954 fr_strerror_printf("Invalid cast from %s to %s. Only /128 (not /%i) prefixes may be "
2955 "cast to IP address types",
2956 fr_type_to_str(src->type),
2957 fr_type_to_str(dst_type),
2958 src->vb_ip.prefix);
2959 return -1;
2960 }
2961 if (memcmp(&src->vb_ipv6addr, v4_v6_map, sizeof(v4_v6_map)) != 0) goto bad_v6_prefix_map;
2962 memcpy(&dst->vb_ip.addr.v4, &src->vb_ipv6addr[sizeof(v4_v6_map)],
2963 sizeof(dst->vb_ip.addr.v4));
2964 break;
2965
2966 case FR_TYPE_OCTETS:
2967 if (src->vb_length != sizeof(dst->vb_ipv4addr)) {
2968 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2969 fr_type_to_str(src->type),
2970 fr_type_to_str(dst_type),
2971 sizeof(dst->vb_ipv4addr), src->vb_length);
2972 return -1;
2973 }
2974 memcpy(&dst->vb_ip.addr.v4, src->vb_octets, sizeof(dst->vb_ipv4addr));
2975 break;
2976
2977 case FR_TYPE_UINT32:
2978 {
2979 uint32_t net;
2980
2981 net = ntohl(src->vb_uint32);
2982 memcpy(&dst->vb_ip.addr.v4, (uint8_t *)&net, sizeof(dst->vb_ipv4addr));
2983 }
2984 break;
2985
2986 default:
2987 return fr_value_box_cast_unsupported(dst_type, src->type);
2988 }
2989
2990 return 0;
2991}
2992
2993/** Convert any supported type to an IPv6 address
2994 *
2995 * Allowed input types are:
2996 * - FR_TYPE_IPV4_ADDR
2997 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2998 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
2999 * - FR_TYPE_OCTETS (of length 16).
3000 *
3001 * @param ctx unused.
3002 * @param dst Where to write result of casting.
3003 * @param dst_type to cast to.
3004 * @param dst_enumv enumeration values.
3005 * @param src Input data.
3006 */
3007static inline int fr_value_box_cast_to_ipv4prefix(TALLOC_CTX *ctx, fr_value_box_t *dst,
3008 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3009 fr_value_box_t const *src)
3010{
3011 fr_type_t src_type = src->type;
3012
3013 fr_assert(dst_type == FR_TYPE_IPV4_PREFIX);
3015
3016 switch (src_type) {
3017 case FR_TYPE_STRING:
3018 if (fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3019 src->vb_strvalue, src->vb_length,
3020 NULL) < 0) {
3021 return -1;
3022 }
3023 return 0;
3024
3026
3027 default:
3028 break;
3029 }
3030
3031 /*
3032 * Pre-initialise box for non-variable types
3033 */
3034 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3035 dst->vb_ip.af = AF_INET;
3036 dst->vb_ip.scope_id = 0;
3037
3038 switch (src_type) {
3039 case FR_TYPE_IPV4_PREFIX: /* Needed for handling combo prefixes */
3040 dst->vb_ip.prefix = src->vb_ip.prefix;
3042
3043 case FR_TYPE_IPV4_ADDR:
3044 memcpy(&dst->vb_ip, &src->vb_ip, sizeof(dst->vb_ip));
3045 break;
3046
3047 /*
3048 * Copy the last four bytes, to make an IPv4prefix
3049 */
3050 case FR_TYPE_IPV6_ADDR:
3051 if (memcmp(src->vb_ipv6addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
3052 bad_v6_prefix_map:
3053 fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
3054 fr_type_to_str(src->type),
3055 fr_type_to_str(dst_type));
3056 return -1;
3057 }
3058 memcpy(&dst->vb_ipv4addr, &src->vb_ipv6addr[sizeof(v4_v6_map)],
3059 sizeof(dst->vb_ipv4addr));
3060 dst->vb_ip.prefix = 32;
3061 break;
3062
3064 if (memcmp(src->vb_ipv6addr, v4_v6_map, sizeof(v4_v6_map)) != 0) goto bad_v6_prefix_map;
3065
3066 if (src->vb_ip.prefix < (sizeof(v4_v6_map) << 3)) {
3067 fr_strerror_printf("Invalid cast from %s to %s. Expected prefix >= %u bits got %u bits",
3068 fr_type_to_str(src->type),
3069 fr_type_to_str(dst_type),
3070 (unsigned int)(sizeof(v4_v6_map) << 3), src->vb_ip.prefix);
3071 return -1;
3072 }
3073 memcpy(&dst->vb_ipv4addr, &src->vb_ipv6addr[sizeof(v4_v6_map)],
3074 sizeof(dst->vb_ipv4addr));
3075
3076 /*
3077 * Subtract the bits used by the v4_v6_map to get the v4 prefix bits
3078 */
3079 dst->vb_ip.prefix = src->vb_ip.prefix - (sizeof(v4_v6_map) << 3);
3080 break;
3081
3082 case FR_TYPE_OCTETS:
3083 if (src->vb_length != sizeof(dst->vb_ipv4addr) + 1) {
3084 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
3085 fr_type_to_str(src->type),
3086 fr_type_to_str(dst_type),
3087 sizeof(dst->vb_ipv4addr) + 1, src->vb_length);
3088 return -1;
3089 }
3090 dst->vb_ip.prefix = src->vb_octets[0];
3091 memcpy(&dst->vb_ip.addr.v4, &src->vb_octets[1], sizeof(dst->vb_ipv4addr));
3092 break;
3093
3094 case FR_TYPE_UINT32:
3095 {
3096 uint32_t net;
3097
3098 net = ntohl(src->vb_uint32);
3099 memcpy(&dst->vb_ip.addr.v4, (uint8_t *)&net, sizeof(dst->vb_ipv4addr));
3100 dst->vb_ip.prefix = 32;
3101 break;
3102 }
3103
3104 default:
3105 return fr_value_box_cast_unsupported(dst_type, src->type);
3106 }
3107
3108 return 0;
3109}
3110
3111/** Convert any supported type to an IPv6 address
3112 *
3113 * Allowed input types are:
3114 * - FR_TYPE_IPV4_ADDR
3115 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
3116 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
3117 * - FR_TYPE_OCTETS (of length 16).
3118 *
3119 * @param ctx unused.
3120 * @param dst Where to write result of casting.
3121 * @param dst_type to cast to.
3122 * @param dst_enumv enumeration values.
3123 * @param src Input data.
3124 */
3125static inline int fr_value_box_cast_to_ipv6addr(TALLOC_CTX *ctx, fr_value_box_t *dst,
3126 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3127 fr_value_box_t const *src)
3128{
3129 fr_type_t src_type = src->type;
3130
3131 static_assert((sizeof(v4_v6_map) + sizeof(src->vb_ip.addr.v4)) <=
3132 sizeof(src->vb_ip.addr.v6), "IPv6 storage too small");
3133
3134 fr_assert(dst_type == FR_TYPE_IPV6_ADDR);
3136
3137 switch (src_type) {
3138 case FR_TYPE_STRING:
3139 if (fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3140 src->vb_strvalue, src->vb_length,
3141 NULL) < 0) {
3142 return -1;
3143 }
3144 return 0;
3145
3147
3148 default:
3149 break;
3150 }
3151
3152 /*
3153 * Pre-initialise box for non-variable types
3154 */
3155 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3156 dst->vb_ip.af = AF_INET6;
3157 dst->vb_ip.prefix = 128;
3158
3159 switch (src_type) {
3160 case FR_TYPE_IPV4_ADDR:
3161 {
3162 uint8_t *p = dst->vb_ipv6addr;
3163
3164 /* Add the v4/v6 mapping prefix */
3165 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
3166 p += sizeof(v4_v6_map);
3167 memcpy(p, (uint8_t const *)&src->vb_ipv4addr, sizeof(src->vb_ipv4addr));
3168 dst->vb_ip.scope_id = 0;
3169 }
3170 break;
3171
3173 {
3174 uint8_t *p = dst->vb_ipv6addr;
3175
3176 if (src->vb_ip.prefix != 32) {
3177 fr_strerror_printf("Invalid cast from %s to %s. Only /32 (not /%i) prefixes may be "
3178 "cast to IP address types",
3179 fr_type_to_str(src->type),
3180 fr_type_to_str(dst_type),
3181 src->vb_ip.prefix);
3182 return -1;
3183 }
3184
3185 /* Add the v4/v6 mapping prefix */
3186 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
3187 p += sizeof(v4_v6_map);
3188 memcpy(p, (uint8_t const *)&src->vb_ipv4addr, sizeof(src->vb_ipv4addr));
3189 dst->vb_ip.scope_id = 0;
3190 }
3191 break;
3192
3194 if (src->vb_ip.prefix != 128) {
3195 fr_strerror_printf("Invalid cast from %s to %s. Only /128 (not /%i) prefixes may be "
3196 "cast to IP address types",
3197 fr_type_to_str(src->type),
3198 fr_type_to_str(dst_type),
3199 src->vb_ip.prefix);
3200 return -1;
3201 }
3203
3204 case FR_TYPE_IPV6_ADDR: /* Needed for handling combo addresses */
3205 memcpy(dst->vb_ipv6addr, src->vb_ipv6addr,
3206 sizeof(dst->vb_ipv6addr));
3207 dst->vb_ip.scope_id = src->vb_ip.scope_id;
3208 break;
3209
3210 case FR_TYPE_OCTETS:
3211 if (src->vb_length != sizeof(dst->vb_ipv6addr)) {
3212 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
3213 fr_type_to_str(src->type),
3214 fr_type_to_str(dst_type),
3215 sizeof(dst->vb_ipv6addr), src->vb_length);
3216 return -1;
3217 }
3218 memcpy(&dst->vb_ipv6addr, src->vb_octets, sizeof(dst->vb_ipv6addr));
3219 break;
3220
3221 default:
3222 return fr_value_box_cast_unsupported(dst_type, src->type);
3223 }
3224
3225 return 0;
3226}
3227
3228/** Convert any supported type to an IPv6 address
3229 *
3230 * Allowed input types are:
3231 * - FR_TYPE_IPV4_ADDR
3232 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
3233 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
3234 * - FR_TYPE_OCTETS (of length 16).
3235 *
3236 * @param ctx unused.
3237 * @param dst Where to write result of casting.
3238 * @param dst_type to cast to.
3239 * @param dst_enumv enumeration values.
3240 * @param src Input data.
3241 */
3242static inline int fr_value_box_cast_to_ipv6prefix(TALLOC_CTX *ctx, fr_value_box_t *dst,
3243 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3244 fr_value_box_t const *src)
3245{
3246 fr_type_t src_type = src->type;
3247
3248 fr_assert(dst_type == FR_TYPE_IPV6_PREFIX);
3250
3251 switch (src_type) {
3252 case FR_TYPE_STRING:
3253 if (fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3254 src->vb_strvalue, src->vb_length,
3255 NULL) < 0) {
3256 return -1;
3257 }
3258 return 0;
3259
3261
3262 default:
3263 break;
3264 }
3265
3266 /*
3267 * Pre-initialise box for non-variable types
3268 */
3269 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3270 dst->vb_ip.af = AF_INET6;
3271
3272 switch (src_type) {
3273 case FR_TYPE_IPV4_ADDR:
3274 {
3275 uint8_t *p = dst->vb_ipv6addr;
3276
3277 /* Add the v4/v6 mapping prefix */
3278 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
3279 p += sizeof(v4_v6_map);
3280 memcpy(p, (uint8_t const *)&src->vb_ipv4addr, sizeof(src->vb_ipv4addr));
3281 dst->vb_ip.prefix = 128;
3282 dst->vb_ip.scope_id = 0;
3283 }
3284 break;
3285
3287 {
3288 uint8_t *p = dst->vb_ipv6addr;
3289
3290 /* Add the v4/v6 mapping prefix */
3291 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
3292 p += sizeof(v4_v6_map);
3293 memcpy(p, (uint8_t const *)&src->vb_ipv4addr, sizeof(src->vb_ipv4addr));
3294 dst->vb_ip.prefix = (sizeof(v4_v6_map) << 3) + src->vb_ip.prefix;
3295 dst->vb_ip.scope_id = 0;
3296 }
3297 break;
3298
3299 case FR_TYPE_IPV6_PREFIX: /* Needed for handling combo prefixes */
3300 dst->vb_ip.prefix = src->vb_ip.prefix;
3301 goto v6_common;
3302
3303 case FR_TYPE_IPV6_ADDR:
3304 dst->vb_ip.prefix = 128;
3305 v6_common:
3306 memcpy(dst->vb_ipv6addr, src->vb_ipv6addr,
3307 sizeof(dst->vb_ipv6addr));
3308 dst->vb_ip.scope_id = src->vb_ip.scope_id;
3309 break;
3310
3311 case FR_TYPE_OCTETS:
3312 if (src->vb_length != (sizeof(dst->vb_ipv6addr) + 2)) {
3313 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
3314 fr_type_to_str(src->type),
3315 fr_type_to_str(dst_type),
3316 sizeof(dst->vb_ipv6addr) + 2, src->vb_length);
3317 return -1;
3318 }
3319 dst->vb_ip.scope_id = src->vb_octets[0];
3320 dst->vb_ip.prefix = src->vb_octets[1];
3321 memcpy(&dst->vb_ipv6addr, src->vb_octets + 2, sizeof(dst->vb_ipv6addr));
3322 break;
3323
3324 default:
3325 return fr_value_box_cast_unsupported(dst_type, src->type);
3326 }
3327 return 0;
3328}
3329
3330/** Convert any supported type to an ethernet address
3331 *
3332 * Allowed input types are:
3333 * - FR_TYPE_STRING ("00:11:22:33:44:55")
3334 * - FR_TYPE_OCTETS (0x001122334455)
3335 *
3336 *
3337 * @param ctx unused.
3338 * @param dst Where to write result of casting.
3339 * @param dst_type to cast to.
3340 * @param dst_enumv enumeration values.
3341 * @param src Input data.
3342 */
3343static inline int fr_value_box_cast_to_ethernet(TALLOC_CTX *ctx, fr_value_box_t *dst,
3344 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3345 fr_value_box_t const *src)
3346{
3347 fr_assert(dst_type == FR_TYPE_ETHERNET);
3349
3350 switch (src->type) {
3351 case FR_TYPE_STRING:
3352 if (fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3353 src->vb_strvalue, src->vb_length,
3354 NULL) < 0) {
3355 return -1;
3356 }
3357 return 0;
3358
3359 case FR_TYPE_OCTETS:
3360 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
3361
3362 default:
3363 break;
3364 }
3365
3366 /*
3367 * Pre-initialise box for non-variable types
3368 */
3369 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3370
3371 switch (src->type) {
3372 case FR_TYPE_UINT64: {
3373 uint8_t array[8];
3374
3375 fr_nbo_from_uint64(array, src->vb_uint64);
3376
3377 /*
3378 * For OUIs in the DB.
3379 */
3380 if ((array[0] != 0) || (array[1] != 0)) return -1;
3381
3382 memcpy(dst->vb_ether, &array[2], 6);
3383 break;
3384 }
3385
3386 default:
3387 return fr_value_box_cast_unsupported(dst_type, src->type);
3388 }
3389
3390 return 0;
3391}
3392
3393/** Convert any supported type to a bool
3394 *
3395 * Allowed input types are:
3396 * - FR_TYPE_STRING ("yes", "true", "no", "false")
3397 *
3398 * @param ctx unused.
3399 * @param dst Where to write result of casting.
3400 * @param dst_type to cast to.
3401 * @param dst_enumv enumeration values.
3402 * @param src Input data.
3403 */
3404static inline int fr_value_box_cast_to_bool(TALLOC_CTX *ctx, fr_value_box_t *dst,
3405 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3406 fr_value_box_t const *src)
3407{
3408 fr_assert(dst_type == FR_TYPE_BOOL);
3410
3411 switch (src->type) {
3412 case FR_TYPE_STRING:
3413 if (fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3414 src->vb_strvalue, src->vb_length,
3415 NULL) < 0) {
3416 return -1;
3417 }
3418 return 0;
3419
3420 case FR_TYPE_OCTETS:
3421 /*
3422 * This is really "bool from network"
3423 */
3424 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
3425
3426 default:
3427 break;
3428 }
3429
3430 /*
3431 * Pre-initialise box for non-variable types
3432 */
3433 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3434
3435 switch (src->type) {
3436 case FR_TYPE_INT8:
3437 dst->vb_bool = (src->vb_int8 != 0);
3438 break;
3439
3440 case FR_TYPE_UINT8:
3441 dst->vb_bool = (src->vb_uint8 != 0);
3442 break;
3443
3444 case FR_TYPE_INT16:
3445 dst->vb_bool = (src->vb_int16 != 0);
3446 break;
3447
3448 case FR_TYPE_UINT16:
3449 dst->vb_bool = (src->vb_uint16 != 0);
3450 break;
3451
3452 case FR_TYPE_INT32:
3453 dst->vb_bool = (src->vb_int32 != 0);
3454 break;
3455
3456 case FR_TYPE_UINT32:
3457 dst->vb_bool = (src->vb_uint32 != 0);
3458 break;
3459
3460 case FR_TYPE_INT64:
3461 dst->vb_bool = (src->vb_int64 != 0);
3462 break;
3463
3464 case FR_TYPE_UINT64:
3465 dst->vb_bool = (src->vb_uint64 != 0);
3466 break;
3467
3468 case FR_TYPE_SIZE:
3469 dst->vb_bool = (src->vb_size != 0);
3470 break;
3471
3472 case FR_TYPE_TIME_DELTA:
3473 dst->vb_bool = (fr_time_delta_unwrap(src->vb_time_delta) != 0);
3474 break;
3475
3476 case FR_TYPE_FLOAT32:
3477 dst->vb_bool = (fpclassify(src->vb_float32) != FP_ZERO);
3478 break;
3479
3480 case FR_TYPE_FLOAT64:
3481 dst->vb_bool = (fpclassify(src->vb_float64) != FP_ZERO);
3482 break;
3483
3484 default:
3485 return fr_value_box_cast_unsupported(dst_type, src->type);
3486 }
3487
3488 return 0;
3489}
3490
3491/** Convert any signed or unsigned integer type to any other signed or unsigned integer type
3492 *
3493 */
3494static inline int fr_value_box_cast_integer_to_integer(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst,
3495 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3496 fr_value_box_t const *src)
3497{
3498 uint64_t tmp = 0;
3499 size_t len = fr_value_box_field_sizes[src->type];
3500 int64_t min;
3501
3503
3504#define SIGN_BIT_HIGH(_int, _len) ((((uint64_t)1) << (((_len) << 3) - 1)) & (_int))
3505#define SIGN_PROMOTE(_int, _len) ((_len) < sizeof(_int) ? \
3506 (_int) | (~((__typeof__(_int))0)) << ((_len) << 3) : (_int))
3507
3508#if !defined(NDEBUG) || defined(STATIC_ANALYZER)
3509 /*
3510 * Helps catch invalid fr_value_box_field_sizes
3511 * entries, and shuts up clang analyzer.
3512 */
3513 if (!fr_cond_assert_msg(len > 0, "Invalid cast from %s to %s. "
3514 "invalid source type len, expected > 0, got %zu",
3515 fr_type_to_str(src->type),
3516 fr_type_to_str(dst_type),
3517 len)) return -1;
3518
3519 if (!fr_cond_assert_msg(len <= sizeof(uint64_t),
3520 "Invalid cast from %s to %s. "
3521 "invalid source type len, expected <= %zu, got %zu",
3522 fr_type_to_str(src->type),
3523 fr_type_to_str(dst_type),
3524 sizeof(uint64_t), len)) return -1;
3525#endif
3526
3527 switch (src->type) {
3528 /*
3529 * Dates are always represented in nanoseconds
3530 * internally, but when we convert to another
3531 * integer type, we scale appropriately.
3532 *
3533 * i.e. if the attribute value resolution is
3534 * seconds, then the integer value is
3535 * nanoseconds -> seconds.
3536 */
3537 case FR_TYPE_DATE:
3538 {
3540 if (src->enumv) res = (fr_time_res_t)src->enumv->flags.flag_time_res;
3541
3542 tmp = fr_unix_time_to_integer(src->vb_date, res);
3543 }
3544 break;
3545
3546 /*
3547 * Same deal with time deltas. Note that
3548 * even though we store the value as an
3549 * unsigned integer, it'll be cast to a
3550 * signed integer for comparisons.
3551 */
3552 case FR_TYPE_TIME_DELTA:
3553 {
3555
3556 if (src->enumv) res = (fr_time_res_t)src->enumv->flags.flag_time_res;
3557
3558 tmp = (uint64_t)fr_time_delta_to_integer(src->vb_time_delta, res);
3559 }
3560 break;
3561
3562 default:
3563#ifdef WORDS_BIGENDIAN
3564 memcpy(((uint8_t *)&tmp) + (sizeof(tmp) - len),
3565 fr_value_box_raw(src, src->type), len);
3566#else
3567 memcpy(&tmp, fr_value_box_raw(src, src->type), len);
3568#endif
3569 break;
3570 }
3571
3572 min = fr_value_box_integer_min[dst_type];
3573
3574 /*
3575 * Sign promote the input if the source type is
3576 * signed, and the high bit is set.
3577 */
3578 if (fr_value_box_integer_min[src->type] < 0) {
3579 if (SIGN_BIT_HIGH(tmp, len)) tmp = SIGN_PROMOTE(tmp, len);
3580
3581 if ((int64_t)tmp < min) {
3582 fr_strerror_printf("Invalid cast from %s to %s. %"PRId64" "
3583 "outside value range %"PRId64"-%"PRIu64,
3584 fr_type_to_str(src->type),
3585 fr_type_to_str(dst_type),
3586 (int64_t)tmp,
3587 min, fr_value_box_integer_max[dst_type]);
3588 return -1;
3589 }
3590 } else if (tmp > fr_value_box_integer_max[dst_type]) {
3591 fr_strerror_printf("Invalid cast from %s to %s. %"PRIu64" "
3592 "outside value range 0-%"PRIu64,
3593 fr_type_to_str(src->type),
3594 fr_type_to_str(dst_type),
3595 tmp, fr_value_box_integer_max[dst_type]);
3596 return -1;
3597 }
3598
3599 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3600 switch (dst_type) {
3601 case FR_TYPE_DATE:
3602 {
3603 bool overflow;
3605 if (dst->enumv) res = (fr_time_res_t)dst->enumv->flags.flag_time_res;
3606
3607 dst->vb_date = fr_unix_time_from_integer(&overflow, tmp, res);
3608 if (overflow) {
3609 fr_strerror_const("Input to date type would overflow");
3610 return -1;
3611 }
3612 }
3613 break;
3614
3615 case FR_TYPE_TIME_DELTA:
3616 {
3617 bool overflow;
3619 if (dst->enumv) res = (fr_time_res_t)dst->enumv->flags.flag_time_res;
3620
3621 dst->vb_time_delta = fr_time_delta_from_integer(&overflow, tmp, res);
3622 if (overflow) {
3623 fr_strerror_const("Input to time_delta type would overflow");
3624 return -1;
3625 }
3626 }
3627 break;
3628
3629 default:
3630#ifdef WORDS_BIGENDIAN
3631 memcpy(fr_value_box_raw(dst, dst->type),
3632 ((uint8_t *)&tmp) + (sizeof(tmp) - len), fr_value_box_field_sizes[dst_type]);
3633#else
3634 memcpy(fr_value_box_raw(dst, dst->type),
3635 &tmp, fr_value_box_field_sizes[dst_type]);
3636#endif
3637 break;
3638 }
3639
3640 return 0;
3641}
3642
3643/** Check whether a floating point value is above the range of an integer type
3644 *
3645 * The maximum of a 64-bit integer type is not representable as a double. The conversion
3646 * rounds UINT64_MAX up to 2^64, and INT64_MAX up to 2^63. A source equal to the rounded
3647 * maximum passes a "greater than the maximum" test, and converting that source to the
3648 * integer type is undefined. Adding 1.0 to a rounded maximum leaves the maximum unchanged,
3649 * and the second test catches the source which equals the maximum. For the narrower types,
3650 * the maximum converts exactly, and the second test adds nothing to the first.
3651 *
3652 * @param[in] f The value to check.
3653 * @param[in] dst_type The integer type the value is cast to.
3654 * @return
3655 * - true if the value does not fit in dst_type.
3656 * - false if the value fits.
3657 */
3658static inline CC_HINT(always_inline) bool value_box_float_overflows(double f, fr_type_t dst_type)
3659{
3660 double max = (double) fr_value_box_integer_max[dst_type];
3661
3662 return (f > max) || (f >= max + 1.0);
3663}
3664
3665/** Convert any value to a signed or unsigned integer
3666 *
3667 * @param ctx unused.
3668 * @param dst Where to write result of casting.
3669 * @param dst_type to cast to.
3670 * @param dst_enumv enumeration values.
3671 * @param src Input data.
3672 */
3673static inline int fr_value_box_cast_to_integer(TALLOC_CTX *ctx, fr_value_box_t *dst,
3674 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3675 fr_value_box_t const *src)
3676{
3677 switch (src->type) {
3678 case FR_TYPE_STRING:
3679 if (fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3680 src->vb_strvalue, src->vb_length,
3681 NULL) < 0) {
3682 return -1;
3683 }
3684 return 0;
3685
3686 case FR_TYPE_OCTETS:
3687 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
3688
3689 case FR_TYPE_INTEGER:
3690 fr_value_box_init(dst, dst_type, dst_enumv, false);
3691 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, src);
3692
3693 case FR_TYPE_IPV4_ADDR:
3695 {
3696 fr_value_box_t tmp;
3697
3698 switch (dst_type) {
3699 case FR_TYPE_UINT32:
3700 case FR_TYPE_INT64:
3701 case FR_TYPE_UINT64:
3702 case FR_TYPE_DATE:
3703 case FR_TYPE_TIME_DELTA:
3704 break;
3705
3706 default:
3707 goto bad_cast;
3708 }
3709
3710 fr_value_box_init(&tmp, FR_TYPE_UINT32, src->enumv, src->tainted);
3711 memcpy(&tmp.vb_uint32, &src->vb_ip.addr.v4, sizeof(tmp.vb_uint32));
3712 fr_value_box_hton(&tmp, &tmp);
3713 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, &tmp);
3714 }
3715
3716 case FR_TYPE_ETHERNET:
3717 {
3718 fr_value_box_t tmp;
3719
3720 switch (dst_type) {
3721 case FR_TYPE_INT64:
3722 case FR_TYPE_UINT64:
3723 case FR_TYPE_DATE:
3724 case FR_TYPE_TIME_DELTA:
3725 break;
3726
3727 default:
3728 goto bad_cast;
3729 }
3730
3731 fr_value_box_init(&tmp, FR_TYPE_UINT64, src->enumv, src->tainted);
3732 memcpy(((uint8_t *)&tmp.vb_uint64) + (sizeof(tmp.vb_uint64) - sizeof(src->vb_ether)),
3733 &src->vb_ether, sizeof(src->vb_ether));
3734#ifndef WORDS_BIGENDIAN
3735 /*
3736 * Ethernet addresses are always stored bigendian,
3737 * convert to native on little endian systems
3738 */
3739 fr_value_box_hton(&tmp, &tmp);
3740#endif
3741 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, &tmp);
3742 }
3743
3744 case FR_TYPE_IFID:
3745 {
3746 switch (dst_type) {
3747 case FR_TYPE_UINT64:
3748 break;
3749
3750 default:
3751 goto bad_cast;
3752 }
3753
3754 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3755 dst->vb_uint64 = fr_nbo_to_uint64(&src->vb_ifid[0]);
3756 return 0;
3757 }
3758
3759 case FR_TYPE_FLOAT32:
3760 if ((double) src->vb_float32 < (double) fr_value_box_integer_min[dst_type]) {
3761 underflow:
3762 fr_strerror_const("Source value for cast would underflow destination type");
3763 return -1;
3764 }
3765
3766 if (value_box_float_overflows((double) src->vb_float32, dst_type)) {
3767 overflow:
3768 fr_strerror_const("Source value for cast would overflow destination type");
3769 return -1;
3770 }
3771
3772 switch (dst_type) {
3773 case FR_TYPE_UINT8:
3774 dst->vb_uint8 = (uint8_t) src->vb_float32;
3775 break;
3776
3777 case FR_TYPE_UINT16:
3778 dst->vb_uint16 = (uint16_t) src->vb_float32;
3779 break;
3780
3781 case FR_TYPE_UINT32:
3782 dst->vb_uint32 = (uint32_t) src->vb_float32;
3783 break;
3784
3785 case FR_TYPE_UINT64:
3786 dst->vb_uint64 = (uint64_t) src->vb_float32;
3787 break;
3788
3789 case FR_TYPE_INT8:
3790 dst->vb_int8 = (int8_t) src->vb_float32;
3791 break;
3792
3793 case FR_TYPE_INT16:
3794 dst->vb_int16 = (int16_t) src->vb_float32;
3795 break;
3796
3797 case FR_TYPE_INT32:
3798 dst->vb_int32 = (int32_t) src->vb_float32;
3799 break;
3800
3801 case FR_TYPE_INT64:
3802 dst->vb_int64 = (int64_t) src->vb_float32;
3803 break;
3804
3805 case FR_TYPE_SIZE:
3806 dst->vb_size = (size_t) src->vb_float32;
3807 break;
3808
3809 case FR_TYPE_DATE: {
3810 int64_t sec, nsec;
3811
3812 /*
3813 * A date is int64_t nanoseconds. The check runs on the float,
3814 * before any conversion, and leaves room for the fraction.
3815 */
3816 if (unlikely((double) src->vb_float32 >= (double) (INT64_MAX / NSEC))) goto overflow;
3817
3818 sec = (int64_t) src->vb_float32;
3819 sec *= NSEC;
3820 nsec = (int64_t) ((src->vb_float32 * NSEC) - ((float) sec));
3821
3822 dst->vb_date = fr_unix_time_from_nsec(sec + nsec);
3823 }
3824 break;
3825
3826 case FR_TYPE_TIME_DELTA: {
3827 int64_t sec, nsec;
3828 int64_t res = NSEC;
3829 bool fail = false;
3830
3831 if (dst->enumv) res = fr_time_multiplier_by_res[(fr_time_res_t)dst->enumv->flags.flag_time_res];
3832
3833 sec = (int64_t) src->vb_float32;
3834 sec *= res;
3835 nsec = (int64_t) (((double) src->vb_float32 * (double) res) - ((double) sec));
3836
3837 dst->vb_time_delta = fr_time_delta_from_integer(&fail, sec + nsec,
3838 dst->enumv ? (fr_time_res_t)dst->enumv->flags.flag_time_res : FR_TIME_RES_NSEC);
3839 if (fail) goto overflow;
3840 }
3841 break;
3842
3843 default:
3844 goto bad_cast;
3845 }
3846 return 0;
3847
3848 case FR_TYPE_FLOAT64:
3849 if (src->vb_float64 < (double) fr_value_box_integer_min[dst_type]) goto underflow;
3850
3851 if (value_box_float_overflows(src->vb_float64, dst_type)) goto overflow;
3852
3853 switch (dst_type) {
3854 case FR_TYPE_UINT8:
3855 dst->vb_uint8 = (uint8_t) src->vb_float64;
3856 break;
3857
3858 case FR_TYPE_UINT16:
3859 dst->vb_uint16 = (uint16_t) src->vb_float64;
3860 break;
3861
3862 case FR_TYPE_UINT32:
3863 dst->vb_uint32 = (uint32_t) src->vb_float64;
3864 break;
3865
3866 case FR_TYPE_UINT64:
3867 dst->vb_uint64 = (uint64_t) src->vb_float64;
3868 break;
3869
3870 case FR_TYPE_INT8:
3871 dst->vb_int8 = (int8_t) src->vb_float64;
3872 break;
3873
3874 case FR_TYPE_INT16:
3875 dst->vb_int16 = (int16_t) src->vb_float64;
3876 break;
3877
3878 case FR_TYPE_INT32:
3879 dst->vb_int32 = (int32_t) src->vb_float64;
3880 break;
3881
3882 case FR_TYPE_INT64:
3883 dst->vb_int64 = (int64_t) src->vb_float64;
3884 break;
3885
3886 case FR_TYPE_SIZE:
3887 dst->vb_size = (size_t) src->vb_float64;
3888 break;
3889
3890 case FR_TYPE_DATE: {
3891 int64_t sec, nsec;
3892
3893 /*
3894 * A date is int64_t nanoseconds. The check runs on the double,
3895 * before any conversion, and leaves room for the fraction.
3896 */
3897 if (unlikely(src->vb_float64 >= (double) (INT64_MAX / NSEC))) goto overflow;
3898
3899 sec = (int64_t) src->vb_float64;
3900 sec *= NSEC;
3901 nsec = (int64_t) ((src->vb_float64 * NSEC) - ((double) sec));
3902
3903 dst->vb_date = fr_unix_time_from_nsec(sec + nsec);
3904 }
3905 break;
3906
3907 case FR_TYPE_TIME_DELTA: {
3908 int64_t sec, nsec;
3909 int64_t res = NSEC;
3910 bool fail = false;
3911
3912 if (dst->enumv) res = fr_time_multiplier_by_res[(fr_time_res_t)dst->enumv->flags.flag_time_res];
3913
3914 sec = (int64_t) src->vb_float64;
3915
3916 if (unlikely((sec > INT64_MAX / res) || (sec < INT64_MIN / res))) goto overflow;
3917 sec *= res;
3918 nsec = (int64_t) ((src->vb_float64 * (double) res) - ((double) sec));
3919
3920 dst->vb_time_delta = fr_time_delta_from_integer(&fail, sec + nsec,
3921 dst->enumv ? (fr_time_res_t)dst->enumv->flags.flag_time_res : FR_TIME_RES_NSEC);
3922 if (fail) goto overflow;
3923 }
3924 break;
3925
3926 default:
3927 goto bad_cast;
3928 }
3929 return 0;
3930
3931 default:
3932 break;
3933 }
3934
3935bad_cast:
3936 return fr_value_box_cast_unsupported(dst_type, src->type);
3937}
3938
3939/** Convert any value to a floating point value
3940 *
3941 * @param ctx unused.
3942 * @param dst Where to write result of casting.
3943 * @param dst_type to cast to.
3944 * @param dst_enumv enumeration values.
3945 * @param src Input data.
3946 */
3947static inline int fr_value_box_cast_to_float(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst,
3948 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3949 fr_value_box_t const *src)
3950{
3951 double num;
3952
3953 switch (src->type) {
3954 case FR_TYPE_FLOAT32:
3955 if (dst_type == FR_TYPE_FLOAT64) {
3956 num = (double) src->vb_float32;
3957 goto good_cast;
3958 }
3959
3960 goto bad_cast;
3961
3962 case FR_TYPE_FLOAT64:
3963 if (dst_type == FR_TYPE_FLOAT32) {
3964 num = src->vb_float64;
3965 goto good_cast;
3966 }
3967
3968 goto bad_cast;
3969
3970 case FR_TYPE_BOOL:
3971 num = src->vb_bool;
3972 goto good_cast;
3973
3974 case FR_TYPE_INT8:
3975 num = src->vb_int8;
3976 goto good_cast;
3977
3978 case FR_TYPE_INT16:
3979 num = src->vb_int16;
3980 goto good_cast;
3981
3982 case FR_TYPE_INT32:
3983 num = src->vb_int32;
3984 goto good_cast;
3985
3986 case FR_TYPE_INT64:
3987 num = (double) src->vb_int64;
3988 goto good_cast;
3989
3990 case FR_TYPE_UINT8:
3991 num = src->vb_uint8;
3992 goto good_cast;
3993
3994 case FR_TYPE_UINT16:
3995 num = src->vb_uint16;
3996 goto good_cast;
3997
3998 case FR_TYPE_UINT32:
3999 num = src->vb_uint32;
4000 goto good_cast;
4001
4002 case FR_TYPE_UINT64:
4003 num = (double) src->vb_uint64;
4004 goto good_cast;
4005
4006 case FR_TYPE_DATE:
4007 /*
4008 * Unix times are in nanoseconds
4009 */
4010 num = fr_unix_time_to_sec_double(src->vb_date);
4011 goto good_cast;
4012
4013 case FR_TYPE_TIME_DELTA:
4014 {
4015 /*
4016 * Time deltas are in nanoseconds, but scaled.
4017 */
4018 int64_t nsec = fr_time_delta_unwrap(src->vb_time_delta);
4019
4020 num = (double) nsec;
4021 if (src->enumv) {
4022 num /= (double) fr_time_multiplier_by_res[(fr_time_res_t)src->enumv->flags.flag_time_res];
4023 } else {
4024 num /= NSEC;
4025 }
4026 goto good_cast;
4027 }
4028
4029 case FR_TYPE_SIZE:
4030 num = (double) src->vb_size;
4031
4032 good_cast:
4033 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
4035
4036 if (dst_type == FR_TYPE_FLOAT32) {
4037 dst->vb_float32 = num;
4038 } else {
4039 dst->vb_float64 = num;
4040 }
4041 return 0;
4042
4043 default:
4044 break;
4045 }
4046
4047bad_cast:
4048 return fr_value_box_cast_unsupported(dst_type, src->type);
4049}
4050
4051
4052/** Convert one type of fr_value_box_t to another
4053 *
4054 * This should be the canonical function used to convert between INTERNAL data formats.
4055 *
4056 * If you want to convert from PRESENTATION format, use #fr_value_box_from_substr.
4057 *
4058 * @note src and dst must not be the same box. We do not support casting in place.
4059 *
4060 * @param ctx to allocate buffers in (usually the same as dst)
4061 * @param dst Where to write result of casting.
4062 * @param dst_type to cast to.
4063 * @param dst_enumv Aliases for values contained within this fr_value_box_t.
4064 * If #fr_value_box_t is passed to #fr_value_box_aprint
4065 * names will be printed instead of actual value.
4066 * @param src Input data.
4067 * @return
4068 * - 0 on success.
4069 * - -1 on failure.
4070 */
4071int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst,
4072 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
4073 fr_value_box_t const *src)
4074{
4075 if (!fr_cond_assert(src != dst)) return -1;
4076
4077 if (fr_type_is_non_leaf(dst_type)) {
4078 fr_strerror_printf("Invalid cast from %s to %s. Can only cast simple data types",
4079 fr_type_to_str(src->type),
4080 fr_type_to_str(dst_type));
4081 return -1;
4082 }
4083
4084 /*
4085 * If it's the same type, copy, but set the enumv
4086 * in the destination box to be the one provided.
4087 *
4088 * The theory here is that the attribute value isn't
4089 * being converted into its presentation format and
4090 * re-parsed, and the enumv names only get applied
4091 * when converting internal values to/from strings,
4092 * so it's OK just to swap out the enumv.
4093 *
4094 * If there's a compelling case in the future we
4095 * might revisit this, but it'd likely mean fixing
4096 * all the casting functions to treat any value
4097 * with an enumv as a string, which seems weird.
4098 */
4099 if (dst_type == src->type) {
4100 int ret;
4101
4102 ret = fr_value_box_copy(ctx, dst, src);
4103 if (ret < 0) return ret;
4104
4105 if (dst_enumv) dst->enumv = dst_enumv;
4106
4107 return ret;
4108 }
4109
4110 /*
4111 * Initialise dst
4112 */
4113 fr_value_box_init(dst, dst_type, NULL, src->tainted);
4114
4115 /*
4116 * Dispatch to specialised cast functions
4117 */
4118 switch (dst_type) {
4119 case FR_TYPE_STRING:
4120 return fr_value_box_cast_to_strvalue(ctx, dst, dst_type, dst_enumv, src);
4121
4122 case FR_TYPE_OCTETS:
4123 return fr_value_box_cast_to_octets(ctx, dst, dst_type, dst_enumv, src);
4124
4125 case FR_TYPE_IPV4_ADDR:
4126 return fr_value_box_cast_to_ipv4addr(ctx, dst, dst_type, dst_enumv, src);
4127
4129 return fr_value_box_cast_to_ipv4prefix(ctx, dst, dst_type, dst_enumv, src);
4130
4131 case FR_TYPE_IPV6_ADDR:
4132 return fr_value_box_cast_to_ipv6addr(ctx, dst, dst_type, dst_enumv, src);
4133
4135 return fr_value_box_cast_to_ipv6prefix(ctx, dst, dst_type, dst_enumv, src);
4136
4139 break;
4140 /*
4141 * Need func
4142 */
4143 case FR_TYPE_IFID:
4144 break;
4145
4146 case FR_TYPE_ETHERNET:
4147 return fr_value_box_cast_to_ethernet(ctx, dst, dst_type, dst_enumv, src);
4148
4149 case FR_TYPE_BOOL:
4150 return fr_value_box_cast_to_bool(ctx, dst, dst_type, dst_enumv, src);
4151
4152 case FR_TYPE_DATE:
4153 if (src->type != FR_TYPE_TIME_DELTA) return fr_value_box_cast_to_integer(ctx, dst, dst_type, dst_enumv, src);
4154
4155 if (fr_time_delta_isneg(src->vb_time_delta)) {
4156 fr_strerror_const("Input to data type would underflow");
4157 return -1;
4158 }
4159
4161 dst->enumv = dst_enumv;
4162 dst->vb_date = fr_unix_time_wrap(fr_time_delta_unwrap(src->vb_time_delta));
4163 return 0;
4164
4165 case FR_TYPE_TIME_DELTA:
4166 /*
4167 * Unix time cast to time_delta is just nanoseconds since the epoch.
4168 *
4169 * Note that we do NOT change time resolution, but we DO change enumv. Both unix time
4170 * and time_delta are tracked internally as nanoseconds, and the only use of precision is
4171 * for printing / parsing.
4172 */
4173 if (src->type == FR_TYPE_DATE) {
4174 uint64_t when;
4175
4176 when = fr_unix_time_unwrap(src->vb_date);
4177 if (when > INT64_MAX) {
4178 fr_strerror_const("Input to data type would overflow");
4179 return -1;
4180 }
4181
4183 dst->enumv = dst_enumv;
4184 dst->vb_time_delta = fr_time_delta_wrap((int64_t) when);
4185 return 0;
4186 }
4188
4189 case FR_TYPE_UINT8:
4190 case FR_TYPE_UINT16:
4191 case FR_TYPE_UINT32:
4192 case FR_TYPE_UINT64:
4193 case FR_TYPE_INT8:
4194 case FR_TYPE_INT16:
4195 case FR_TYPE_INT32:
4196 case FR_TYPE_INT64:
4197 case FR_TYPE_SIZE:
4198 return fr_value_box_cast_to_integer(ctx, dst, dst_type, dst_enumv, src);
4199
4200 case FR_TYPE_FLOAT32:
4201 case FR_TYPE_FLOAT64:
4202 if (fr_type_is_fixed_size(src->type)) {
4203 return fr_value_box_cast_to_float(ctx, dst, dst_type, dst_enumv, src);
4204 }
4205 break; /* use generic string/octets stuff below */
4206
4207#if 0
4208 case FR_TYPE_ATTR:
4209 /*
4210 * Convert it to an integer of the correct length. Then, cast it in place.
4211 */
4212 switch (src->vb_attr->flags.length) {
4213 case 1:
4214 fr_value_box_init(dst, FR_TYPE_UINT8, NULL, false);
4215 dst->vb_uint8 = src->vb_attr->attr;
4216 break;
4217
4218 case 2:
4219 fr_value_box_init(dst, FR_TYPE_UINT16, NULL, false);
4220 dst->vb_uint16 = src->vb_attr->attr;
4221 break;
4222
4223 case 4:
4224 fr_value_box_init(dst, FR_TYPE_UINT32, NULL, false);
4225 dst->vb_uint32 = src->vb_attr->attr;
4226 break;
4227
4228 default:
4229 fr_strerror_printf("Unsupported length '%d' for attribute %s",
4230 src->vb_attr->flags.length, src->vb_attr->name);
4231 return 0;
4232 }
4233
4234 return fr_value_box_cast_in_place(ctx, dst, dst_type, dst_enumv);
4235#else
4236 case FR_TYPE_ATTR:
4237 if (src->type == FR_TYPE_STRING) break;
4238
4240
4241#endif
4242 /*
4243 * Invalid types for casting (were caught earlier)
4244 */
4245 case FR_TYPE_NON_LEAF:
4246 fr_strerror_printf("Invalid cast from %s to %s. Invalid destination type",
4247 fr_type_to_str(src->type),
4248 fr_type_to_str(dst_type));
4249 return -1;
4250 }
4251
4252 /*
4253 * Deserialise a fr_value_box_t
4254 */
4255 if (src->type == FR_TYPE_STRING) {
4256 if (fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
4257 src->vb_strvalue, src->vb_length,
4258 NULL) < 0) {
4259 return -1;
4260 }
4261 return 0;
4262 }
4263
4264 if (src->type == FR_TYPE_OCTETS) {
4265 fr_value_box_t tmp;
4266
4267 if (src->vb_length < network_min_size(dst_type)) {
4268 fr_strerror_printf("Invalid cast from %s to %s. Source is length %zu is smaller than "
4269 "destination type size %zu",
4270 fr_type_to_str(src->type),
4271 fr_type_to_str(dst_type),
4272 src->vb_length,
4273 network_min_size(dst_type));
4274 return -1;
4275 }
4276
4277 if (src->vb_length > network_max_size(dst_type)) {
4278 fr_strerror_printf("Invalid cast from %s to %s. Source length %zu is greater than "
4279 "destination type size %zu",
4280 fr_type_to_str(src->type),
4281 fr_type_to_str(dst_type),
4282 src->vb_length,
4283 network_max_size(dst_type));
4284 return -1;
4285 }
4286
4287 fr_value_box_init(&tmp, dst_type, NULL, false);
4288
4289 /*
4290 * Copy the raw octets into the datum of a value_box
4291 * inverting bytesex for uint32s (if LE).
4292 */
4293 memcpy(&tmp.datum, src->vb_octets, fr_value_box_field_sizes[dst_type]);
4294 tmp.type = dst_type;
4295 dst->enumv = dst_enumv;
4296
4297 fr_value_box_hton(dst, &tmp);
4298 fr_value_box_safety_copy(dst, src);
4299 return 0;
4300 }
4301
4302 memcpy(&dst->datum, &src->datum, fr_value_box_field_sizes[src->type]);
4303
4305 dst->enumv = dst_enumv;
4306
4307 return 0;
4308}
4309
4310/** Convert one type of fr_value_box_t to another in place
4311 *
4312 * This should be the canonical function used to convert between INTERNAL data formats.
4313 *
4314 * If you want to convert from PRESENTATION format, use #fr_value_box_from_substr.
4315 *
4316 * @param ctx to allocate buffers in (usually the same as dst)
4317 * @param vb to cast.
4318 * @param dst_type to cast to.
4319 * @param dst_enumv Aliases for values contained within this fr_value_box_t.
4320 * If #fr_value_box_t is passed to #fr_value_box_aprint
4321 * names will be printed instead of actual value.
4322 * @return
4323 * - 0 on success.
4324 * - -1 on failure.
4325 */
4327 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
4328{
4329 fr_value_box_t tmp;
4330 /*
4331 * Store list pointers to restore later - fr_value_box_cast clears them
4332 */
4333 fr_value_box_entry_t entry = vb->entry;
4334
4335 /*
4336 * Simple case, destination type and current
4337 * type are the same.
4338 */
4339 if (vb->type == dst_type) {
4340 vb->enumv = dst_enumv; /* Update the enumv as this may be different */
4341 return 0;
4342 }
4343
4344 /*
4345 * Copy meta data and any existing buffers to
4346 * a temporary box. We then clear that value
4347 * box after the cast has been completed,
4348 * freeing any old buffers.
4349 */
4350 fr_value_box_copy_shallow(NULL, &tmp, vb);
4351
4352 if (fr_value_box_cast(ctx, vb, dst_type, dst_enumv, &tmp) < 0) {
4353 /*
4354 * On error, make sure the original
4355 * box is left in a consistent state.
4356 */
4357 fr_value_box_copy_shallow(NULL, vb, &tmp);
4358 vb->entry = entry;
4359 return -1;
4360 }
4361 fr_value_box_clear_value(&tmp); /* Clear out any old buffers */
4362
4363 /*
4364 * Restore list pointers
4365 */
4366 vb->entry = entry;
4367
4368 return 0;
4369}
4370
4371/** Return a uint64_t from a #fr_value_box_t
4372 *
4373 * @param[in] vb the value-box. Must be an unsigned integer data type.
4374 * @return the value as uint64_t.
4375 */
4377{
4378#undef O
4379#define O(_x, _y) case FR_TYPE_##_x: return vb->vb_##_y
4380
4381
4382 switch (vb->type) {
4383 O(BOOL, bool);
4384 O(UINT8, uint8);
4385 O(UINT16, uint16);
4386 O(UINT32, uint32);
4387 O(UINT64, uint64);
4388 O(SIZE, size);
4389
4390 default:
4391 fr_assert(0);
4392 return 0;
4393 }
4394}
4395
4396
4397/** Assign a #fr_value_box_t value from an #fr_ipaddr_t
4398 *
4399 * Automatically determines the type of the value box from the ipaddr address family
4400 * and the length of the prefix field.
4401 *
4402 * @param[in] dst to assign ipaddr to.
4403 * @param[in] enumv Aliases for values.
4404 * @param[in] ipaddr to copy address from.
4405 * @param[in] tainted Whether the value came from a trusted source.
4406 * @return
4407 * - 0 on success.
4408 * - -1 on failure.
4409 */
4410int fr_value_box_ipaddr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, fr_ipaddr_t const *ipaddr, bool tainted)
4411{
4413
4414 switch (ipaddr->af) {
4415 case AF_INET:
4417 break;
4418
4419 case AF_INET6:
4421 break;
4422
4423 default:
4424 fr_strerror_printf("Invalid address family %i", ipaddr->af);
4425 return -1;
4426 }
4427
4428 fr_value_box_init(dst, type, enumv, tainted);
4429 memcpy(&dst->vb_ip, ipaddr, sizeof(dst->vb_ip));
4430
4431 return 0;
4432}
4433
4434/** Unbox an IP address performing a type check
4435 *
4436 * @param[out] dst Where to copy the IP address to.
4437 * @param[in] src Where to copy the IP address from.
4438 * @return
4439 * - 0 on success.
4440 * - -1 on type mismatch.
4441 */
4443{
4444 if (!fr_type_is_ip(src->type)) {
4445 fr_strerror_printf("Unboxing failed. Needed IPv4/6 addr/prefix, had type %s",
4446 fr_type_to_str(src->type));
4447 return -1;
4448 }
4449
4450 memcpy(dst, &src->vb_ip, sizeof(*dst));
4451
4452 return 0;
4453}
4454
4455/** Clear/free any existing value
4456 *
4457 * @note Do not use on uninitialised memory.
4458 *
4459 * @param[in] data to clear.
4460 */
4462{
4464
4465 switch (data->type) {
4466 case FR_TYPE_OCTETS:
4467 case FR_TYPE_STRING:
4468 if (data->vb_secret) memset_explicit(data->datum.ptr, 0, data->vb_length);
4469 talloc_free(data->datum.ptr);
4470 break;
4471
4472 case FR_TYPE_GROUP:
4473 /*
4474 * Depth first freeing of children
4475 *
4476 * This ensures orderly freeing, regardless
4477 * of talloc hierarchy.
4478 */
4479 {
4480 fr_value_box_t *vb;
4481
4482 while ((vb = fr_value_box_list_pop_head(&data->vb_group)) != NULL) {
4484 talloc_free(vb);
4485 }
4486 }
4487 return;
4488
4489 case FR_TYPE_NULL:
4490 break;
4491
4493 talloc_free(data->vb_cursor);
4494 break;
4495
4496 default:
4497 break;
4498 }
4499
4500 memset(&data->datum, 0, sizeof(data->datum));
4501}
4502
4503/** Clear/free any existing value and metadata
4504 *
4505 * @note Do not use on uninitialised memory.
4506 *
4507 * @param[in] data to clear.
4508 */
4514
4515/** Copy value data verbatim duplicating any buffers
4516 *
4517 * @note Will free any exiting buffers associated with the dst #fr_value_box_t.
4518 *
4519 * @param ctx To allocate buffers in.
4520 * @param dst Where to copy value_box to.
4521 * @param src Where to copy value_box from.
4522 * @return
4523 * - 0 on success.
4524 * - -1 on failure.
4525 */
4526int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
4527{
4528 switch (src->type) {
4529 case FR_TYPE_NUMERIC:
4530 case FR_TYPE_IP:
4531 case FR_TYPE_IFID:
4532 case FR_TYPE_ETHERNET:
4533 fr_value_box_memcpy_out(fr_value_box_raw(dst, src->type), src);
4534 fr_value_box_copy_meta(dst, src);
4535 break;
4536
4537 case FR_TYPE_NULL:
4538 fr_value_box_copy_meta(dst, src);
4539 break;
4540
4541 case FR_TYPE_STRING:
4542 {
4543 char *str = NULL;
4544
4545 /*
4546 * Zero length strings still have a one uint8 buffer
4547 */
4548 str = talloc_bstrndup(ctx, src->vb_strvalue, src->vb_length);
4549 if (!str) {
4550 fr_strerror_const("Failed allocating string buffer");
4551 return -1;
4552 }
4553 dst->vb_strvalue = str;
4554 fr_value_box_copy_meta(dst, src);
4555 }
4556 break;
4557
4558 case FR_TYPE_OCTETS:
4559 {
4560 uint8_t *bin;
4561
4562 if (src->vb_length) {
4563 bin = talloc_memdup(ctx, src->vb_octets, src->vb_length);
4564 if (!bin) {
4565 fr_strerror_const("Failed allocating octets buffer");
4566 return -1;
4567 }
4568 talloc_set_type(bin, uint8_t);
4569 } else {
4570 bin = talloc_array(ctx, uint8_t, 0);
4571 }
4572 dst->vb_octets = bin;
4573 fr_value_box_copy_meta(dst, src);
4574 }
4575 break;
4576
4577 case FR_TYPE_GROUP:
4578 {
4579 fr_value_box_t *child = NULL;
4580
4581 fr_value_box_copy_meta(dst, src); /* Initialises group child dlist */
4582
4583 while ((child = fr_value_box_list_next(&src->vb_group, child))) {
4584 fr_value_box_t *new;
4585
4586 /*
4587 * Build out the child
4588 */
4589 new = fr_value_box_alloc_null(ctx);
4590 if (unlikely(!new)) {
4591 group_error:
4592 fr_strerror_const("Failed duplicating group child");
4593 fr_value_box_list_talloc_free(&dst->vb_group);
4594 return -1;
4595 }
4596
4597 /*
4598 * Populate it with the data from the original child.
4599 *
4600 * We do NOT update the dst safety. The individual boxes have safety. A group
4601 * doesn't.
4602 */
4603 if (unlikely(fr_value_box_copy(new, new, child) < 0)) goto group_error;
4604 fr_value_box_list_insert_tail(&dst->vb_group, new);
4605 }
4606 }
4607 break;
4608
4609 case FR_TYPE_ATTR:
4610 fr_value_box_copy_meta(dst, src);
4611
4612 /* raw also sets is_unknown */
4613 if (src->vb_attr->flags.is_unknown) {
4614 dst->vb_attr = fr_dict_attr_unknown_copy(ctx, src->vb_attr);
4615 if (!dst->vb_attr) return -1;
4616 break;
4617 }
4618 dst->vb_attr = src->vb_attr;
4619 break;
4620
4621 case FR_TYPE_TLV:
4622 case FR_TYPE_STRUCT:
4623 case FR_TYPE_VSA:
4624 case FR_TYPE_VENDOR:
4625 case FR_TYPE_UNION:
4626 case FR_TYPE_VOID:
4627 case FR_TYPE_VALUE_BOX:
4630 case FR_TYPE_MAX:
4631 fr_assert(0);
4632 fr_strerror_printf("Cannot copy data type '%s'", fr_type_to_str(src->type));
4633 return -1;
4634 }
4635
4636 VERIFY_CLEAR(dst);
4637
4638 return 0;
4639}
4640
4641/** Perform a shallow copy of a value_box
4642 *
4643 * Like #fr_value_box_copy, but does not duplicate the buffers of the src value_box.
4644 *
4645 * For #FR_TYPE_STRING and #FR_TYPE_OCTETS adds a reference from ctx so that the
4646 * buffer cannot be freed until the ctx is freed.
4647 *
4648 * @param[in] ctx to add reference from. If NULL no reference will be added.
4649 * @param[in] dst to copy value to.
4650 * @param[in] src to copy value from.
4651 */
4652void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
4653{
4654 switch (src->type) {
4655 default:
4656 if (unlikely(fr_value_box_copy(NULL, dst, src) < 0)) return;
4657 break;
4658
4659 case FR_TYPE_STRING:
4660 case FR_TYPE_OCTETS:
4661 dst->datum.ptr = ctx ? talloc_reference(ctx, src->datum.ptr) : src->datum.ptr;
4662 fr_value_box_copy_meta(dst, src);
4663 break;
4664
4665 case FR_TYPE_ATTR:
4666 dst->vb_attr = src->vb_attr;
4667 fr_value_box_copy_meta(dst, src);
4668 break;
4669
4670 case FR_TYPE_VOID:
4671 dst->vb_void = src->vb_void;
4672 fr_value_box_copy_meta(dst, src);
4673 break;
4674 }
4675
4676 VERIFY_CLEAR(dst);
4677}
4678
4679/** Copy value data verbatim moving any buffers to the specified context
4680 *
4681 * @param[in] ctx to allocate any new buffers in.
4682 * @param[in] dst to copy value to.
4683 * @param[in] src to copy value from.
4684 * @return
4685 * - 0 on success.
4686 * - -1 on failure.
4687 */
4688int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
4689{
4690 VALUE_BOX_VERIFY(src);
4691
4692 switch (src->type) {
4693 default:
4694 return fr_value_box_copy(ctx, dst, src);
4695
4696 case FR_TYPE_STRING:
4697 {
4698 char const *str;
4699
4700 str = talloc_steal(ctx, src->vb_strvalue);
4701 if (!str) {
4702 fr_strerror_const("Failed stealing string buffer");
4703 return -1;
4704 }
4705 talloc_set_type(str, char);
4706 dst->vb_strvalue = str;
4707 fr_value_box_copy_meta(dst, src);
4708 memset(&src->datum, 0, sizeof(src->datum));
4709 }
4710 break;
4711
4712 case FR_TYPE_OCTETS:
4713 {
4714 uint8_t const *bin;
4715
4716 bin = talloc_steal(ctx, src->vb_octets);
4717 if (!bin) {
4718 fr_strerror_const("Failed stealing octets buffer");
4719 return -1;
4720 }
4721 talloc_set_type(bin, uint8_t);
4722
4723 dst->vb_octets = bin;
4724 fr_value_box_copy_meta(dst, src);
4725 memset(&src->datum, 0, sizeof(src->datum));
4726 }
4727 break;
4728
4729 case FR_TYPE_GROUP:
4730 {
4731 fr_value_box_t *child;
4732
4733 while ((child = fr_value_box_list_pop_head(&src->vb_group))) {
4734 child = talloc_steal(ctx, child);
4735 if (unlikely(!child)) {
4736 fr_strerror_const("Failed stealing child");
4737 return -1;
4738 }
4739 fr_value_box_list_insert_tail(&dst->vb_group, child);
4740
4741 VERIFY_CLEAR(child);
4742 }
4743 }
4744 break;
4745 }
4746
4747 VERIFY_CLEAR(dst);
4748
4749 return 0;
4750}
4751
4752/** Copy a nul terminated string to a #fr_value_box_t
4753 *
4754 * @param[in] ctx to allocate any new buffers in.
4755 * @param[in] dst to assign new buffer to.
4756 * @param[in] enumv Aliases for values.
4757 * @param[in] src a nul terminated buffer.
4758 * @param[in] tainted Whether the value came from a trusted source.
4759 * @return
4760 * - 0 on success.
4761 * - -1 on failure.
4762 */
4763int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4764 char const *src, bool tainted)
4765{
4766 char const *str;
4767
4768 str = talloc_strdup(ctx, src);
4769 if (!str) {
4770 fr_strerror_const("Failed allocating string buffer");
4771 return -1;
4772 }
4773
4774 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4775 dst->vb_strvalue = str;
4776 dst->vb_length = talloc_strlen(str);
4777
4778 return 0;
4779}
4780
4781/** Trim the length of the string buffer to match the length of the C string
4782 *
4783 * @param[in] ctx to re-alloc the buffer in.
4784 * @param[in,out] vb to trim.
4785 * @return
4786 * - 0 on success.
4787 * - -1 on failure.
4788 */
4789int fr_value_box_strtrim(TALLOC_CTX *ctx, fr_value_box_t *vb)
4790{
4791 size_t len;
4792 char *str;
4793
4794 if (!fr_cond_assert(vb->type == FR_TYPE_STRING)) return -1;
4795
4796 len = strlen(vb->vb_strvalue);
4797 str = talloc_realloc(ctx, UNCONST(char *, vb->vb_strvalue), char, len + 1);
4798 if (!str) {
4799 fr_strerror_const("Failed re-allocing string buffer");
4800 return -1;
4801 }
4802 vb->vb_strvalue = str;
4803 vb->vb_length = len;
4804
4805 return 0;
4806}
4807
4808/** Print a formatted string using our internal printf wrapper and assign it to a value box
4809 *
4810 * @param[in] ctx to allocate any new buffers in.
4811 * @param[in] dst to assign new buffer to.
4812 * @param[in] enumv Aliases for values.
4813 * @param[in] fmt The printf format string to process.
4814 * @param[in] tainted Whether the value came from a trusted source.
4815 * @param[in] ap Substitution arguments.
4816 * @return
4817 * - 0 on success.
4818 * - -1 on failure.
4819 */
4820int fr_value_box_vasprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted,
4821 char const *fmt, va_list ap)
4822{
4823 va_list aq;
4824 char *str;
4825
4826 va_copy(aq, ap); /* See vlog_module_failure_msg for why */
4827 str = fr_vasprintf(ctx, fmt, aq);
4828 va_end(aq);
4829
4830 if (!str) return -1;
4831
4832 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4833 dst->vb_strvalue = str;
4834 dst->vb_length = talloc_strlen(str);
4835
4836 return 0;
4837}
4838
4839/** Print a formatted string using our internal printf wrapper and assign it to a value box
4840 *
4841 * @param[in] ctx to allocate any new buffers in.
4842 * @param[in] dst to assign new buffer to.
4843 * @param[in] enumv Aliases for values.
4844 * @param[in] tainted Whether the value came from a trusted source.
4845 * @param[in] fmt The printf format string to process.
4846 * @param[in] ... Substitution arguments.
4847 * @return
4848 * - 0 on success.
4849 * - -1 on failure.
4850 */
4851int fr_value_box_asprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted,
4852 char const *fmt, ...)
4853{
4854 va_list ap;
4855 int ret;
4856
4857 va_start(ap, fmt);
4858 ret = fr_value_box_vasprintf(ctx, dst, enumv, tainted, fmt, ap);
4859 va_end(ap);
4860
4861 return ret;
4862}
4863
4864/** Assign a buffer containing a nul terminated string to a box, but don't copy it
4865 *
4866 * @note Input string will not be duplicated.
4867 *
4868 * @param[in] dst to assign string to.
4869 * @param[in] enumv Aliases for values.
4870 * @param[in] src to copy string from.
4871 * @param[in] tainted Whether the value came from a trusted source.
4872 */
4874 char const *src, bool tainted)
4875{
4876 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4877 dst->vb_strvalue = src;
4878 dst->vb_length = strlen(src);
4879}
4880
4881/** Free the existing buffer (if talloced) associated with the valuebox, and replace it with a new one
4882 *
4883 * @note Input string will not be duplicated.
4884 *
4885 * @param[in] vb to replace string in.
4886 * @param[in] src to assign string from.
4887 * @param[in] len of src.
4888 */
4890{
4892 vb->vb_strvalue = src;
4893 vb->vb_length = len < 0 ? strlen(src) : (size_t)len;
4894}
4895
4896/** Free the existing buffer (if talloced) associated with the valuebox, and replace it with a copy of a new one
4897 *
4898 * The box's flags are left as they were. src may alias the existing value,
4899 * the copy is taken before the existing value is freed.
4900 *
4901 * @param[in] ctx to allocate the copy in.
4902 * @param[in] vb to replace string in.
4903 * @param[in] src to copy string from.
4904 * @param[in] len of src. If negative, src must be NUL terminated.
4905 * @return
4906 * - 0 on success.
4907 * - -1 on allocation failure.
4908 */
4909int fr_value_box_bstrndup_replace(TALLOC_CTX *ctx, fr_value_box_t *vb, char const *src, ssize_t len)
4910{
4911 char *str;
4912
4913 if (len < 0) len = strlen(src);
4914
4915 str = talloc_bstrndup(ctx, src, (size_t)len);
4916 if (unlikely(!str)) {
4917 fr_strerror_const("Failed allocating string buffer");
4918 return -1;
4919 }
4920
4922 vb->vb_strvalue = str;
4923 vb->vb_length = (size_t)len;
4924
4925 return 0;
4926}
4927
4928/** Alloc and assign an empty \0 terminated string to a #fr_value_box_t
4929 *
4930 * @param[in] ctx to allocate any new buffers in.
4931 * @param[out] out if non-null where to write a pointer to the new buffer.
4932 * @param[in] dst to assign new buffer to.
4933 * @param[in] enumv Aliases for values.
4934 * @param[in] len of buffer to allocate.
4935 * @param[in] tainted Whether the value came from a trusted source.
4936 * @return
4937 * - 0 on success.
4938 * - -1 on failure.
4939 */
4940int fr_value_box_bstr_alloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4941 size_t len, bool tainted)
4942{
4943 char *str;
4944
4945 str = talloc_zero_array(ctx, char, len + 1);
4946 if (!str) {
4947 fr_strerror_const("Failed allocating string buffer");
4948 return -1;
4949 }
4950 str[len] = '\0';
4951
4952 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4953 dst->vb_strvalue = str;
4954 dst->vb_length = len;
4955
4956 if (out) *out = str;
4957
4958 return 0;
4959}
4960
4961/** Change the length of a buffer already allocated to a value box
4962 *
4963 * @note Do not use on an uninitialised box.
4964 *
4965 * @param[in] ctx to realloc buffer in.
4966 * @param[out] out if non-null where to write a pointer to the new buffer.
4967 * @param[in] dst to realloc buffer for.
4968 * @param[in] len to realloc to (don't include nul byte).
4969 * @return
4970 * - 0 on success.
4971 * - -1 on failure.
4972 */
4973int fr_value_box_bstr_realloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, size_t len)
4974{
4975 size_t dstlen;
4976 char *str;
4977
4978 fr_assert(dst->type == FR_TYPE_STRING);
4979
4980 dstlen = talloc_strlen(dst->vb_strvalue);
4981 if (dstlen == len) return 0; /* No change */
4982
4983 str = talloc_realloc(ctx, UNCONST(char *, dst->vb_strvalue), char, len + 1);
4984 if (!str) {
4985 fr_strerror_printf("Failed reallocing value box buffer to %zu bytes", len + 1);
4986 return -1;
4987 }
4988
4989 /*
4990 * Zero out the additional bytes
4991 */
4992 if (dstlen < len) {
4993 memset(str + dstlen, '\0', (len - dstlen) + 1);
4994 } else {
4995 str[len] = '\0';
4996 }
4997 dst->vb_strvalue = str;
4998 dst->vb_length = len;
4999
5000 if (out) *out = str;
5001
5002 return 0;
5003}
5004
5005/** Copy a string to to a #fr_value_box_t
5006 *
5007 * @param[in] ctx to allocate any new buffers in.
5008 * @param[in] dst to assign buffer to.
5009 * @param[in] enumv Aliases for values.
5010 * @param[in] src a string. May be NULL only if len == 0.
5011 * @param[in] len of src.
5012 * @param[in] tainted Whether the value came from a trusted source.
5013 */
5014int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
5015 char const *src, size_t len, bool tainted)
5016{
5017 char const *str;
5018
5019 if (unlikely((len > 0) && !src)) {
5020 fr_strerror_printf("Invalid arguments to %s. Len > 0 (%zu) but src string was NULL",
5021 __FUNCTION__, len);
5022 return -1;
5023 }
5024
5025 str = talloc_bstrndup(ctx, src, len);
5026 if (!str) {
5027 fr_strerror_const("Failed allocating string buffer");
5028 return -1;
5029 }
5030
5031 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
5032 dst->vb_strvalue = str;
5033 dst->vb_length = len;
5034
5035 return 0;
5036}
5037
5038int fr_value_box_bstrndup_dbuff(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
5039 fr_dbuff_t *dbuff, size_t len, bool tainted)
5040{
5041 char *str;
5042
5043 str = talloc_array(ctx, char, len + 1);
5044 if (!str) {
5045 fr_strerror_printf("Failed allocating string buffer");
5046 return -1;
5047 }
5048
5049 if (fr_dbuff_out_memcpy((uint8_t *)str, dbuff, len) < 0) {
5050 talloc_free(str);
5051 return -1;
5052 }
5053 str[len] = '\0';
5054
5055 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
5056 dst->vb_strvalue = str;
5057 dst->vb_length = len;
5058
5059 return 0;
5060}
5061
5062/** Copy a nul terminated talloced buffer to a #fr_value_box_t
5063 *
5064 * Copy a talloced nul terminated buffer, setting fields in the dst value box appropriately.
5065 *
5066 * The buffer must be \0 terminated, or an error will be returned.
5067 *
5068 * @param[in] ctx to allocate any new buffers in.
5069 * @param[in] dst to assign new buffer to.
5070 * @param[in] enumv Aliases for values.
5071 * @param[in] src a talloced nul terminated buffer.
5072 * @param[in] tainted Whether the value came from a trusted source.
5073 * @return
5074 * - 0 on success.
5075 * - -1 on failure.
5076 */
5077int fr_value_box_bstrdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
5078 char const *src, bool tainted)
5079{
5080 size_t len;
5081
5082 (void)talloc_get_type_abort_const(src, char);
5083
5084 len = talloc_array_length(src);
5085 if ((len == 0) || (src[len - 1] != '\0')) {
5086 fr_strerror_const("Input buffer not \\0 terminated");
5087 return -1;
5088 }
5089
5090 return fr_value_box_bstrndup(ctx, dst, enumv, src, len - 1, tainted);
5091}
5092
5093/** Assign a string to to a #fr_value_box_t
5094 *
5095 * @param[in] dst to assign new buffer to.
5096 * @param[in] enumv Aliases for values.
5097 * @param[in] src a string.
5098 * @param[in] len of src.
5099 * @param[in] tainted Whether the value came from a trusted source.
5100 */
5102 char const *src, size_t len, bool tainted)
5103{
5104 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
5105 dst->vb_strvalue = src;
5106 dst->vb_length = len;
5107}
5108
5109/** Assign a talloced buffer containing a nul terminated string to a box, but don't copy it
5110 *
5111 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
5112 *
5113 * @param[in] ctx to add reference from. If NULL no reference will be added.
5114 * @param[in] dst to assign string to.
5115 * @param[in] enumv Aliases for values.
5116 * @param[in] src to copy string from.
5117 * @param[in] tainted Whether the value came from a trusted source.
5118 * @return
5119 * - 0 on success.
5120 * - -1 on failure.
5121 */
5123 char const *src, bool tainted)
5124{
5125 size_t len;
5126
5127 (void) talloc_get_type_abort_const(src, char);
5128
5129 len = talloc_array_length(src);
5130 if ((len == 0) || (src[len - 1] != '\0')) {
5131 fr_strerror_const("Input buffer not \\0 terminated");
5132 return -1;
5133 }
5134
5135 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
5136 dst->vb_strvalue = ctx ? talloc_reference(ctx, src) : src;
5137 dst->vb_length = len - 1;
5138
5139 return 0;
5140}
5141
5142/** Pre-allocate an octets buffer for filling by the caller
5143 *
5144 * @note Buffer will not be zeroed, as it's assumed the caller will be filling it.
5145 *
5146 * @param[in] ctx to allocate any new buffers in.
5147 * @param[out] out If non-null will be filled with a pointer to the
5148 * new buffer.
5149 * @param[in] dst to assign new buffer to.
5150 * @param[in] enumv Aliases for values.
5151 * @param[in] len of data in the buffer. If 0, a zero length
5152 * talloc buffer will be alloced. dst->vb_octets
5153 * will *NOT* be NULL. You should use the length
5154 * field of the box to determine if any value
5155 * is assigned.
5156 * @param[in] tainted Whether the value came from a trusted source.
5157 * @return
5158 * - 0 on success.
5159 * - -1 on failure.
5160 */
5161int fr_value_box_mem_alloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
5162 size_t len, bool tainted)
5163{
5164 uint8_t *bin;
5165
5166 bin = talloc_array(ctx, uint8_t, len);
5167 if (!bin) {
5168 fr_strerror_const("Failed allocating octets buffer");
5169 return -1;
5170 }
5171 talloc_set_type(bin, uint8_t);
5172
5173 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
5174 dst->vb_octets = bin;
5175 dst->vb_length = len;
5176
5177 if (out) *out = bin;
5178
5179 return 0;
5180}
5181
5182/** Change the length of a buffer already allocated to a value box
5183 *
5184 * @note Do not use on an uninitialised box.
5185 *
5186 * @param[in] ctx to realloc buffer in.
5187 * @param[out] out if non-null where to write a pointer to the new buffer.
5188 * @param[in] dst to realloc buffer for.
5189 * @param[in] len to realloc to.
5190 * @return
5191 * - 0 on success.
5192 * - -1 on failure.
5193 */
5194int fr_value_box_mem_realloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, size_t len)
5195{
5196 size_t dstlen;
5197 uint8_t *bin;
5198
5199 fr_assert(dst->type == FR_TYPE_OCTETS);
5200
5201 dstlen = talloc_array_length(dst->vb_octets);
5202 if (dstlen == len) return 0; /* No change */
5203
5204 /*
5205 * Realloc the buffer. If the new length is 0, we
5206 * need to call talloc_array() instead of talloc_realloc()
5207 * as talloc_realloc() will fail.
5208 */
5209 if (len > 0) {
5210 bin = talloc_realloc(ctx, UNCONST(uint8_t *, dst->vb_octets), uint8_t, len);
5211 } else {
5212 bin = talloc_array(ctx, uint8_t, 0);
5213 }
5214 if (!bin) {
5215 fr_strerror_printf("Failed reallocing value box buffer to %zu bytes", len);
5216 return -1;
5217 }
5218
5219 /*
5220 * Only free the original buffer once we've allocated
5221 * a new empty array.
5222 */
5223 if (len == 0) talloc_const_free(dst->vb_octets);
5224
5225 /*
5226 * Zero out the additional bytes
5227 */
5228 if (dstlen < len) memset(bin + dstlen, 0x00, len - dstlen);
5229 dst->vb_octets = bin;
5230 dst->vb_length = len;
5231
5232 if (out) *out = bin;
5233
5234 return 0;
5235}
5236
5237/** Copy a buffer to a fr_value_box_t
5238 *
5239 * Copy a buffer containing binary data, setting fields in the dst value box appropriately.
5240 *
5241 * @param[in] ctx to allocate any new buffers in.
5242 * @param[in] dst to assign new buffer to.
5243 * @param[in] enumv Aliases for values.
5244 * @param[in] src a buffer.
5245 * @param[in] len of data in the buffer. If 0, a zero length
5246 * talloc buffer will be alloced. dst->vb_octets
5247 * will *NOT* be NULL. You should use the length
5248 * field of the box to determine if any value
5249 * is assigned.
5250 * @param[in] tainted Whether the value came from a trusted source.
5251 * @return
5252 * - 0 on success.
5253 * - -1 on failure.
5254 */
5255int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
5256 uint8_t const *src, size_t len, bool tainted)
5257{
5258 uint8_t *bin;
5259
5260 if (unlikely((len > 0) && !src)) {
5261 fr_strerror_printf("Invalid arguments to %s. Len > 0 (%zu) but src was NULL",
5262 __FUNCTION__, len);
5263 return -1;
5264 }
5265
5266 bin = talloc_memdup(ctx, src, len);
5267 if (!bin) {
5268 fr_strerror_const("Failed allocating octets buffer");
5269 return -1;
5270 }
5271 talloc_set_type(bin, uint8_t);
5272
5273 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
5274 dst->vb_octets = bin;
5275 dst->vb_length = len;
5276
5277 return 0;
5278}
5279
5280int fr_value_box_memdup_dbuff(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
5281 fr_dbuff_t *dbuff, size_t len, bool tainted)
5282{
5283 uint8_t *bin;
5284
5285 bin = talloc_size(ctx, len);
5286 if (!bin) {
5287 fr_strerror_printf("Failed allocating octets buffer");
5288 return -1;
5289 }
5290
5291 if (fr_dbuff_out_memcpy(bin, dbuff, len) < (ssize_t) len) {
5292 talloc_free(bin);
5293 return -1;
5294 }
5295 talloc_set_type(bin, uint8_t);
5296
5297 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
5298 dst->vb_octets = bin;
5299 dst->vb_length = len;
5300
5301 return 0;
5302}
5303
5304/** Copy a talloced buffer to a fr_value_box_t
5305 *
5306 * Copy a buffer containing binary data, setting fields in the dst value box appropriately.
5307 *
5308 * @param[in] ctx to allocate any new buffers in.
5309 * @param[in] dst to assign new buffer to.
5310 * @param[in] enumv Aliases for values.
5311 * @param[in] src a buffer.
5312 * @param[in] tainted Whether the value came from a trusted source.
5313 * @return
5314 * - 0 on success.
5315 * - -1 on failure.
5316 */
5317int fr_value_box_memdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
5318 uint8_t const *src, bool tainted)
5319{
5321
5322 return fr_value_box_memdup(ctx, dst, enumv, src, talloc_array_length(src), tainted);
5323}
5324
5325/** Assign a buffer to a box, but don't copy it
5326 *
5327 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
5328 *
5329 * Caller should set dst->taint = true, where the value was acquired from an untrusted source.
5330 *
5331 * @note Will free any exiting buffers associated with the value box.
5332 *
5333 * @param[in] dst to assign buffer to.
5334 * @param[in] enumv Aliases for values.
5335 * @param[in] src a talloced buffer.
5336 * @param[in] len of buffer.
5337 * @param[in] tainted Whether the value came from a trusted source.
5338 */
5340 uint8_t const *src, size_t len, bool tainted)
5341{
5342 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
5343 dst->vb_octets = src;
5344 dst->vb_length = len;
5345}
5346
5347/** Assign a talloced buffer to a box, but don't copy it
5348 *
5349 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
5350 *
5351 * @param[in] ctx to allocate any new buffers in.
5352 * @param[in] dst to assign buffer to.
5353 * @param[in] enumv Aliases for values.
5354 * @param[in] src a talloced buffer.
5355 * @param[in] tainted Whether the value came from a trusted source.
5356 */
5358 uint8_t const *src, bool tainted)
5359{
5361
5362 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
5363 dst->vb_octets = ctx ? talloc_reference(ctx, src) : src;
5364 dst->vb_length = talloc_array_length(src);
5365}
5366
5367/*
5368 * Assign a cursor to the data type.
5369 */
5371{
5373
5374 fr_value_box_init(dst, type, NULL, false);
5375 dst->vb_cursor = cursor;
5376 dst->vb_cursor_name = name;
5377}
5378
5379
5380/** Assign a void pointer to a box
5381 *
5382 * @param[in] dst to assign void pointer to.
5383 * @param[in] ptr to assign.
5384 */
5386{
5387 fr_value_box_init(dst, FR_TYPE_VOID, NULL, false);
5388 dst->vb_void = UNCONST(void *, ptr);
5389}
5390
5392{
5394
5395 /*
5396 * If the DA points to a root (e.g. OID-Tree), then use that.
5397 *
5398 * Otherwise if it doesn't have ENUMs defined, then point it at the dict root.
5399 *
5400 * If it does have enums, then the enumv is itself.
5401 */
5403 if (ext) {
5405 fr_assert(!da->flags.has_value);
5406
5407 return ext->ref;
5408 }
5409
5410 if (!da->flags.has_value) {
5411 return fr_dict_root(da->dict);
5412 }
5413
5414 return da;
5415}
5416
5418{
5419 fr_value_box_init(dst, FR_TYPE_ATTR, NULL, false);
5420 dst->vb_attr = da;
5421
5422 dst->enumv = fr_value_box_attr_enumv(da);
5423}
5424
5425/** Increment a boxed value
5426 *
5427 * Implements safe integer overflow.
5428 *
5429 * @param[in] vb to increment.
5430 */
5432{
5433 switch (vb->type) {
5434 case FR_TYPE_UINT8:
5435 vb->vb_uint8 = vb->vb_uint8 == UINT8_MAX ? 0 : vb->vb_uint8 + 1;
5436 return;
5437
5438 case FR_TYPE_UINT16:
5439 vb->vb_uint16 = vb->vb_uint16 == UINT16_MAX ? 0 : vb->vb_uint16 + 1;
5440 return;
5441
5442 case FR_TYPE_UINT32:
5443 vb->vb_uint32 = vb->vb_uint32 == UINT32_MAX ? 0 : vb->vb_uint32 + 1;
5444 return;
5445
5446 case FR_TYPE_UINT64:
5447 vb->vb_uint64 = vb->vb_uint64 == UINT64_MAX ? 0 : vb->vb_uint64 + 1;
5448 return;
5449
5450 case FR_TYPE_INT8:
5451 vb->vb_int8 = vb->vb_int8 == INT8_MAX ? INT8_MIN : vb->vb_int8 + 1;
5452 return;
5453
5454 case FR_TYPE_INT16:
5455 vb->vb_int16 = vb->vb_int16 == INT16_MAX ? INT16_MIN : vb->vb_int16 + 1;
5456 return;
5457
5458 case FR_TYPE_INT32:
5459 vb->vb_int32 = vb->vb_int32 == INT32_MAX ? INT32_MIN : vb->vb_int32 + 1;
5460 return;
5461
5462 case FR_TYPE_INT64:
5463 vb->vb_int64 = vb->vb_int64 == INT64_MAX ? INT64_MIN : vb->vb_int64 + 1;
5464 return;
5465
5466 default:
5467 fr_assert_fail(NULL);
5468 return;
5469 }
5470}
5471
5472/** Convert integer encoded as string to a fr_value_box_t type
5473 *
5474 * @param[out] dst where to write parsed value.
5475 * @param[in] dst_type type of integer to convert string to.
5476 * @param[in] dst_enumv Enumeration values.
5477 * @param[in] in String to convert to integer.
5478 * @param[in] rules for parsing string.
5479 * @param[in] tainted Whether the value came from a trusted source.
5480 * @return
5481 * - >= 0 on success (number of bytes parsed).
5482 * - < 0 on error (where the parse error occurred).
5483 */
5484static inline CC_HINT(always_inline)
5486 fr_dict_attr_t const *dst_enumv,
5487 fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules, bool tainted)
5488{
5489 fr_sbuff_t our_in = FR_SBUFF(in);
5490 fr_sbuff_err_t err;
5491
5492 fr_value_box_init(dst, dst_type, dst_enumv, tainted);
5493
5494 switch (dst_type) {
5495 case FR_TYPE_UINT8:
5496 err = fr_sbuff_out(&dst->vb_uint8, &our_in);
5497 break;
5498
5499 case FR_TYPE_UINT16:
5500 err = fr_sbuff_out(&dst->vb_uint16, &our_in);
5501 break;
5502
5503 case FR_TYPE_UINT32:
5504 err = fr_sbuff_out(&dst->vb_uint32, &our_in);
5505 break;
5506
5507 case FR_TYPE_UINT64:
5508 err = fr_sbuff_out(&dst->vb_uint64, &our_in);
5509 break;
5510
5511 case FR_TYPE_INT8:
5512 err = fr_sbuff_out(&dst->vb_int8, &our_in);
5513 break;
5514
5515 case FR_TYPE_INT16:
5516 err = fr_sbuff_out(&dst->vb_int16, &our_in);
5517 break;
5518
5519 case FR_TYPE_INT32:
5520 err = fr_sbuff_out(&dst->vb_int32, &our_in);
5521 break;
5522
5523 case FR_TYPE_INT64:
5524 err = fr_sbuff_out(&dst->vb_int64, &our_in);
5525 break;
5526
5527 case FR_TYPE_SIZE:
5528 err = fr_sbuff_out(&dst->vb_size, &our_in);
5529 break;
5530
5531 case FR_TYPE_FLOAT32:
5532 err = fr_sbuff_out(&dst->vb_float32, &our_in);
5533 break;
5534
5535 case FR_TYPE_FLOAT64:
5536 err = fr_sbuff_out(&dst->vb_float64, &our_in);
5537 break;
5538
5539 default:
5540 fr_assert_fail(NULL);
5541 return -1;
5542 }
5543
5544 if (err < 0) {
5545 /*
5546 * If an enumeration attribute is provided and we
5547 * don't find an integer, assume this is an enumv
5548 * lookup fail, and produce a better error.
5549 */
5550 if (dst_enumv && dst_enumv->flags.has_value && (err == FR_SBUFF_ERR_NOT_FOUND)) {
5551 fr_sbuff_adv_until(&our_in, SIZE_MAX, rules->terminals,
5552 rules->escapes ? rules->escapes->chr : '\0');
5553
5554 fr_strerror_printf("Invalid enumeration value \"%pV\" for attribute %s",
5556 dst_enumv->name);
5557 return -1;
5558 }
5559
5560 if (err == FR_SBUFF_ERR_NOT_FOUND) {
5561 fr_strerror_printf("Failed parsing string as type '%s'",
5562 fr_type_to_str(dst_type));
5563 } else {
5564 fr_sbuff_err_to_strerror(err);
5565 }
5566 FR_SBUFF_ERROR_RETURN(&our_in);
5567 }
5568
5569 FR_SBUFF_SET_RETURN(in, &our_in);
5570}
5571
5572/** Convert string value to a fr_value_box_t type
5573 *
5574 * @param[in] ctx to alloc strings in.
5575 * @param[out] dst where to write parsed value.
5576 * @param[in,out] dst_type of value data to create/dst_type of value created.
5577 * @param[in] dst_enumv fr_dict_attr_t with string names for uint32 values.
5578 * @param[in] in sbuff to read data from.
5579 * @param[in] rules unescape and termination rules.
5580 * @return
5581 * - >0 on success.
5582 * - <= 0 on parse error.
5583 */
5585 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
5586 fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules)
5587{
5588 static fr_sbuff_parse_rules_t default_rules;
5589 fr_sbuff_t *unescaped = NULL;
5590 fr_sbuff_t our_in = FR_SBUFF(in);
5591 fr_ipaddr_t addr;
5592 fr_slen_t slen;
5593 char buffer[256];
5594
5595 if (!rules) rules = &default_rules;
5596
5598 fr_value_box_init(dst, dst_type, NULL, false);
5599
5600 /*
5601 * Lookup any names before continuing
5602 */
5603 if (dst_enumv && dst_enumv->flags.has_value && (dst_type != FR_TYPE_ATTR)) {
5604 size_t name_len;
5605 fr_dict_enum_value_t const *enumv;
5606
5607 /*
5608 * @todo - allow enum names for IPv6 addresses and prefixes. See also
5609 * tmpl_afrom_enum().
5610 */
5611 (void) fr_sbuff_adv_past_str_literal(&our_in, "::");
5612
5613 /*
5614 * If there is no escaping, then we ignore the terminals. The list of allowed characters
5615 * in enum names will ensure that the parsing doesn't go too far. i.e. to '\r', '\n'. '}', etc.
5616 *
5617 * The reason is that the list of terminals may include things like '-', which is also a
5618 * valid character in enum names. We don't want to parse "Framed-User" as "Framed - User".
5619 */
5620 if (!rules->escapes) {
5621 size_t len;
5623
5624 fr_sbuff_marker(&m, &our_in);
5625
5628 fr_sbuff_set(&our_in, &m);
5629 fr_sbuff_marker_release(&m);
5630
5631 if (!len) goto parse; /* Zero length name can't match enum */
5632
5633 enumv = fr_dict_enum_by_name(dst_enumv, fr_sbuff_current(&our_in), len);
5634 if (!enumv) {
5635 goto parse; /* No enumeration matches escaped string */
5636 }
5637
5638 (void) fr_sbuff_advance(&our_in, len);
5639 goto cast_enum;
5640 }
5641
5642 /*
5643 * Create a thread-local extensible buffer to
5644 * store unescaped data.
5645 *
5646 * This is created once per-thread (the first time
5647 * this function is called), and freed when the
5648 * thread exits.
5649 */
5650 FR_SBUFF_TALLOC_THREAD_LOCAL(&unescaped, 256, 4096);
5651
5652 /*
5653 * This function only does escaping until a terminal character, such as '-'. So
5654 * Framed-User will get parsed as "Framed - User".
5655 *
5656 * Pretty much no other enum has this problem. For Service-Type, it defines "Framed" ss
5657 * an equivalent name to "Framed-User". The parser sees "Framed-User", stops at the '-',
5658 * and then finds the enum named "Framed". It then returns the trailing "-User" as
5659 * something more to parse.
5660 *
5661 * As a result, when the user passes in "Framed-User", the output is "Framed-User -
5662 * User", which is more than a bit surprising.
5663 */
5664 if (fr_sbuff_out_unescape_until(&name_len, unescaped, &our_in, SIZE_MAX,
5665 rules->terminals, rules->escapes) < 0) {
5666 fr_strerror_const("Failed reading enumeration name");
5667 FR_SBUFF_ERROR_RETURN(&our_in);
5668 }
5669 if (!name_len) {
5670 fr_sbuff_set_to_start(&our_in);
5671 goto parse; /* Zero length name can't match enum */
5672 }
5673
5674 enumv = fr_dict_enum_by_name(dst_enumv, fr_sbuff_start(unescaped), fr_sbuff_used(unescaped));
5675 if (!enumv) {
5676 fr_sbuff_set_to_start(&our_in);
5677 goto parse; /* No enumeration matches escaped string */
5678 }
5679
5680 cast_enum:
5681 /*
5682 * dst_type may not match enumv type
5683 */
5684 if (fr_value_box_cast(ctx, dst, dst_type, dst_enumv, enumv->value) < 0) return -1;
5685
5686 FR_SBUFF_SET_RETURN(in, &our_in);
5687 }
5688
5689parse:
5690 /*
5691 * It's a variable ret src->dst_type so we just alloc a new buffer
5692 * of size len and copy.
5693 */
5694 switch (dst_type) {
5695 case FR_TYPE_STRING:
5696 /*
5697 * We've not unescaped the string yet, produce an unescaped version
5698 */
5699 if (!dst_enumv || !unescaped) {
5700 char *buff;
5701
5702 if (unlikely(fr_sbuff_out_aunescape_until(ctx, &buff, NULL, &our_in, SIZE_MAX,
5703 rules->terminals, rules->escapes) < 0)) {
5704 return -1;
5705 }
5706 fr_value_box_bstrdup_buffer_shallow(NULL, dst, dst_enumv, buff, false);
5707 /*
5708 * We already have an unescaped version, just use that
5709 */
5710 } else {
5711 fr_value_box_bstrndup(ctx, dst, dst_enumv,
5712 fr_sbuff_start(unescaped), fr_sbuff_used(unescaped), false);
5713 }
5714 FR_SBUFF_SET_RETURN(in, &our_in);
5715
5716 /* raw octets: 0x01020304... */
5717 case FR_TYPE_OCTETS:
5718 {
5719 fr_sbuff_marker_t hex_start;
5720 size_t hex_len;
5721 uint8_t *bin_buff;
5722
5723 /*
5724 * If there's escape sequences that need to be processed
5725 * or the string doesn't start with 0x, then assume this
5726 * is literal data, not hex encoded data.
5727 */
5728 if (rules->escapes || !fr_sbuff_adv_past_strcase_literal(&our_in, "0x")) {
5729 if (!dst_enumv || !unescaped) {
5730 char *buff = NULL;
5731 uint8_t *bin;
5732 size_t len;
5733
5734 if (fr_sbuff_extend(&our_in)) {
5735 if (fr_sbuff_out_aunescape_until(ctx, &buff, &len, &our_in, SIZE_MAX,
5736 rules->terminals, rules->escapes) < 0) {
5737 return -1;
5738 }
5739
5740 if (len == 0) {
5742 goto zero;
5743 }
5744
5745 /*
5746 * Trim off the trailing '\0', and change the data type.
5747 */
5749 if (unlikely(!bin)) {
5750 fr_strerror_const("Failed trimming string buffer");
5752 return -1;
5753 }
5754
5755 /*
5756 * Input data is zero
5757 *
5758 * talloc realloc will refuse to realloc to
5759 * a zero length buffer. This is probably
5760 * a bug, because we can create zero length
5761 * arrays normally
5762 */
5763 } else {
5764 zero:
5765 bin = talloc_zero_array(ctx, uint8_t, 0);
5766 }
5767
5768 fr_value_box_memdup_buffer_shallow(NULL, dst, dst_enumv, bin, false);
5769 /*
5770 * We already have an unescaped version, just use that
5771 */
5772 } else {
5773 fr_value_box_memdup(ctx, dst, dst_enumv,
5774 (uint8_t *)fr_sbuff_start(unescaped),
5775 fr_sbuff_used(unescaped), false);
5776 }
5777 FR_SBUFF_SET_RETURN(in, &our_in);
5778 }
5779
5780 fr_sbuff_marker(&hex_start, &our_in); /* Record where the hexits start */
5781
5782 /*
5783 * Find the end of the hex sequence.
5784 *
5785 * We don't technically need to do this, fr_base16_decode
5786 * will find the end on its own.
5787 *
5788 * We do this so we can alloc the correct sized
5789 * output buffer.
5790 */
5791 hex_len = fr_sbuff_adv_past_allowed(&our_in, SIZE_MAX, sbuff_char_class_hex, rules->terminals);
5792 if (hex_len == 0) {
5793 if (fr_value_box_memdup(ctx, dst, dst_enumv, (uint8_t[]){ 0x00 }, 0, false) < 0) return -1;
5794 FR_SBUFF_SET_RETURN(in, &our_in);
5795 }
5796
5797 if ((hex_len & 0x01) != 0) {
5798 fr_strerror_printf("Length of hex string is not even, got %zu bytes", hex_len);
5799 FR_SBUFF_ERROR_RETURN(&our_in);
5800 }
5801
5802 /*
5803 * Pre-allocate the bin buff and initialise the box
5804 */
5805 if (fr_value_box_mem_alloc(ctx, &bin_buff, dst, dst_enumv, (hex_len >> 1), false) < 0) return -1;
5806
5807 /*
5808 * Reset to the start of the hex string
5809 */
5810 fr_sbuff_set(&our_in, &hex_start);
5811
5812 if (unlikely(fr_base16_decode(NULL, &FR_DBUFF_TMP(bin_buff, hex_len), &our_in, false) < 0)) {
5813 talloc_free(bin_buff);
5814 FR_SBUFF_ERROR_RETURN(&our_in);
5815 }
5816
5817 FR_SBUFF_SET_RETURN(in, &our_in);
5818 }
5819
5820 case FR_TYPE_IPV4_ADDR:
5821 {
5822 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5823 if (!name_len) goto empty_is_invalid;
5824
5825 if (fr_inet_pton4(&addr, fr_sbuff_current(in), name_len,
5826 fr_hostname_lookups, false, true) < 0) return -1;
5827
5828 /*
5829 * We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
5830 * print them this way.
5831 */
5832 if (addr.prefix != 32) {
5833 fail_ipv4_prefix:
5834 fr_strerror_printf("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted "
5835 "for non-prefix types", addr.prefix);
5836 return -1;
5837 }
5838
5839 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5840 }
5841 goto finish;
5842
5844 {
5845 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5846 if (!name_len) goto empty_is_invalid;
5847
5848 if (fr_inet_pton4(&dst->vb_ip, fr_sbuff_current(in), name_len,
5849 fr_hostname_lookups, false, true) < 0) return -1;
5850 }
5851 goto finish;
5852
5853 case FR_TYPE_IPV6_ADDR:
5854 {
5855 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5856 if (!name_len) goto empty_is_invalid;
5857
5858 /*
5859 * Parse scope, too.
5860 */
5861 if (fr_sbuff_next_if_char(&our_in, '%')) {
5862 name_len += fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_uint, rules->terminals);
5863 }
5864
5865 if (fr_inet_pton6(&addr, fr_sbuff_current(in), name_len,
5866 fr_hostname_lookups, false, true) < 0) return -1;
5867
5868 /*
5869 * We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
5870 * print them this way.
5871 */
5872 if (addr.prefix != 128) {
5873 fail_ipv6_prefix:
5874 fr_strerror_printf("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted "
5875 "for non-prefix types", addr.prefix);
5876 return -1;
5877 }
5878
5879 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5880 }
5881 goto finish;
5882
5884 {
5885 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5886 if (!name_len) goto empty_is_invalid;
5887
5888 if (fr_inet_pton6(&dst->vb_ip, fr_sbuff_current(in), name_len,
5889 fr_hostname_lookups, false, true) < 0) return -1;
5890 }
5891 goto finish;
5892
5894 {
5895 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5896 if (!name_len) goto empty_is_invalid;
5897
5898 /*
5899 * Parse scope, too.
5900 */
5901 if (fr_sbuff_next_if_char(&our_in, '%')) {
5902 name_len += fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_uint, rules->terminals);
5903 }
5904
5905 if (fr_inet_pton(&addr, fr_sbuff_current(in), name_len, AF_UNSPEC,
5906 fr_hostname_lookups, true) < 0) return -1;
5907
5908 if ((addr.af == AF_INET) && (addr.prefix != 32)) {
5909 goto fail_ipv4_prefix;
5910 }
5911
5912 if ((addr.af == AF_INET6) && (addr.prefix != 128)) {
5913 goto fail_ipv6_prefix;
5914 }
5915
5916 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5917 }
5918 goto finish;
5919
5921 {
5922 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5923 if (!name_len) goto empty_is_invalid;
5924
5925 if (fr_inet_pton(&dst->vb_ip, fr_sbuff_current(in), name_len, AF_UNSPEC,
5926 fr_hostname_lookups, true) < 0) return -1;
5927 }
5928 goto finish;
5929
5930 case FR_TYPE_UINT8:
5931 case FR_TYPE_UINT16:
5932 case FR_TYPE_UINT32:
5933 case FR_TYPE_UINT64:
5934 case FR_TYPE_INT8:
5935 case FR_TYPE_INT16:
5936 case FR_TYPE_INT32:
5937 case FR_TYPE_INT64:
5938 case FR_TYPE_FLOAT32:
5939 case FR_TYPE_FLOAT64:
5940 return fr_value_box_from_numeric_substr(dst, dst_type, dst_enumv, in, rules, false);
5941
5942 case FR_TYPE_SIZE:
5943 if (fr_size_from_str(&dst->datum.size, &our_in) < 0) return -1;
5944 goto finish;
5945
5946 case FR_TYPE_BOOL:
5947 {
5948 fr_sbuff_t bool_in = FR_SBUFF(in);
5949
5950 fr_value_box_init(dst, dst_type, dst_enumv, false);
5951
5952 /*
5953 * Quoted boolean values are "yes", "no", "true", "false"
5954 */
5955 if (fr_sbuff_out(&dst->vb_bool, &bool_in) >= 0) FR_SBUFF_SET_RETURN(in, &bool_in);
5956
5957 /*
5958 * For barewords we also allow 0 for false and any other
5959 * integer value for true.
5960 */
5961 if (!rules->escapes) {
5962 int64_t stmp;
5963 uint64_t utmp;
5964
5965 if (fr_sbuff_out(&stmp, &bool_in) >= 0) {
5966 dst->vb_bool = (stmp != 0);
5967 FR_SBUFF_SET_RETURN(in, &bool_in);
5968 }
5969
5970 if (fr_sbuff_out(&utmp, &bool_in) >= 0) {
5971 dst->vb_bool = (utmp != 0);
5972 FR_SBUFF_SET_RETURN(in, &bool_in);
5973 }
5974 }
5975
5976 fr_strerror_const("Invalid boolean value. Accepted values are "
5977 "\"yes\", \"no\", \"true\", \"false\" or any unquoted integer");
5978
5979 FR_SBUFF_ERROR_RETURN(&bool_in);
5980 }
5981
5982 case FR_TYPE_ETHERNET:
5983 {
5984 uint64_t num;
5985 fr_ethernet_t ether;
5986 fr_dbuff_t dbuff;
5987 fr_sbuff_err_t err;
5988
5989 fr_dbuff_init(&dbuff, ether.addr, sizeof(ether.addr));
5990
5991 /*
5992 * Convert things which are obviously integers to Ethernet addresses
5993 *
5994 * We assume the number is the decimal
5995 * representation of the ethernet address.
5996 * i.e. the ethernet address converted to a
5997 * number, and printed.
5998 *
5999 * The string gets converted to a network-order
6000 * 8-byte number, and then the lower bytes of
6001 * that get copied to the ethernet address.
6002 *
6003 * Note: We need to check for a terminal sequence
6004 * after the number, else we may just end up
6005 * parsing the first hexit and returning.
6006 *
6007 * i.e. 1c:00:00:00:00 -> 1
6008 */
6009 if ((fr_sbuff_out(&num, &our_in) >= 0) && fr_sbuff_is_terminal(&our_in, rules->terminals)) {
6010 num = htonll(num);
6011
6012 FR_DBUFF_IN_MEMCPY_RETURN(&dbuff, ((uint8_t *) &num) + 2, sizeof(dst->vb_ether));
6013 fr_value_box_ethernet_addr(dst, dst_enumv, &ether, false);
6014
6015 FR_SBUFF_SET_RETURN(in, &our_in);
6016 }
6017
6018 fr_sbuff_set_to_start(&our_in);
6019
6020 fr_base16_decode(&err, &dbuff, &our_in, true);
6021 if (err != FR_SBUFF_OK) {
6022 ether_error:
6023 fr_sbuff_err_to_strerror(err);
6024 FR_SBUFF_ERROR_RETURN(&our_in);
6025 }
6026
6027 if (!fr_sbuff_next_if_char(&our_in, ':')) {
6028 ether_sep_error:
6029 fr_strerror_const("Missing separator, expected ':'");
6030 FR_SBUFF_ERROR_RETURN(&our_in);
6031 }
6032
6033 fr_base16_decode(&err, &dbuff, &our_in, true);
6034 if (err != FR_SBUFF_OK) goto ether_error;
6035
6036 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
6037
6038 fr_base16_decode(&err, &dbuff, &our_in, true);
6039 if (err != FR_SBUFF_OK) goto ether_error;
6040
6041 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
6042
6043 fr_base16_decode(&err, &dbuff, &our_in, true);
6044 if (err != FR_SBUFF_OK) goto ether_error;
6045
6046 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
6047
6048 fr_base16_decode(&err, &dbuff, &our_in, true);
6049 if (err != FR_SBUFF_OK) goto ether_error;
6050
6051 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
6052
6053 fr_base16_decode(&err, &dbuff, &our_in, true);
6054 if (err != FR_SBUFF_OK) goto ether_error;
6055
6056 fr_value_box_ethernet_addr(dst, dst_enumv, (fr_ethernet_t * const)fr_dbuff_start(&dbuff), false);
6057
6058 FR_SBUFF_SET_RETURN(in, &our_in);
6059 }
6060
6061 case FR_TYPE_TIME_DELTA:
6062 fr_value_box_init(dst, FR_TYPE_TIME_DELTA, dst_enumv, false);
6063
6064 slen = fr_time_delta_from_substr(&dst->datum.time_delta, &our_in,
6065 dst_enumv ? (fr_time_res_t)dst_enumv->flags.flag_time_res : FR_TIME_RES_SEC,
6066 false, rules->terminals);
6067 if (slen < 0) return slen;
6068 if (!slen) {
6069 empty_is_invalid:
6070 fr_strerror_const("Empty input is invalid");
6071 return -1;
6072 }
6073 FR_SBUFF_SET_RETURN(in, &our_in);
6074
6075 case FR_TYPE_NULL:
6076 if (!rules->escapes && fr_sbuff_adv_past_str_literal(&our_in, "NULL")) {
6077 fr_value_box_init(dst, dst_type, dst_enumv, false);
6078 FR_SBUFF_SET_RETURN(in, &our_in);
6079 }
6080
6081 fr_strerror_const("Unexpected value for data type NULL");
6082 return -1;
6083
6084 case FR_TYPE_ATTR:
6085 if (!dst_enumv) {
6086 fr_strerror_const("No dictionary passed for data type 'attr'");
6087 return -1;
6088 }
6089
6090 /*
6091 * @todo - have attributes of FR_TYPE_ATTR also
6092 * carry a ref to where their values are taken from.
6093 */
6094 if (dst_enumv->type == FR_TYPE_ATTR) {
6095 dst_enumv = fr_value_box_attr_enumv(dst_enumv);
6096
6097 } else if (dst_enumv->type != FR_TYPE_TLV) {
6098 fr_strerror_printf("Can only start from data type 'tlv' for data type 'attribute', and not from %s", dst_enumv->name);
6099 return -1;
6100 }
6101
6102 fr_value_box_init(dst, dst_type, dst_enumv, false);
6103
6104 (void) fr_sbuff_adv_past_str_literal(&our_in, "::");
6105
6106 /*
6107 * Allow '@' references in values.
6108 */
6109 if (fr_sbuff_is_char(&our_in, '@')) {
6110 size_t len;
6112
6113 fr_sbuff_marker(&m, &our_in);
6114 fr_sbuff_advance(&our_in, 1); /* '@' is not an allowed character for dictionary names */
6115
6118 fr_sbuff_set(&our_in, &m);
6119 fr_sbuff_marker_release(&m);
6120
6121 len++; /* account for '@' */
6122
6123 /*
6124 * This function needs the '@'.
6125 */
6126 if (fr_dict_protocol_reference(&dst->vb_attr, fr_dict_root(dst_enumv->dict), &FR_SBUFF_IN(fr_sbuff_current(&our_in), len)) < 0) {
6127 return -1;
6128 }
6129
6130 if (!dst->vb_attr) {
6131 fr_strerror_printf("Failed to find attribute reference %.*s", (int) len, fr_sbuff_current(&our_in));
6132 return -1;
6133 }
6134
6135 fr_assert(dst->vb_attr != NULL);
6136
6137 if (dst->vb_attr->dict != dst_enumv->dict) {
6138 fr_strerror_const("Type 'attribute' cannot reference a different protocol");
6139 return -1;
6140 }
6141
6142 fr_sbuff_advance(&our_in, len);
6143 FR_SBUFF_SET_RETURN(in, &our_in);
6144
6145 } else {
6146 fr_dict_attr_t const *da;
6147
6148 fr_assert(dst_enumv != NULL);
6149
6150 slen = fr_dict_attr_by_oid_substr(NULL, &dst->vb_attr, dst_enumv, &our_in, rules->terminals);
6151 if (slen > 0) {
6152 fr_assert(dst->vb_attr != NULL);
6153
6154 if (!fr_sbuff_next_if_char(&our_in, '.')) {
6155 FR_SBUFF_SET_RETURN(in, &our_in);
6156 }
6157
6158 /*
6159 * The next bit MUST be an unknown attribute.
6160 */
6161 }
6162
6163 if (!fr_sbuff_is_digit(&our_in)) {
6164 invalid_attr:
6165 fr_strerror_printf_push("Failed to find the attribute in %s", dst_enumv->name);
6166 return -2;
6167 }
6168
6169 slen = fr_dict_attr_unknown_afrom_oid_substr(ctx, &da, dst->vb_attr, &our_in, FR_TYPE_OCTETS);
6170 if (slen <= 0) goto invalid_attr;
6171
6172 dst->vb_attr = da;
6173 FR_SBUFF_SET_RETURN(in, &our_in);
6174 }
6175
6176 /*
6177 * Dealt with below
6178 */
6179 default:
6180 break;
6181 }
6182
6183 /*
6184 * We may have terminals. If so, respect them.
6185 */
6186 if (rules && rules->terminals) {
6187 size_t len;
6188 fr_sbuff_err_t sberr;
6189
6190 sberr = fr_sbuff_out_unescape_until(&len, &FR_SBUFF_OUT(buffer, sizeof(buffer)), &our_in, SIZE_MAX,
6191 rules->terminals, rules->escapes);
6192 if (sberr < 0) {
6193 fr_strerror_printf("Failed reading value: %s", fr_sbuff_err_to_str(sberr));
6194 return -1;
6195 }
6196
6197 buffer[len] = '\0';
6198
6199 } else {
6200 /*
6201 * It's a fixed size src->dst_type, copy to a temporary buffer and
6202 * \0 terminate.
6203 *
6204 * @todo - note that this brute-force copy means that the input sbuff
6205 * is NOT advanced, and this function will return 0, even though it parsed data!
6206 */
6207 if (fr_sbuff_remaining(in) >= sizeof(buffer)) {
6208 fr_strerror_const("Temporary buffer too small");
6209 return -1;
6210 }
6211
6213 buffer[fr_sbuff_remaining(in)] = '\0';
6214 }
6215
6216 switch (dst_type) {
6217 case FR_TYPE_DATE:
6218 {
6219 if (dst_enumv) {
6220 if (fr_unix_time_from_str(&dst->vb_date, buffer, (fr_time_res_t)dst_enumv->flags.flag_time_res) < 0) return -1;
6221 } else {
6222 if (fr_unix_time_from_str(&dst->vb_date, buffer, FR_TIME_RES_SEC) < 0) return -1;
6223 }
6224
6225 dst->enumv = dst_enumv;
6226 }
6227 break;
6228
6229 case FR_TYPE_IFID:
6230 if (fr_inet_ifid_pton((void *) dst->vb_ifid, buffer) == NULL) {
6231 fr_strerror_printf("Failed to parse interface-id string \"%s\"", buffer);
6232 return -1;
6233 }
6234 break;
6235
6236 default:
6237 fr_strerror_printf("Cannot parse input as data type %s", fr_type_to_str(dst_type));
6238 return -1;
6239 }
6240
6241finish:
6242 dst->type = dst_type;
6243 dst->tainted = false;
6245
6246 /*
6247 * Fixup enumvs
6248 */
6249 dst->enumv = dst_enumv;
6250 fr_value_box_list_entry_init(dst);
6251 VALUE_BOX_VERIFY(dst);
6252
6253 FR_SBUFF_SET_RETURN(in, &our_in);
6254}
6255
6257 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
6258 char const *in, size_t inlen,
6259 fr_sbuff_unescape_rules_t const *erules)
6260{
6261 fr_slen_t slen;
6262 fr_sbuff_parse_rules_t prules = { .escapes = erules };
6263
6264 slen = fr_value_box_from_substr(ctx, dst, dst_type, dst_enumv, &FR_SBUFF_IN(in, inlen), &prules);
6265 if (slen <= 0) return slen;
6266
6267 if (slen != (ssize_t)inlen) {
6268 fr_strerror_printf("Failed parsing '%s'. %zu bytes of trailing data after string value \"%pV\"",
6269 fr_type_to_str(dst_type),
6270 inlen - slen,
6271 fr_box_strvalue_len(in + slen, inlen - slen));
6272 return (slen - inlen) - 1;
6273 }
6274
6275 return slen;
6276}
6277
6278/** Print one boxed value to a string
6279 *
6280 * This function should primarily be used when a #fr_value_box_t is being
6281 * serialized in some non-standard way, i.e. as a value for a field
6282 * in a database, in all other instances it's better to use
6283 * #fr_value_box_print_quoted.
6284 *
6285 * @note - this function does NOT respect tainting! The escaping rules
6286 * are ONLY for escaping quotation characters, CR, LF, etc.
6287 *
6288 * @param[in] out Where to write the printed string.
6289 * @param[in] data Value box to print.
6290 * @param[in] e_rules To apply to FR_TYPE_STRING types, for escaping quotation characters _only_.
6291 * Is not currently applied to any other box type.
6292 */
6294{
6295 fr_sbuff_t our_out = FR_SBUFF(out);
6296
6297 char buf[1024]; /* Interim buffer to use with poorly behaved printing functions */
6298
6299 if (data->enumv && data->enumv->flags.has_value) {
6300 char const *name;
6301
6303 if (name) {
6304 FR_SBUFF_IN_ESCAPE_BUFFER_RETURN(&our_out, name, NULL);
6305 goto done;
6306 }
6307 }
6308
6309 switch (data->type) {
6310 case FR_TYPE_STRING:
6311 if (data->vb_length) FR_SBUFF_IN_ESCAPE_RETURN(&our_out,
6312 data->vb_strvalue, data->vb_length, e_rules);
6313 break;
6314
6315 case FR_TYPE_OCTETS:
6316 FR_SBUFF_IN_CHAR_RETURN(&our_out, '0', 'x');
6317 if (data->vb_length) FR_SBUFF_RETURN(fr_base16_encode, &our_out,
6318 &FR_DBUFF_TMP(data->vb_octets, data->vb_length));
6319 break;
6320
6321 /*
6322 * We need to use the proper inet_ntop functions for IP
6323 * addresses, else the output might not match output of
6324 * other functions, which makes testing difficult.
6325 *
6326 * An example is tunneled ipv4 in ipv6 addresses.
6327 */
6328 case FR_TYPE_IPV4_ADDR:
6329 case FR_TYPE_IPV6_ADDR:
6331 if (!fr_inet_ntop(buf, sizeof(buf), &data->vb_ip)) return 0;
6332 FR_SBUFF_IN_STRCPY_RETURN(&our_out, buf);
6333 break;
6334
6338 if (!fr_inet_ntop_prefix(buf, sizeof(buf), &data->vb_ip)) return 0;
6339 FR_SBUFF_IN_STRCPY_RETURN(&our_out, buf);
6340 break;
6341
6342 case FR_TYPE_IFID:
6343 if (!fr_inet_ifid_ntop(buf, sizeof(buf), data->vb_ifid)) return 0;
6344 FR_SBUFF_IN_STRCPY_RETURN(&our_out, buf);
6345 break;
6346
6347 case FR_TYPE_ETHERNET:
6348 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%02x:%02x:%02x:%02x:%02x:%02x",
6349 data->vb_ether[0], data->vb_ether[1],
6350 data->vb_ether[2], data->vb_ether[3],
6351 data->vb_ether[4], data->vb_ether[5]);
6352 break;
6353
6354 case FR_TYPE_BOOL:
6355 FR_SBUFF_IN_STRCPY_RETURN(&our_out, data->vb_uint8 ? "yes" : "no");
6356 break;
6357
6358 case FR_TYPE_UINT8:
6359 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", data->vb_uint8);
6360 break;
6361
6362 case FR_TYPE_UINT16:
6363 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", data->vb_uint16);
6364 break;
6365
6366 case FR_TYPE_UINT32:
6367 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", data->vb_uint32);
6368 break;
6369
6370 case FR_TYPE_UINT64:
6371 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%" PRIu64, data->vb_uint64);
6372 break;
6373
6374 case FR_TYPE_INT8:
6375 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%d", data->vb_int8);
6376 break;
6377
6378 case FR_TYPE_INT16:
6379 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%d", data->vb_int16);
6380 break;
6381
6382 case FR_TYPE_INT32:
6383 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%d", data->vb_int32);
6384 break;
6385
6386 case FR_TYPE_INT64:
6387 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%" PRId64, data->vb_int64);
6388 break;
6389
6390 case FR_TYPE_FLOAT32:
6391 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%f", (double) data->vb_float32);
6392 break;
6393
6394 case FR_TYPE_FLOAT64:
6395 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%g", data->vb_float64);
6396 break;
6397
6398 case FR_TYPE_DATE:
6399 {
6401
6402 if (data->enumv) res = (fr_time_res_t)data->enumv->flags.flag_time_res;
6403
6404 FR_SBUFF_RETURN(fr_unix_time_to_str, &our_out, data->vb_date, res, true);
6405 break;
6406 }
6407
6408 case FR_TYPE_SIZE:
6409 FR_SBUFF_RETURN(fr_size_to_str, &our_out, data->datum.size);
6410 break;
6411
6412 case FR_TYPE_TIME_DELTA:
6413 {
6415 bool is_unsigned = false;
6416
6417 if (data->enumv) {
6418 res = (fr_time_res_t)data->enumv->flags.flag_time_res;
6419 is_unsigned = data->enumv->flags.is_unsigned;
6420 }
6421
6422
6423 FR_SBUFF_RETURN(fr_time_delta_to_str, &our_out, data->vb_time_delta, res, is_unsigned);
6424 }
6425 break;
6426
6427 case FR_TYPE_GROUP:
6428 /*
6429 * If the caller didn't ask to escape binary data
6430 * in 'octets' types, then we force that now.
6431 * Otherwise any 'octets' type which is buried
6432 * inside of a 'group' will get copied verbatim
6433 * from input to output, with no escaping!
6434 */
6435 if (!e_rules || (!e_rules->do_oct && !e_rules->do_hex)) {
6436 e_rules = &fr_value_escape_double;
6437 }
6438
6439 /*
6440 * Represent groups as:
6441 *
6442 * { <value0>, <value1>, { <sub-value0>, <sub-value1>, <sub-valueN> }}
6443 */
6444 FR_SBUFF_IN_CHAR_RETURN(&our_out, '{');
6446 NULL, &our_out, UNCONST(fr_value_box_list_t *, &data->vb_group),
6447 ", ", (sizeof(", ") - 1), e_rules,
6449 FR_SBUFF_IN_CHAR_RETURN(&our_out, '}');
6450 break;
6451
6452 case FR_TYPE_ATTR: {
6453 fr_dict_attr_t const *parent = NULL;
6454 fr_sbuff_t *unescaped = NULL;
6455
6456 FR_SBUFF_IN_CHAR_RETURN(&our_out, ':', ':');
6457
6458 if (!data->enumv) {
6459 fr_strerror_const("Value of type 'attribute' is missing the enum");
6460 return -1;
6461 }
6462
6463 switch (data->enumv->type) {
6464 case FR_TYPE_TLV:
6465 parent = data->enumv;
6466 break;
6467
6468 case FR_TYPE_ATTR: /* will print from the root */
6469 break;
6470
6471 default:
6472 fr_assert_msg(0, "Invalid data type for 'attr' enumv");
6473 break;
6474 }
6475
6476 /*
6477 * No escaping, just dump the name as-is.
6478 */
6479 if (!e_rules) {
6480 FR_DICT_ATTR_OID_PRINT_RETURN(&our_out, parent, data->vb_attr, false);
6481 break;
6482 }
6483
6484 /*
6485 * Escaping, use an intermediate buffer. Because
6486 * we can't pipe sbuffs together.
6487 */
6488 FR_SBUFF_TALLOC_THREAD_LOCAL(&unescaped, 256, 4096);
6489
6490 FR_DICT_ATTR_OID_PRINT_RETURN(unescaped, parent, data->vb_attr, false);
6491
6492 FR_SBUFF_IN_ESCAPE_RETURN(&our_out, fr_sbuff_start(unescaped),
6493 fr_sbuff_used(unescaped), e_rules);
6494 }
6495 break;
6496
6497 case FR_TYPE_NULL:
6498 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "NULL");
6499 break;
6500
6501 /*
6502 * Don't add default here
6503 */
6504 case FR_TYPE_TLV: /* Not a box type */
6505 case FR_TYPE_STRUCT: /* Not a box type */
6506 case FR_TYPE_VSA: /* Not a box type */
6507 case FR_TYPE_VENDOR: /* Not a box type */
6508 case FR_TYPE_UNION: /* Not a box type */
6509 case FR_TYPE_VALUE_BOX:
6510 case FR_TYPE_VOID:
6511 case FR_TYPE_MAX:
6512 (void)fr_cond_assert(0);
6513 return 0;
6514
6517 FR_SBUFF_IN_STRCPY_RETURN(&our_out, data->vb_cursor_name);
6518 break;
6519 }
6520
6521done:
6522 FR_SBUFF_SET_RETURN(out, &our_out);
6523}
6524
6525/** Print one boxed value to a string with quotes (where needed)
6526 *
6527 * @param[in] out Where to write the printed string.
6528 * @param[in] data Value box to print.
6529 * @param[in] quote To apply to FR_TYPE_STRING types.
6530 * Is not currently applied to any
6531 * other box type.
6532 */
6534{
6535 fr_sbuff_t our_out = FR_SBUFF(out);
6536
6537 if (quote == T_BARE_WORD) return fr_value_box_print(out, data, NULL);
6538
6539 switch (data->type) {
6540 case FR_TYPE_QUOTED:
6541 FR_SBUFF_IN_CHAR_RETURN(&our_out, fr_token_quote[quote]);
6543 FR_SBUFF_IN_CHAR_RETURN(&our_out, fr_token_quote[quote]);
6544 break;
6545
6546 default:
6547 return fr_value_box_print(out, data, NULL);
6548 }
6549
6550 FR_SBUFF_SET_RETURN(out, &our_out);
6551}
6552
6553/** Concatenate a list of value boxes together
6554 *
6555 * All boxes will be removed from the list.
6556 *
6557 * @param[out] safety if !NULL, the results of tainted / secret / safe_for will be stored here.
6558 * @param[out] sbuff to write the result of the concatenation to.
6559 * @param[in] list to concatenate.
6560 * @param[in] sep Insert a separator between the values.
6561 * @param[in] sep_len Length of the separator.
6562 * @param[in] e_rules To apply to FR_TYPE_STRING types.
6563 * Is not currently applied to any other box type.
6564 * @param[in] proc_action What to do with the boxes in the list once
6565 * they've been processed.
6566 * @param[in] safe_for if value has this safe_for value, don't apply the escape rules.
6567 * for values which are escaped, mash the safe_for value to this.
6568 * @param[in] flatten If true and we encounter a #FR_TYPE_GROUP,
6569 * we concat the contents of its children together.
6570 * If false, the contents will be cast to #FR_TYPE_STRING.
6571 * @return
6572 * - >=0 the number of bytes written to the sbuff.
6573 * - <0 how many additional bytes we would have needed to
6574 * concat the next box.
6575 */
6577 char const *sep, size_t sep_len, fr_sbuff_escape_rules_t const *e_rules,
6578 fr_value_box_list_action_t proc_action, fr_value_box_safe_for_t safe_for, bool flatten)
6579{
6580 fr_sbuff_t our_sbuff = FR_SBUFF(sbuff);
6581 ssize_t slen;
6582
6583 if (fr_value_box_list_empty(list)) return 0;
6584
6585 fr_value_box_list_foreach(list, vb) {
6586 fr_value_box_safe_for_t box_safe_for = vb->vb_safefor;
6587
6588 switch (vb->type) {
6589 case FR_TYPE_GROUP:
6590 if (!flatten) goto print;
6591 slen = fr_value_box_list_concat_as_string(safety, &our_sbuff, &vb->vb_group,
6592 sep, sep_len, e_rules,
6593 proc_action, safe_for, flatten);
6594 break;
6595
6596 case FR_TYPE_OCTETS:
6597
6598 /*
6599 * Copy the raw string over, if necessary with escaping.
6600 */
6601 if (e_rules && (!fr_value_box_is_safe_for(vb, safe_for) || e_rules->do_oct || e_rules->do_hex)) {
6602 box_safe_for = safe_for;
6603
6604 slen = fr_sbuff_in_escape(&our_sbuff, (char const *)vb->vb_strvalue, vb->vb_length, e_rules);
6605 } else {
6606 slen = fr_sbuff_in_bstrncpy(&our_sbuff, (char const *)vb->vb_strvalue, vb->vb_length);
6607 }
6608 break;
6609
6610 case FR_TYPE_STRING:
6611 if (!fr_value_box_is_safe_for(vb, safe_for) && e_rules) goto print;
6612
6613 slen = fr_sbuff_in_bstrncpy(&our_sbuff, vb->vb_strvalue, vb->vb_length);
6614 break;
6615
6616 case FR_TYPE_NULL: /* Skip null */
6617 continue;
6618
6619 default:
6620 print:
6621 /*
6622 * If we escaped it, set the output safe_for value.
6623 */
6624 if (e_rules) box_safe_for = safe_for;
6625 slen = fr_value_box_print(&our_sbuff, vb, e_rules);
6626 break;
6627 }
6628 if (slen < 0) return slen;
6629
6630 /*
6631 * Add in the separator
6632 */
6633 if (sep && fr_value_box_list_next(list, vb)) {
6634 slen = fr_sbuff_in_bstrncpy(&our_sbuff, sep, sep_len);
6635 if (slen < 0) return slen;
6636 }
6637
6638 /*
6639 * Merge in the safety rules.
6640 */
6641 if (!safety || (vb->type == FR_TYPE_GROUP)) continue;
6642
6643 /*
6644 * We can't call fr_box_safety_merge(), as we may have escaped the input box.
6645 */
6646 if ((safety->safe_for != FR_VALUE_BOX_SAFE_FOR_NONE) &&
6647 (safety->safe_for != box_safe_for)) {
6648 if (safety->safe_for == FR_VALUE_BOX_SAFE_FOR_ANY) {
6649 safety->safe_for = box_safe_for;
6650 } else if (box_safe_for != FR_VALUE_BOX_SAFE_FOR_ANY) {
6652 }
6653 }
6654
6655 safety->secret |= vb->vb_secret;
6656 }
6657
6658 /*
6659 * Free the boxes last so if there's
6660 * an issue concatenating them, everything
6661 * is still in a known state.
6662 */
6663 fr_value_box_list_foreach(list, vb) {
6664 if (vb_should_remove(proc_action)) fr_value_box_list_remove(list, vb);
6665 if (vb_should_free_value(proc_action)) fr_value_box_clear_value(vb);
6666 if (vb_should_free(proc_action)) talloc_free(vb);
6667 }
6668
6669 FR_SBUFF_SET_RETURN(sbuff, &our_sbuff);
6670}
6671
6673
6674/** Concatenate a list of value boxes together
6675 *
6676 * All boxes will be removed from the list.
6677 *
6678 * @param[out] safety if !NULL, the results of tainted / secret / safe_for will be stored here.
6679 * @param[out] dbuff to write the result of the concatenation to.
6680 * @param[in] list to concatenate.
6681 * @param[in] sep Insert a separator between the values.
6682 * @param[in] sep_len Length of the separator.
6683 * @param[in] proc_action What to do with the boxes in the list once
6684 * they've been processed.
6685 * @param[in] flatten If true and we encounter a #FR_TYPE_GROUP,
6686 * we concat the contents of its children together.
6687 * If false, the contents will be cast to #FR_TYPE_OCTETS.
6688 * @return
6689 * - >=0 the number of bytes written to the sbuff.
6690 * - <0 how many additional bytes we would have needed to
6691 * concat the next box.
6692 */
6694 uint8_t const *sep, size_t sep_len,
6695 fr_value_box_list_action_t proc_action, bool flatten)
6696{
6697 fr_dbuff_t our_dbuff = FR_DBUFF(dbuff);
6698 TALLOC_CTX *tmp_ctx = NULL;
6699 ssize_t slen;
6700
6701 if (fr_value_box_list_empty(list)) return 0;
6702
6703 fr_value_box_list_foreach(list, vb) {
6704 switch (vb->type) {
6705 case FR_TYPE_GROUP:
6706 if (!flatten) goto cast;
6707 slen = fr_value_box_list_concat_as_octets(safety, &our_dbuff, &vb->vb_group,
6708 sep, sep_len,
6709 proc_action, flatten);
6710 break;
6711
6712 case FR_TYPE_OCTETS:
6713 slen = fr_dbuff_in_memcpy(&our_dbuff, vb->vb_octets, vb->vb_length);
6714 break;
6715
6716 case FR_TYPE_STRING:
6717 slen = fr_dbuff_in_memcpy(&our_dbuff, (uint8_t const *)vb->vb_strvalue, vb->vb_length);
6718 break;
6719
6720 case FR_TYPE_NULL: /* Skip null */
6721 continue;
6722
6723 default:
6724 cast:
6725 {
6726 fr_value_box_t tmp_vb;
6727
6728 if (!tmp_ctx) tmp_ctx = talloc_pool(NULL, 1024);
6729
6730 /*
6731 * Not equivalent to fr_value_box_to_network
6732 */
6733 if (fr_value_box_cast_to_octets(tmp_ctx, &tmp_vb, FR_TYPE_OCTETS, NULL, vb) < 0) {
6734 slen = -1;
6735 goto error;
6736 }
6737
6738 slen = fr_dbuff_in_memcpy(&our_dbuff, tmp_vb.vb_octets, tmp_vb.vb_length);
6739 fr_value_box_clear_value(&tmp_vb);
6740 break;
6741 }
6742 }
6743
6744 if (slen < 0) {
6745 error:
6746 talloc_free(tmp_ctx);
6747 return slen;
6748 }
6749
6750 if (sep && fr_value_box_list_next(list, vb)) {
6751 slen = fr_dbuff_in_memcpy(&our_dbuff, sep, sep_len);
6752 if (slen < 0) goto error;
6753 }
6754
6755 if (safety) _value_box_safety_merge(safety, &vb->safety);
6756 }
6757
6758 talloc_free(tmp_ctx);
6759
6760 /*
6761 * Free the boxes last so if there's
6762 * an issue concatenating them, everything
6763 * is still in a known state.
6764 */
6765 fr_value_box_list_foreach(list, vb) {
6766 if (vb_should_remove(proc_action)) fr_value_box_list_remove(list, vb);
6767 if (vb_should_free_value(proc_action)) fr_value_box_clear_value(vb);
6768 if (vb_should_free(proc_action)) talloc_free(vb);
6769 }
6770
6771 return fr_dbuff_set(dbuff, &our_dbuff);
6772}
6773
6774/** Concatenate a list of value boxes
6775 *
6776 * @note Will automatically cast all #fr_value_box_t to type specified.
6777 *
6778 * @param[in] ctx to allocate new value buffer in.
6779 * @param[out] out Where to write the resulting box.
6780 * @param[in] list to concatenate together.
6781 * @param[in] type May be #FR_TYPE_STRING or #FR_TYPE_OCTETS, no other types are
6782 * supported.
6783 * @param[in] proc_action What to do with the boxes in the list once
6784 * they've been processed.
6785 * @param[in] flatten If true and we encounter a #FR_TYPE_GROUP,
6786 * we concat the contents of its children together.
6787 * If false, the contents will be cast to the given type.
6788 * @param[in] max_size of the value.
6789 * @return
6790 * - 0 on success.
6791 * - -1 on failure.
6792 */
6794 fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type,
6795 fr_value_box_list_action_t proc_action, bool flatten,
6796 size_t max_size)
6797{
6798 fr_dbuff_t dbuff; /* FR_TYPE_OCTETS */
6799 fr_dbuff_uctx_talloc_t dbuff_tctx;
6800
6801 fr_sbuff_t sbuff; /* FR_TYPE_STRING */
6802 fr_sbuff_uctx_talloc_t sbuff_tctx;
6803
6804 fr_value_box_t *head_vb = fr_value_box_list_head(list);
6805
6806 fr_value_box_entry_t entry;
6807 fr_value_box_safety_t safety = { .safe_for = FR_VALUE_BOX_SAFE_FOR_ANY }; /* Merged safety of every box, applied to out at the end */
6808
6809 if (fr_value_box_list_empty(list)) {
6810 fr_strerror_const("Invalid arguments. List contains no elements");
6811 return -1;
6812 }
6813
6814 /*
6815 * Exit quickly if the list is only one box of the correct type and
6816 * out points at that box.
6817 */
6818 if ((fr_value_box_list_num_elements(list) == 1) && (head_vb == out) && (head_vb->type == type)) return 0;
6819
6820 /*
6821 * The accumulator starts as "safe for anything", the identity for the merge,
6822 * and each box narrows it. The constructor below re-initialises out, so the
6823 * merged safety is applied to out afterwards.
6824 */
6825
6826 switch (type) {
6827 case FR_TYPE_STRING:
6828 if (unlikely(!fr_sbuff_init_talloc(ctx, &sbuff, &sbuff_tctx, 256, max_size))) return -1;
6829 break;
6830
6831 case FR_TYPE_OCTETS:
6832 if (unlikely(!fr_dbuff_init_talloc(ctx, &dbuff, &dbuff_tctx, 256, max_size))) return -1;
6833 break;
6834
6835 default:
6836 fr_strerror_printf("Invalid argument. Can't concatenate boxes to type %s",
6838 return -1;
6839 }
6840
6841 /*
6842 * Merge all siblings into list head.
6843 *
6844 * This is where the first element in the
6845 * list is the output box.
6846 *
6847 * i.e. we want to merge all its siblings
6848 * into it.
6849 */
6850 if (out == head_vb) {
6851 switch (type) {
6852 case FR_TYPE_STRING:
6853 /*
6854 * Head gets dealt with specially as we don't
6855 * want to free it, and we don't want to free
6856 * the buffer associated with it (just yet).
6857 *
6858 * Note that we don't convert 'octets' to a printable string
6859 * here. Doing so breaks the keyword tests.
6860 */
6861 if (fr_value_box_list_concat_as_string(&safety, &sbuff, list,
6862 NULL, 0, NULL,
6864 fr_strerror_printf("Concatenation exceeded max_size (%zu)", max_size);
6865 error:
6866 switch (type) {
6867 case FR_TYPE_STRING:
6868 talloc_free(fr_sbuff_buff(&sbuff));
6869 break;
6870
6871 case FR_TYPE_OCTETS:
6872 talloc_free(fr_dbuff_buff(&dbuff));
6873 break;
6874
6875 default:
6876 break;
6877 }
6878 return -1;
6879 }
6880
6881 /*
6882 * Concat the rest of the children...
6883 */
6884 if (fr_value_box_list_concat_as_string(&safety, &sbuff, list,
6885 NULL, 0, NULL,
6886 proc_action, FR_VALUE_BOX_SAFE_FOR_ANY, flatten) < 0) {
6887 fr_value_box_list_insert_head(list, head_vb);
6888 goto error;
6889 }
6890 (void)fr_sbuff_trim_talloc(&sbuff, SIZE_MAX);
6892 if (fr_value_box_bstrndup(ctx, out, NULL, fr_sbuff_buff(&sbuff), fr_sbuff_used(&sbuff), out->tainted) < 0) goto error;
6893 fr_value_box_safety_set(out, &safety);
6894 break;
6895
6896 case FR_TYPE_OCTETS:
6897 if (fr_value_box_list_concat_as_octets(&safety, &dbuff, list,
6898 NULL, 0,
6899 FR_VALUE_BOX_LIST_REMOVE, flatten) < 0) goto error;
6900
6901 if (fr_value_box_list_concat_as_octets(&safety, &dbuff, list,
6902 NULL, 0,
6903 proc_action, flatten) < 0) {
6904 fr_value_box_list_insert_head(list, head_vb);
6905 goto error;
6906 }
6907 (void)fr_dbuff_trim_talloc(&dbuff, SIZE_MAX);
6909 if (fr_value_box_memdup(ctx, out, NULL, fr_dbuff_buff(&dbuff), fr_dbuff_used(&dbuff), out->tainted) < 0) goto error;
6910 fr_value_box_safety_set(out, &safety);
6911 break;
6912
6913 default:
6914 break;
6915 }
6916
6917 fr_value_box_list_insert_head(list, out);
6918
6919 /*
6920 * Merge all the boxes in the list into
6921 * a single contiguous buffer.
6922 *
6923 * This deals with an unrelated out and list
6924 * and also where list is the children of
6925 * out.
6926 */
6927 } else {
6928 switch (type) {
6929 case FR_TYPE_STRING:
6930 if (fr_value_box_list_concat_as_string(&safety, &sbuff, list,
6931 NULL, 0, NULL,
6932 proc_action, FR_VALUE_BOX_SAFE_FOR_ANY, flatten) < 0) goto error;
6933 (void)fr_sbuff_trim_talloc(&sbuff, SIZE_MAX);
6934
6935 entry = out->entry;
6936 if (fr_value_box_bstrndup(ctx, out, NULL, fr_sbuff_buff(&sbuff), fr_sbuff_used(&sbuff), out->tainted) < 0) goto error;
6937 out->entry = entry;
6938 fr_value_box_safety_set(out, &safety);
6939 break;
6940
6941 case FR_TYPE_OCTETS:
6942 if (fr_value_box_list_concat_as_octets(&safety, &dbuff, list,
6943 NULL, 0,
6944 proc_action, flatten) < 0) goto error;
6945 (void)fr_dbuff_trim_talloc(&dbuff, SIZE_MAX);
6946
6947 entry = out->entry;
6948 if (fr_value_box_memdup(ctx, out, NULL, fr_dbuff_buff(&dbuff), fr_dbuff_used(&dbuff), out->tainted) < 0) goto error;
6949 out->entry = entry;
6950 fr_value_box_safety_set(out, &safety);
6951 break;
6952
6953 default:
6954 break;
6955 }
6956 }
6957
6958 return 0;
6959}
6960
6961/** Escape a single value box in place
6962 *
6963 * @note Applies recursively to the children of group boxes.
6964 *
6965 * @param[in] vb to escape.
6966 * @param[in] escape escape definition to apply to the value box.
6967 * @param[in] uctx user context to pass to the escape function.
6968 * @return
6969 * - 0 on success.
6970 * - -1 on failure.
6971 */
6973{
6974 int ret;
6975
6976 switch (vb->type) {
6977 case FR_TYPE_GROUP:
6978 return fr_value_box_list_escape_in_place(&vb->vb_group, escape, uctx);
6979
6980 case FR_TYPE_NULL:
6981 case FR_TYPE_TLV:
6982 case FR_TYPE_STRUCT:
6983 case FR_TYPE_VSA:
6984 case FR_TYPE_VENDOR:
6985 case FR_TYPE_INTERNAL:
6986 fr_strerror_printf("Cannot escape data type '%s'", fr_type_to_str(vb->type));
6987 return -1;
6988
6989 case FR_TYPE_ATTR:
6990 fr_assert(0); /* @todo - print to string, and then escape? */
6991 fr_strerror_printf("Cannot escape data type '%s'", fr_type_to_str(vb->type));
6992 return -1;
6993
6994 default:
6995 break;
6996 }
6997
6998 /*
6999 * Don't do double escaping.
7000 */
7001 if (!escape->always_escape && fr_value_box_is_safe_for(vb, escape->safe_for)) return 0;
7002
7003 ret = escape->func(vb, uctx);
7004 if (unlikely(ret < 0)) return ret;
7005
7006 /*
7007 * '1' means that the function mashed the safe_for value, so we don't need to.
7008 */
7009 if (!ret) vb->vb_safefor = escape->safe_for;
7010 vb->tainted = false;
7011
7012 return 0;
7013}
7014
7015/** Escape a list of value boxes in place
7016 *
7017 * @note Applies recursively to the children of group boxes.
7018 *
7019 * @note on error, the list may be left in an inconsistent/partially escaped state.
7020 *
7021 * @param[in] list to escape.
7022 * @param[in] escape escape definition to apply to the value box.
7023 * @param[in] uctx user context to pass to the escape function.
7024 * @return
7025 * - 0 on success.
7026 * - -1 on failure.
7027 */
7028int fr_value_box_list_escape_in_place(fr_value_box_list_t *list, fr_value_box_escape_t const *escape, void *uctx)
7029{
7030 int ret = 0;
7031
7032 fr_value_box_list_foreach(list, vb) {
7033 ret = fr_value_box_escape_in_place(vb, escape, uctx);
7034 if (unlikely(ret < 0)) return ret;
7035 }
7036
7037 return ret;
7038}
7039
7044
7045static int _value_box_escape_rules(fr_value_box_t *vb, void *uctx)
7046{
7048
7049 if (fr_type_is_leaf(vb->type)) {
7050 if (fr_value_box_escape_in_place_erules(ctx->ctx, vb, ctx->erules) < 0) return -1;
7051
7052 return 1; /* safe_for has been updated */
7053 }
7054
7058 .safe_for = (fr_value_box_safe_for_t) ctx->erules,
7059 .always_escape = false,
7060 },
7062 .ctx = vb,
7063 .erules = ctx->erules,
7064 }
7065 );
7066}
7067
7068/** Escape a value-box in place using sbuff escaping rules, and mark it safe-for.
7069 *
7070 * If the input type isn't a string, then it is converted to a string.
7071 *
7072 * The output type is always #FR_TYPE_STRING
7073 *
7074 * @param[in] ctx to allocate any new buffers in.
7075 * @param[in] vb which will be escaped
7076 * @param[in] erules escape rules
7077 * @return
7078 * - <0 for error, generally OOM
7079 * - 0 for success (did not set safe_for)
7080 * - 1 for success (did set safe_for)
7081 */
7083{
7084 ssize_t slen;
7085 fr_sbuff_t *escaped = NULL;
7086
7087 FR_SBUFF_TALLOC_THREAD_LOCAL(&escaped, 256, 4096);
7088
7089 /*
7090 * Structural types are much more complicated. :(
7091 */
7092 if (!fr_type_is_leaf(vb->type)) {
7093 int rcode;
7094
7098 .safe_for = (fr_value_box_safe_for_t) erules,
7099 .always_escape = false,
7100 },
7102 .ctx = ctx,
7103 .erules = erules,
7104 }
7105 );
7106 if (rcode < 0) return rcode;
7107
7108 slen = fr_value_box_list_concat_as_string(NULL, escaped, &vb->vb_group, NULL, 0, NULL,
7110 (fr_value_box_safe_for_t) erules, true);
7111 if (slen < 0) return -1;
7112
7113 fr_assert(fr_value_box_list_num_elements(&vb->vb_group) == 0);
7114
7115 goto set_value;
7116 }
7117
7118 if (vb->type != FR_TYPE_STRING) {
7119 if (fr_value_box_cast_in_place(ctx, vb, FR_TYPE_STRING, NULL) < 0) return -1;
7120 } else {
7121 if (fr_value_box_is_safe_for(vb, erules)) return 0;
7122 }
7123
7124 slen = fr_sbuff_in_escape(escaped, vb->vb_strvalue, vb->vb_length, erules);
7125 if (slen < 0) return -1;
7126
7127set_value:
7128 if (fr_value_box_bstrndup(ctx, vb, NULL, fr_sbuff_start(escaped), fr_sbuff_used(escaped), false) < 0) return -1;
7129
7130 fr_value_box_mark_safe_for(vb, erules);
7131
7132 return 1;
7133}
7134
7135/** Escape a value-box in place using the supplied #fr_sbuff_escape_rules_t in uctx
7136 *
7137 * If the input type isn't a string, then it is converted to a string.
7138 *
7139 * The output type is always #FR_TYPE_STRING
7140 *
7141 * @param[in] vb which will be escaped
7142 * @param[in] uctx escape rules
7143 * @return
7144 * - <0 for error, generally OOM
7145 * - 0 for success (did not set safe_for)
7146 * - 1 for success (did set safe_for)
7147 */
7149{
7150 return fr_value_box_escape_in_place_erules(vb, vb, uctx);
7151}
7152
7153/** Escape a value box in place using an sbuff escape function
7154 *
7155 * If the input type isn't a string, then it is converted to a string.
7156 *
7157 * The output type is always #FR_TYPE_STRING. The safe_for and tainted
7158 * flags are left as they were. The caller marks the box once it knows
7159 * which dialect the escape function produced.
7160 *
7161 * @param[in] ctx to allocate the escaped string in.
7162 * @param[in] vb which will be escaped. Must be a leaf type.
7163 * @param[in] escape function to run over the string value.
7164 * @return
7165 * - <0 for error, generally OOM.
7166 * - 0 for success.
7167 */
7168int fr_value_box_escape_in_place_func(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_sbuff_escape_func_t escape)
7169{
7170 fr_sbuff_t *escaped = NULL;
7171
7172 fr_assert(fr_type_is_leaf(vb->type));
7173
7174 if ((vb->type != FR_TYPE_STRING) && (fr_value_box_cast_in_place(ctx, vb, FR_TYPE_STRING, NULL) < 0)) {
7175 return -1;
7176 }
7177
7178 FR_SBUFF_TALLOC_THREAD_LOCAL(&escaped, 256, SIZE_MAX);
7179
7180 if (escape(escaped, &FR_SBUFF_IN(vb->vb_strvalue, vb->vb_length)) < 0) return -1;
7181
7182 return fr_value_box_bstrndup_replace(ctx, vb, fr_sbuff_start(escaped), (ssize_t)fr_sbuff_used(escaped));
7183}
7184
7185
7186/** Removes a single layer of nesting, moving all children into the parent list
7187 *
7188 * @param[in] ctx to reparent children in if steal is true.
7189 * @param[in] list to flatten.
7190 * @param[in] steal whether to change the talloc ctx of children.
7191 * @param[in] free whether to free any group boxes which have had
7192 * their children removed.
7193 */
7194void fr_value_box_flatten(TALLOC_CTX *ctx, fr_value_box_list_t *list, bool steal, bool free)
7195{
7196 fr_value_box_list_foreach(list, child) {
7197 if (!fr_type_is_structural(child->type)) continue;
7198
7199 fr_value_box_list_foreach(&child->vb_group, grandchild) {
7200 fr_value_box_list_remove(&child->vb_group, grandchild);
7201 if (steal) talloc_steal(ctx, grandchild);
7202 fr_value_box_list_insert_before(list, child, grandchild);
7203 }
7204
7205 if (free) talloc_free(child);
7206 }
7207}
7208
7209/** Concatenate the string representations of a list of value boxes together
7210 *
7211 * @param[in] ctx to allocate the buffer in.
7212 * @param[in] list of value boxes.
7213 * @param[in] delim to insert between value box values.
7214 * @param[in] e_rules to control escaping of the concatenated elements.
7215 * @return
7216 * - NULL on error.
7217 * - The concatenation of the string values of the value box list on success.
7218 */
7219char *fr_value_box_list_aprint(TALLOC_CTX *ctx, fr_value_box_list_t const *list, char const *delim,
7220 fr_sbuff_escape_rules_t const *e_rules)
7221{
7222 fr_value_box_t const *vb = fr_value_box_list_head(list);
7223 char *aggr, *td = NULL;
7224 TALLOC_CTX *pool = NULL;
7225
7226 if (!vb) return NULL;
7227
7228 fr_value_box_aprint(ctx, &aggr, vb, e_rules);
7229 if (!aggr) return NULL;
7230 if (!fr_value_box_list_next(list, vb)) return aggr;
7231
7232 /*
7233 * If we're aggregating more values,
7234 * allocate a temporary pool.
7235 */
7236 pool = talloc_pool(NULL, 255);
7237 if (delim) td = talloc_strdup(pool, delim);
7238
7239 while ((vb = fr_value_box_list_next(list, vb))) {
7240 char *str, *new_aggr;
7241
7242 fr_value_box_aprint(pool, &str, vb, e_rules);
7243 if (!str) continue;
7244
7245 new_aggr = talloc_buffer_append_variadic_buffer(ctx, aggr, 2, td, str);
7246 if (unlikely(!new_aggr)) {
7247 talloc_free(aggr);
7248 talloc_free(pool);
7249 return NULL;
7250 }
7251 aggr = new_aggr;
7252 talloc_free(str);
7253 }
7254 talloc_free(pool);
7255
7256 return aggr;
7257}
7258
7259/** Concatenate the string representations of a list of value boxes together hiding "secret" values
7260 *
7261 * @param[in] ctx to allocate the buffer in.
7262 * @param[in] list of value boxes.
7263 * @param[in] delim to insert between value box values.
7264 * @param[in] e_rules to control escaping of the concatenated elements.
7265 * @return
7266 * - NULL on error.
7267 * - The concatenation of the string values of the value box list on success.
7268 */
7269char *fr_value_box_list_aprint_secure(TALLOC_CTX *ctx, fr_value_box_list_t const *list, char const *delim,
7270 fr_sbuff_escape_rules_t const *e_rules)
7271{
7272 fr_value_box_t const *vb = fr_value_box_list_head(list);
7273 char *aggr, *td = NULL;
7274 TALLOC_CTX *pool = NULL;
7275
7276 if (!vb) return NULL;
7277
7279 aggr = talloc_strdup(ctx, "<<< secret >>>");
7280 } else {
7281 fr_value_box_aprint(ctx, &aggr, vb, e_rules);
7282 }
7283 if (!aggr) return NULL;
7284 if (!fr_value_box_list_next(list, vb)) return aggr;
7285
7286 /*
7287 * If we're aggregating more values,
7288 * allocate a temporary pool.
7289 */
7290 pool = talloc_pool(NULL, 255);
7291 if (delim) td = talloc_strdup(pool, delim);
7292
7293 while ((vb = fr_value_box_list_next(list, vb))) {
7294 char *str, *new_aggr;
7295
7297 str = talloc_strdup(pool, "<<< secret >>>");
7298 } else {
7299 fr_value_box_aprint(pool, &str, vb, e_rules);
7300 }
7301 if (!str) continue;
7302
7303 new_aggr = talloc_buffer_append_variadic_buffer(ctx, aggr, 2, td, str);
7304 if (unlikely(!new_aggr)) {
7305 talloc_free(aggr);
7306 talloc_free(pool);
7307 return NULL;
7308 }
7309 aggr = new_aggr;
7310 talloc_free(str);
7311 }
7312 talloc_free(pool);
7313
7314 return aggr;
7315}
7316
7317/** Hash the contents of a value box
7318 *
7319 */
7321{
7322 switch (vb->type) {
7323 case FR_TYPE_FIXED_SIZE:
7324 return fr_hash(fr_value_box_raw(vb, vb->type),
7325 fr_value_box_field_sizes[vb->type]);
7326
7327 case FR_TYPE_STRING:
7328 return fr_hash(vb->vb_strvalue, vb->vb_length);
7329
7330 case FR_TYPE_OCTETS:
7331 return fr_hash(vb->vb_octets, vb->vb_length);
7332
7333 case FR_TYPE_ATTR:
7334 return fr_hash(&vb->vb_attr, sizeof(vb->vb_attr));
7335
7336 case FR_TYPE_STRUCTURAL:
7337 case FR_TYPE_INTERNAL:
7340 case FR_TYPE_NULL:
7341 fr_assert(0);
7342 break;
7343 }
7344
7345 return 0;
7346}
7347
7348/** Do a full copy of a list of value boxes
7349 *
7350 * @param[in] ctx to allocate boxes in.
7351 * @param[out] out Where to write the head of the new list.
7352 * @param[in] in boxes to copy.
7353 * @return
7354 * - A duplicate list of value boxes, allocated in the context of 'ctx'
7355 * - NULL on error, or empty input list.
7356 */
7357int fr_value_box_list_acopy(TALLOC_CTX *ctx, fr_value_box_list_t *out, fr_value_box_list_t const *in)
7358{
7359 fr_value_box_t const *in_p = NULL;
7360
7361 while ((in_p = fr_value_box_list_next(in, in_p))) {
7362 fr_value_box_t *n = NULL;
7363
7365 if (!n) {
7366 error:
7367 fr_value_box_list_talloc_free(out);
7368 return -1;
7369 }
7370
7371 if (fr_value_box_copy(n, n, in_p) < 0) goto error;
7372 fr_dlist_insert_tail(fr_value_box_list_dlist_head(out), n);
7373 }
7374
7375 return 0;
7376}
7377
7378/** Check to see if any list members (or their children) are tainted
7379 *
7380 * @param[in] head of list to check.
7381 * @return
7382 * - true if a list member is tainted.
7383 * - false if no list members are tainted.
7384 */
7385bool fr_value_box_list_tainted(fr_value_box_list_t const *head)
7386{
7387 fr_value_box_t *vb = NULL;
7388
7389 while ((vb = fr_value_box_list_next(head, vb))) {
7390 if (fr_type_is_group(vb->type) && fr_value_box_list_tainted(&vb->vb_group)) return true;
7391 if (vb->tainted) return true;
7392 }
7393
7394 return false;
7395}
7396
7397#if defined(WITH_VERIFY_PTR) || !defined(NDEBUG)
7398#define VB_NAME "fr_value_box_t %p (from %s:%d)"
7399#define VB_NAME_LOCATION(_x) (void const *) (_x), (_x)->file ? (_x)->file : "", (_x)->line
7400
7401/** Validation function to check that a fr_value_box_t is correctly initialised
7402 *
7403 */
7404void fr_value_box_verify(char const *file, int line, fr_value_box_t const *vb)
7405{
7407 /*
7408 * nonnull only does something if we're building
7409 * with ubsan... We still want to assert event
7410 * if we're building without sanitizers.
7411 */
7412 fr_fatal_assert_msg(vb, "CONSISTENCY CHECK FAILED %s[%i]: fr_value_box_t pointer was NULL", file, line);
7414
7415 if (VERIFY_IS_SET(vb)) return;
7416
7417 if (vb->talloced) vb = talloc_get_type_abort_const(vb, fr_value_box_t);
7418
7419#ifndef NDEBUG
7420 fr_fatal_assert_msg(vb->magic == FR_VALUE_BOX_MAGIC, "CONSISTENCY CHECK FAILED %s[%i]: " VB_NAME " magic "
7421 "incorrect, expected %" PRIx64 ", got %" PRIx64,
7422 file, line,
7423 VB_NAME_LOCATION(vb),
7424 FR_VALUE_BOX_MAGIC, vb->magic);
7425#endif
7426 switch (vb->type) {
7427 case FR_TYPE_STRING:
7428 if (!vb->vb_length) {
7429#if 0
7430 fr_fatal_assert_msg(!vb->vb_strvalue || (talloc_array_length(vb->vb_strvalue) == 1), "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " strvalue field "
7431 "wasn non-NULL, but length was %u",
7432 file, line,
7433 VB_NAME_LOCATION(vb),
7434 vb->vb_length);
7435#endif
7436 break;
7437 }
7438
7439 fr_fatal_assert_msg(vb->vb_strvalue, "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " strvalue field "
7440 "was NULL", file, line, VB_NAME_LOCATION(vb));
7441 fr_fatal_assert_msg(vb->vb_strvalue[vb->vb_length] == '\0',
7442 "CONSISTENCY CHECK FAILED %s[%i]: " VB_NAME " strvalue field "
7443 "not null terminated", file, line, VB_NAME_LOCATION(vb));
7444 if (vb->talloced) {
7445 size_t len = talloc_array_length(vb->vb_strvalue);
7446
7447 /* We always \0 terminate to be safe, even though most things should use the len field */
7448 if (len <= vb->vb_length) {
7449 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: Expected " VB_NAME " strvalue talloc buffer "
7450 "len >= %zu, got %zu",
7451 file, line,
7452 VB_NAME_LOCATION(vb),
7453 vb->vb_length + 1, len);
7454 }
7455 }
7456 break;
7457
7458 case FR_TYPE_OCTETS:
7459 if (!vb->vb_length) {
7460#if 0
7461 fr_fatal_assert_msg(!vb->vb_octets || (talloc_array_length(vb->vb_octets) == 0), "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " octets field "
7462 "wasn non-NULL, but length was %u",
7463 file, line,
7464 VB_NAME_LOCATION(vb).
7465 vb->vb_length);
7466#endif
7467 break;
7468 }
7469
7470 fr_fatal_assert_msg(vb->vb_octets, "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " octets field "
7471 "was NULL", file, line, VB_NAME_LOCATION(vb));
7472 break;
7473
7474 case FR_TYPE_VOID:
7475 fr_fatal_assert_msg(vb->vb_void, "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " ptr field "
7476 "was NULL", file, line, VB_NAME_LOCATION(vb));
7477 break;
7478
7479 case FR_TYPE_GROUP:
7480 fr_value_box_list_verify(file, line, &vb->vb_group);
7481 break;
7482
7483 case FR_TYPE_ATTR:
7484 fr_fatal_assert_msg(vb->vb_attr, "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " vb_attr field "
7485 "was NULL", file, line, VB_NAME_LOCATION(vb));
7486 break;
7487
7488 case FR_TYPE_BOOL:
7489 fr_fatal_assert_msg(vb->vb_uint8 <= 1, "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " vb_bool field "
7490 "was not boolean!", file, line, VB_NAME_LOCATION(vb));
7491 break;
7492
7493 default:
7494 break;
7495 }
7496
7497 VERIFY_SET(vb);
7498}
7499
7500void fr_value_box_list_verify(char const *file, int line, fr_value_box_list_t const *list)
7501{
7503}
7504#endif
7505
7506/** Mark a value-box as "safe", of a particular type.
7507 *
7508 */
7510{
7511 /*
7512 * Don't over-ride value-boxes which are already safe, unless we want to mark them as being
7513 * completely unsafe.
7514 */
7515 if ((vb->vb_safefor == FR_VALUE_BOX_SAFE_FOR_ANY) &&
7516 (safe_for != FR_VALUE_BOX_SAFE_FOR_NONE)) {
7517 fr_assert(!vb->tainted);
7518 return;
7519 }
7520
7521 vb->vb_safefor = safe_for;
7522}
7523
7524/** Mark a value-box as "unsafe"
7525 *
7526 * This always succeeds, and there are no side effects.
7527 */
7529{
7530 vb->vb_safefor = FR_VALUE_BOX_SAFE_FOR_NONE;
7531}
7532
7533/** Set the escaped flag for all value boxes in a list
7534 *
7535 * @note Only operates on a single level.
7536 *
7537 * @param[in] list to operate on.
7538 * @param[in] safe_for value to set.
7539 */
7540void fr_value_box_list_mark_safe_for(fr_value_box_list_t *list, fr_value_box_safe_for_t safe_for)
7541{
7542 fr_value_box_list_foreach(list, vb) {
7543 /*
7544 * Don't over-ride value-boxes which are already safe.
7545 */
7546 if (vb->vb_safefor == FR_VALUE_BOX_SAFE_FOR_ANY) {
7547 fr_assert(!vb->tainted);
7548
7549 } else {
7550 vb->vb_safefor = safe_for;
7551 }
7552 }
7553}
7554
7555/** Copy the safety values from one box to another.
7556 *
7557 */
7559{
7560 if (out == in) return;
7561
7562 out->vb_safefor = in->vb_safefor;
7563 out->tainted = in->tainted;
7564 out->vb_secret = in->vb_secret;
7565}
7566
7567/** Copy the safety values from one box to another.
7568 *
7569 * But note that we have changed the output format, so we reset the "safe_for" value to NONE.
7570 */
7572{
7573 out->vb_safefor = FR_VALUE_BOX_SAFE_FOR_NONE;
7574 out->tainted = in->tainted;
7575 out->vb_secret = in->vb_secret;
7576}
7577
7578/** Merge one safety into another
7579 *
7580 * @param[in,out] out safety to narrow.
7581 * @param[in] in safety to merge in.
7582 */
7584{
7585 if (out == in) return;
7586
7587 /*
7588 * If we're already at no safety, then we don't need to do anything.
7589 *
7590 * Otherwise we update the safety only if we need to change it.
7591 */
7592 if ((out->safe_for != FR_VALUE_BOX_SAFE_FOR_NONE) &&
7593 (out->safe_for != in->safe_for)) {
7594 /*
7595 * If the output is anything, then the input is more restrictive, so we switch to that.
7596 *
7597 * If the input is anything, then the output is already the more restrictive of the
7598 * two, so we leave it alone.
7599 *
7600 * Otherwise the values are different. Either it's X/Y, or NONE/X, or X/NONE. In which
7601 * case the answer is always NONE.
7602 */
7603 if (out->safe_for == FR_VALUE_BOX_SAFE_FOR_ANY) {
7604 out->safe_for = in->safe_for;
7605
7606 } else if (in->safe_for != FR_VALUE_BOX_SAFE_FOR_ANY) {
7607 out->safe_for = FR_VALUE_BOX_SAFE_FOR_NONE;
7608 }
7609 }
7610
7611 out->secret |= in->secret;
7612}
7613
7614/** Merge safety results.
7615 */
7617{
7618 _value_box_safety_merge(&out->safety, &in->safety);
7619 out->tainted |= in->tainted;
7620}
7621
7622/** Replace the safety of a box
7623 *
7624 * @param[out] box to update.
7625 * @param[in] safety to copy into the box.
7626 */
7628{
7629 box->safety = *safety;
7630}
7631
7632/** Mark a box as holding a secret, or not
7633 *
7634 * A structural value has no safety of its own, the children carry theirs. In a
7635 * #fr_pair_t the children list overlays the safety field, so a structural box is
7636 * left alone rather than written to.
7637 */
7639{
7640 if (fr_type_is_structural(box->type)) return;
7641
7642 box->vb_secret = secret;
7643}
7644
7645/** Merge the safety of every leaf box in a list into out
7646 *
7647 * Recurses into group boxes, which carry no safety of their own.
7648 */
7649static void _value_box_list_safety_merge(fr_value_box_t *out, fr_value_box_list_t const *list)
7650{
7651 fr_value_box_list_foreach(list, vb) {
7652 if (fr_type_is_group(vb->type)) {
7653 _value_box_list_safety_merge(out, &vb->vb_group);
7654 continue;
7655 }
7656
7658 }
7659}
7660
7661/** Set the safety of out to the most restrictive safety of any leaf box in a list
7662 *
7663 * Use when a value is built from several boxes without going through
7664 * #fr_value_box_list_concat_in_place, e.g. when a separator is inserted between them.
7665 * A box safe for consumer X, joined with a box safe for X or for anything, is still
7666 * safe for X. Any other combination is safe for nothing.
7667 *
7668 * @param[out] out Box whose safety is replaced. Its value is left alone.
7669 * @param[in] list Boxes to merge. Group boxes are descended into.
7670 */
7671void fr_value_box_list_safety_merge(fr_value_box_t *out, fr_value_box_list_t const *list)
7672{
7673 out->vb_safefor = FR_VALUE_BOX_SAFE_FOR_ANY;
7674 out->vb_secret = false;
7675
7677}
7678
7679
7680/** Check truthiness of values.
7681 *
7682 * The casting rules for expressions / conditions are slightly
7683 * different than fr_value_box_cast(). Largely because that
7684 * function is used to parse configuration files, and parses "yes
7685 * / no" and "true / false" strings, even if there's no
7686 * fr_dict_attr_t passed to it.
7687 */
7689{
7690 fr_value_box_t box;
7691
7692 switch (in->type) {
7693 case FR_TYPE_NULL:
7697 case FR_TYPE_ATTR:
7698 case FR_TYPE_INTERNAL:
7699 break;
7700
7701 case FR_TYPE_GROUP:
7702 return (fr_value_box_list_num_elements(&in->vb_group) > 0);
7703
7704 case FR_TYPE_BOOL:
7705 return in->vb_bool;
7706
7707 case FR_TYPE_STRING:
7708 case FR_TYPE_OCTETS:
7709 return (in->vb_length > 0);
7710
7711 case FR_TYPE_IPV4_ADDR:
7712 case FR_TYPE_IPV6_ADDR:
7713 return !fr_ipaddr_is_inaddr_any(&in->vb_ip);
7714
7717 return !((in->vb_ip.prefix == 0) && fr_ipaddr_is_inaddr_any(&in->vb_ip));
7718
7720 case FR_TYPE_FLOAT32:
7721 case FR_TYPE_FLOAT64:
7722 case FR_TYPE_IFID:
7723 case FR_TYPE_ETHERNET:
7725 if (fr_value_box_cast(NULL, &box, FR_TYPE_BOOL, NULL, in) < 0) return false;
7726 return box.vb_bool;
7727 }
7728
7729 return false;
7730}
7731
7732#define INFO_INDENT(_fmt, ...) fprintf(fp, "%*s" _fmt "\n", depth * 2, " ", ## __VA_ARGS__)
7733
7734static void _fr_value_box_debug(FILE *fp, fr_value_box_t const *vb, int depth, int idx);
7735static void _fr_value_box_list_debug(FILE *fp, fr_value_box_list_t const *head, int depth)
7736{
7737 int i = 0;
7738
7739 INFO_INDENT("{");
7741 INFO_INDENT("}");
7742}
7743
7744/** Print a list of value boxes as info messages
7745 *
7746 * @note Call directly from the debugger
7747 */
7748void fr_value_box_list_debug(FILE *fp, fr_value_box_list_t const *head)
7749{
7751}
7752
7753static void _fr_value_box_debug(FILE *fp, fr_value_box_t const *vb, int depth, int idx)
7754{
7755 char *value;
7756 char buffer[64];
7757
7758 if (fr_type_is_structural(vb->type)) {
7759 _fr_value_box_list_debug(fp, &vb->vb_group, depth + 1);
7760 return;
7761 }
7762
7763 buffer[0] = '\0';
7764 if (vb->type == FR_TYPE_TIME_DELTA) {
7765 if (!vb->enumv) {
7766 snprintf(buffer, sizeof(buffer), " (sec!) %" PRId64, fr_time_delta_unwrap(vb->vb_time_delta));
7767 } else {
7768 snprintf(buffer, sizeof(buffer), " (%s) %" PRId64,
7769 fr_table_str_by_value(fr_time_precision_table, (fr_time_res_t)vb->enumv->flags.flag_time_res, "?"),
7770 fr_time_delta_unwrap(vb->vb_time_delta));
7771 }
7772 }
7773
7774 fr_value_box_aprint(NULL, &value, vb, NULL);
7775 if (idx >= 0) {
7776 INFO_INDENT("[%d] (%s) %s", idx, fr_type_to_str(vb->type), value);
7777 INFO_INDENT(" %s %s %lx%s",
7778 vb->vb_secret ? "s" : "-",
7779 vb->tainted ? "t" : "-",
7780 vb->vb_safefor, buffer);
7781 } else {
7782 INFO_INDENT("(%s) %s", fr_type_to_str(vb->type), value);
7783 INFO_INDENT(" %s %s %lx%s",
7784 vb->vb_secret ? "s" : "-",
7785 vb->tainted ? "t" : "-",
7786 vb->vb_safefor, buffer);
7787 }
7789}
7790
7791/** Print the value of a box as info messages
7792 *
7793 * @note Call directly from the debugger
7794 */
7795void fr_value_box_debug(FILE *fp, fr_value_box_t const *vb)
7796{
7797 _fr_value_box_debug(fp, vb, 0, -1);
7798}
static int const char char buffer[256]
Definition acutest.h:641
int const char * file
Definition acutest.h:855
va_end(args)
int n
Definition acutest.h:642
static int const char * fmt
Definition acutest.h:638
void int line
Definition acutest.h:810
va_start(args, fmt)
#define fr_base16_encode(_out, _in)
Definition base16.h:71
#define fr_base16_decode(_err, _out, _in, _no_trailing)
Definition base16.h:109
static uint8_t overflow[100]
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:203
#define RCSID(id)
Definition build.h:603
#define DIAG_OFF_OPTIONAL(_x)
Definition build.h:577
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:245
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:422
#define DIAG_ON(_x)
Definition build.h:576
#define SIZEOF_MEMBER(_t, _m)
Definition build.h:436
#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:130
#define unlikely(_x)
Definition build.h:486
#define UNUSED
Definition build.h:415
#define DIAG_ON_OPTIONAL(_x)
Definition build.h:578
#define DIAG_OFF(_x)
Definition build.h:575
#define MEMCMP_FIELDS(_a, _b, _field, _len_field)
Return the comparison of two opaque fields of a structure.
Definition build.h:195
fr_cmp_ret_t
Result of an ordering comparison.
Definition build.h:113
@ CMP_ERR
comparison failed
Definition build.h:114
@ CMP_EQ
a == b
Definition build.h:116
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:819
#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:1911
#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:1056
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
Definition dbuff.h:387
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:950
#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:1951
#define fr_dbuff_buff(_dbuff_or_marker)
Return the underlying buffer in a dbuff or one of marker.
Definition dbuff.h:934
#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen)
Copy exactly _outlen bytes from the dbuff.
Definition dbuff.h:1785
#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:1561
#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:1805
#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:1435
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
Definition dbuff.h:1403
#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:1638
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:230
#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:1871
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:453
#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:1525
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:556
#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:229
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:177
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:248
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition debug.h:254
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:194
#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:222
@ FR_DICT_ATTR_EXT_REF
Attribute references another attribute and/or dictionary.
Definition dict.h:184
#define da_is_length_field16(_da)
Definition dict.h:174
bool const fr_dict_attr_nested_allowed_chars[SBUFF_CHAR_CLASS]
Characters allowed in a nested dictionary attribute name.
Definition dict_util.c:61
static fr_dict_attr_t * fr_dict_attr_unknown_copy(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Definition dict.h:608
#define da_is_length_field8(_da)
Definition dict.h:173
int fr_dict_protocol_reference(fr_dict_attr_t const **da_p, fr_dict_attr_t const *root, fr_sbuff_t *in)
Resolve a reference string to a dictionary attribute.
Definition dict_fixup.c:135
bool const fr_dict_enum_allowed_chars[SBUFF_CHAR_CLASS]
Characters that are allowed in dictionary enumeration value names.
Definition dict_util.c:69
static fr_cmp_ret_t fr_dict_attr_cmp(fr_dict_attr_t const *a, fr_dict_attr_t const *b)
Definition dict.h:676
fr_slen_t fr_dict_attr_by_oid_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *in, fr_sbuff_term_t const *tt))
Resolve an attribute using an OID string.
Definition dict_util.c:2641
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Definition dict.h:635
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2717
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:281
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:3765
fr_slen_t fr_dict_attr_unknown_afrom_oid_substr(TALLOC_CTX *ctx, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *in, fr_type_t type))
Create a fr_dict_attr_t from an ASCII attribute and value.
#define FR_DICT_ATTR_OID_PRINT_RETURN(...)
Definition dict.h:777
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition dict_util.c:3667
fr_dict_enum_value_t const * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition dict_util.c:3778
Value of an enumerated attribute.
Definition dict.h:277
fr_dict_attr_ref_type_t type
The state of the reference.
Definition dict_ext.h:79
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:122
@ FR_DICT_ATTR_REF_ROOT
only for FR_TYPE_ATTR, point to the default root for enums
Definition dict_ext.h:66
Attribute extension - Holds a reference to an attribute in another dictionary.
Definition dict_ext.h:78
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:360
uint32_t fr_hash(void const *data, size_t size)
Definition hash.c:866
free(array)
talloc_free(hp)
int fr_ipaddr_is_prefix(fr_ipaddr_t const *ipaddr)
Determine if an address is a prefix.
Definition inet.c:126
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:1080
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:632
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:783
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:1025
void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
Zeroes out the host portion of an fr_ipaddr_t.
Definition inet.c:218
fr_cmp_ret_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1353
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:1106
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:1120
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.
#define fr_multiply(_out, _a, _b)
Multiplies two integers together.
Definition math.h:179
static const uint8_t * zero
Definition md4.c:359
unsigned short uint16_t
#define SBUFF_CHAR_CLASS
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
fr_sbuff_err_t
@ FR_SBUFF_ERR_NOT_FOUND
@ FR_SBUFF_OK
unsigned char uint8_t
fr_sbuff_err_t fr_sbuff_out_unescape_until(size_t *len, fr_sbuff_t *out, fr_sbuff_t *in, size_t max, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
ssize_t fr_slen_t
unsigned long int size_t
#define UINT8_MAX
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
void * memset_explicit(void *ptr, int ch, size_t len)
Definition missing.c:708
static unsigned int fr_bytes_from_bits(unsigned int bits)
Convert bits (as in prefix length) to bytes, rounding up.
Definition nbo.h:243
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:860
#define fr_assert(_expr)
Definition rad_assert.h:37
static char * secret
static bool done
Definition radclient.c:80
static uint32_t mask
Definition rbmonkey.c:39
static char const * name
size_t fr_sbuff_adv_past_allowed(fr_sbuff_t *sbuff, size_t len, bool const allowed[static SBUFF_CHAR_CLASS], fr_sbuff_term_t const *tt)
Wind position past characters in the allowed set.
Definition sbuff.c:1936
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:444
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:1705
bool const sbuff_char_class_hex[SBUFF_CHAR_CLASS]
Definition sbuff.c:109
bool const sbuff_char_class_uint[SBUFF_CHAR_CLASS]
Definition sbuff.c:75
bool const sbuff_char_class_hostname[SBUFF_CHAR_CLASS]
Definition sbuff.c:97
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
Definition sbuff.c:2311
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:1553
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:2011
fr_sbuff_err_t fr_sbuff_out_bstrncpy(size_t *len, fr_sbuff_t *out, fr_sbuff_t *in, size_t max)
Copy as many bytes as possible from a sbuff to a sbuff.
Definition sbuff.c:755
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:2247
#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:212
#define FR_SBUFF_IN_ESCAPE_BUFFER_RETURN(...)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition sbuff.h:191
char const * name
Name for rule set to aid we debugging.
Definition sbuff.h:210
#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_is_char(_sbuff_or_marker, _c)
#define FR_SBUFF_ERROR_RETURN(_sbuff_or_marker)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define fr_sbuff_is_digit(_sbuff_or_marker)
#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(_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:179
#define FR_SBUFF_IN_STRCPY_RETURN(...)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Talloc sbuff extension structure.
Definition sbuff.h:138
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:37
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
fr_aka_sim_id_type_t type
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
char * talloc_buffer_append_variadic_buffer(TALLOC_CTX *ctx, char *to, int argc,...)
Concatenate to + ...
Definition talloc.c:793
uint8_t * talloc_typed_memdup(TALLOC_CTX *ctx, uint8_t const *in, size_t inlen)
Call talloc_memdup, setting the type on the new chunk correctly.
Definition talloc.c:521
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:693
#define talloc_get_type_abort_const
Definition talloc.h:117
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:289
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
fr_table_num_ordered_t const fr_time_precision_table[]
Definition time.c:46
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:221
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:828
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:717
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:458
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:1163
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:557
static int64_t fr_time_delta_to_integer(fr_time_delta_t delta, fr_time_res_t res)
Definition time.h:636
static fr_unix_time_t fr_unix_time_from_nsec(int64_t nsec)
Definition time.h:423
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
#define fr_time_delta_isneg(_a)
Definition time.h:291
static fr_cmp_ret_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:962
#define fr_time_delta_wrap(_time)
Definition time.h:152
static double fr_unix_time_to_sec_double(fr_unix_time_t when)
Seconds since the epoch as a double, for printing and for arithmetic which need not be exact.
Definition time.h:513
#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_NSEC
Definition time.h:60
@ 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 uint64_t fr_unix_time_unwrap(fr_unix_time_t time)
Definition time.h:161
static fr_cmp_ret_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:948
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:222
@ T_SINGLE_QUOTED_STRING
Definition token.h:120
@ T_BARE_WORD
Definition token.h:118
@ T_BACK_QUOTED_STRING
Definition token.h:121
@ T_OP_NE
Definition token.h:95
@ T_OP_REG_EQ
Definition token.h:100
@ T_DOUBLE_QUOTED_STRING
Definition token.h:119
@ T_OP_CMP_EQ
Definition token.h:104
@ T_OP_LE
Definition token.h:98
@ T_OP_GE
Definition token.h:96
@ T_OP_GT
Definition token.h:97
@ T_SOLIDUS_QUOTED_STRING
Definition token.h:122
@ T_OP_LT
Definition token.h:99
@ T_OP_REG_NE
Definition token.h:101
enum fr_token fr_token_t
#define T_TOKEN_LAST
Definition token.h:127
static fr_slen_t head
Definition xlat.h:410
static fr_slen_t parent
Definition pair.h:864
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:581
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition strerror.h:84
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define FR_TYPE_VARIABLE_SIZE
Definition types.h:311
#define FR_TYPE_QUOTED
Definition types.h:312
#define FR_TYPE_STRUCTURAL_EXCEPT_GROUP
Definition types.h:315
#define fr_type_is_non_leaf(_x)
Definition types.h:394
@ FR_TYPE_VALUE_BOX_CURSOR
cursor over a fr_value_box_t
Definition types.h:88
@ FR_TYPE_UNION
A union of limited children.
Definition types.h:81
@ FR_TYPE_ATTR
A contains an attribute reference.
Definition types.h:83
@ FR_TYPE_PAIR_CURSOR
cursor over a fr_pair_t
Definition types.h:90
#define fr_type_is_group(_x)
Definition types.h:376
#define fr_type_is_variable_size(_x)
Definition types.h:388
#define fr_type_is_structural(_x)
Definition types.h:392
#define FR_TYPE_INTERNAL
Definition types.h:319
#define FR_TYPE_NON_LEAF
Definition types.h:318
#define fr_type_is_fixed_size(_x)
Definition types.h:387
#define FR_TYPE_STRUCTURAL
Definition types.h:316
#define fr_type_is_ip(_x)
Definition types.h:385
#define FR_TYPE_INTEGER_EXCEPT_BOOL
Definition types.h:303
#define FR_TYPE_IP
Definition types.h:308
#define FR_TYPE_INTEGER
Definition types.h:304
#define fr_type_is_leaf(_x)
Definition types.h:393
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:454
#define FR_TYPE_NUMERIC
Definition types.h:306
#define FR_TYPE_FIXED_SIZE
Definition types.h:310
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:5038
void fr_value_box_list_verify(char const *file, int line, fr_value_box_list_t const *list)
Definition value.c:7500
fr_cmp_ret_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:770
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:5357
size_t const fr_value_box_field_sizes[]
How many bytes wide each of the value data fields are.
Definition value.c:162
fr_slen_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:6256
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:1330
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:1431
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:4820
void fr_value_box_set_void_shallow(fr_value_box_t *dst, void const *ptr)
Assign a void pointer to a box.
Definition value.c:5385
static void _fr_value_box_list_debug(FILE *fp, fr_value_box_list_t const *head, int depth)
Definition value.c:7735
#define INFO_INDENT(_fmt,...)
Definition value.c:7732
fr_sbuff_unescape_rules_t const fr_value_unescape_single
Definition value.c:301
void fr_value_box_mark_unsafe(fr_value_box_t *vb)
Mark a value-box as "unsafe".
Definition value.c:7528
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:4789
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
Definition value.c:7320
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:6293
fr_sbuff_escape_rules_t const fr_value_escape_double
Definition value.c:366
fr_sbuff_err_t fr_value_substr_unescape(size_t *len, fr_sbuff_t *out, fr_sbuff_t *in, size_t max, char quote)
Convert a string value with escape sequences into its binary form.
Definition value.c:1300
fr_sbuff_parse_rules_t const value_parse_rules_single_3quoted
Definition value.c:594
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:5485
fr_sbuff_escape_rules_t const fr_value_escape_backtick
Definition value.c:433
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:2667
int fr_value_box_escape_erules(fr_value_box_t *vb, void *uctx)
Escape a value-box in place using the supplied fr_sbuff_escape_rules_t in uctx.
Definition value.c:7148
fr_sbuff_escape_rules_t const fr_value_escape_secret
Escape secret fields by simply mashing all data to '.
Definition value.c:395
fr_sbuff_parse_rules_t const value_parse_rules_double_unquoted
Definition value.c:498
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:7269
#define O(_x, _y)
fr_sbuff_parse_rules_t const value_parse_rules_solidus_quoted
Definition value.c:573
#define VB_NAME
Definition value.c:7398
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:1942
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:5161
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:5317
fr_sbuff_escape_rules_t const fr_value_escape_unprintables
Definition value.c:469
#define network_min_size(_x)
How many bytes on-the-wire would a fr_value_box_t value consume.
Definition value.c:116
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:5077
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:4071
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:4851
ssize_t fr_value_box_list_concat_as_octets(fr_value_box_safety_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:6693
fr_sbuff_parse_rules_t const * value_parse_rules_quoted[T_TOKEN_LAST]
Parse rules for quoted strings.
Definition value.c:620
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:7219
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:5194
static size_t const fr_value_box_network_sizes[FR_TYPE_MAX+1][2]
Definition value.c:118
fr_sbuff_escape_rules_t const fr_value_escape_solidus
Definition value.c:412
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:3947
fr_sbuff_unescape_rules_t const * fr_value_unescape_by_quote[T_TOKEN_LAST]
Definition value.c:352
#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:204
#define VERIFY_CLEAR(_vb)
Definition value.c:99
static void _fr_value_box_debug(FILE *fp, fr_value_box_t const *vb, int depth, int idx)
Definition value.c:7753
#define CAST_IP_FIX_COMBO
Definition value.c:2849
fr_sbuff_parse_rules_t const value_parse_rules_bareword_unquoted
Default formatting rules.
Definition value.c:494
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:2890
static const fr_value_box_ipaddr_sizes_t ipaddr_sizes[FR_TYPE_MAX]
Definition value.c:2311
int fr_value_box_escape_in_place_func(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_sbuff_escape_func_t escape)
Escape a value box in place using an sbuff escape function.
Definition value.c:7168
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:4526
fr_sbuff_parse_rules_t const value_parse_rules_single_unquoted
Definition value.c:502
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:1017
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:7028
int fr_value_box_bstrndup_replace(TALLOC_CTX *ctx, 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 copy of a ...
Definition value.c:4909
fr_sbuff_parse_rules_t const * value_parse_rules_unquoted_char[SBUFF_CHAR_CLASS]
Definition value.c:530
uint64_t fr_value_box_as_uint64(fr_value_box_t const *vb)
Return a uint64_t from a fr_value_box_t.
Definition value.c:4376
bool fr_value_box_is_truthy(fr_value_box_t const *in)
Check truthiness of values.
Definition value.c:7688
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:4326
void fr_value_box_set_cursor_shallow(fr_value_box_t *dst, fr_type_t type, void *cursor, char const *name)
Definition value.c:5370
fr_sbuff_parse_rules_t const value_parse_rules_single_quoted
Definition value.c:567
static uint8_t const v4_v6_map[]
v4 to v6 mapping prefix
Definition value.c:2653
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:5339
static void _value_box_safety_merge(fr_value_box_safety_t *out, fr_value_box_safety_t const *in)
Merge one safety into another.
Definition value.c:7583
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:4652
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:2727
void fr_value_box_increment(fr_value_box_t *vb)
Increment a boxed value.
Definition value.c:5431
fr_slen_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:5584
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:7509
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:4461
void fr_value_box_set_attr(fr_value_box_t *dst, fr_dict_attr_t const *da)
Definition value.c:5417
fr_sbuff_unescape_rules_t const fr_value_unescape_backtick
Definition value.c:333
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:7404
void fr_value_box_set_secret(fr_value_box_t *box, bool secret)
Mark a box as holding a secret, or not.
Definition value.c:7638
fr_sbuff_parse_rules_t const * value_parse_rules_3quoted[T_TOKEN_LAST]
Definition value.c:636
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:4763
#define network_max_size(_x)
Definition value.c:117
#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:4889
void fr_value_box_safety_set(fr_value_box_t *box, fr_value_box_safety_t const *safety)
Replace the safety of a box.
Definition value.c:7627
fr_sbuff_unescape_rules_t const fr_value_unescape_double
Definition value.c:282
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:6533
fr_sbuff_parse_rules_t const value_parse_rules_double_3quoted
Definition value.c:588
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:3673
static int value_box_ipv6_scope_id_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
Encode the scope_id of an IPv6 address or prefix as one byte.
Definition value.c:1483
ssize_t fr_value_box_list_concat_as_string(fr_value_box_safety_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:6576
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:3242
ssize_t fr_value_box_from_memory(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, void const *src, size_t len)
Decode a fr_value_box_t from a C type in memory.
Definition value.c:2467
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:7571
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:4410
static void _value_box_list_safety_merge(fr_value_box_t *out, fr_value_box_list_t const *list)
Merge the safety of every leaf box in a list into out.
Definition value.c:7649
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:894
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:652
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:7540
#define VERIFY_SET(_vb)
Definition value.c:98
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:2597
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:3404
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:4442
int fr_value_box_escape_in_place_erules(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_sbuff_escape_rules_t const *erules)
Escape a value-box in place using sbuff escaping rules, and mark it safe-for.
Definition value.c:7082
fr_sbuff_parse_rules_t const value_parse_rules_bareword_quoted
Definition value.c:538
void fr_value_box_safety_merge(fr_value_box_t *out, fr_value_box_t const *in)
Merge safety results.
Definition value.c:7616
fr_sbuff_parse_rules_t const value_parse_rules_backtick_3quoted
Definition value.c:606
fr_sbuff_escape_rules_t const fr_value_escape_single
Definition value.c:402
static uint64_t const fr_value_box_integer_max[]
Definition value.c:242
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:4873
void fr_value_box_list_debug(FILE *fp, fr_value_box_list_t const *head)
Print a list of value boxes as info messages.
Definition value.c:7748
fr_sbuff_parse_rules_t const * value_parse_rules_quoted_char[SBUFF_CHAR_CLASS]
Definition value.c:628
fr_sbuff_parse_rules_t const value_parse_rules_solidus_unquoted
Definition value.c:506
#define RETURN(_type)
fr_sbuff_parse_rules_t const value_parse_rules_backtick_quoted
Definition value.c:579
fr_sbuff_parse_rules_t const * value_parse_rules_unquoted[T_TOKEN_LAST]
Parse rules for non-quoted strings.
Definition value.c:522
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:3007
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:3343
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:7558
fr_sbuff_parse_rules_t const value_parse_rules_backtick_unquoted
Definition value.c:510
ssize_t fr_value_box_ipaddr_from_network(fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, int prefix_len, uint8_t const *data, size_t data_len, bool fixed, bool tainted)
Decode a fr_value_box_t of type IP address / prefix.
Definition value.c:2346
fr_sbuff_parse_rules_t const value_parse_rules_double_quoted
Definition value.c:561
fr_sbuff_escape_rules_t const * erules
Definition value.c:7042
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:4940
#define SIGN_PROMOTE(_int, _len)
fr_sbuff_parse_rules_t const value_parse_rules_solidus_3quoted
Definition value.c:600
static int _value_box_escape_rules(fr_value_box_t *vb, void *uctx)
Definition value.c:7045
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:4688
static int fr_value_box_cast_unsupported(fr_type_t dst, fr_type_t src)
Definition value.c:2866
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:2534
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:7194
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:7357
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:4509
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:7385
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:1534
#define VERIFY_IS_SET(_vb)
Sanity checks.
Definition value.c:97
static bool value_box_float_overflows(double f, fr_type_t dst_type)
Check whether a floating point value is above the range of an integer type.
Definition value.c:3658
void fr_value_box_list_safety_merge(fr_value_box_t *out, fr_value_box_list_t const *list)
Set the safety of out to the most restrictive safety of any leaf box in a list.
Definition value.c:7671
static fr_cmp_ret_t float_cmp(double a, double b)
Compare two floating point numbers for equality.
Definition value.c:716
static int64_t const fr_value_box_integer_min[]
Definition value.c:262
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:4973
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:5014
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:5280
fr_sbuff_unescape_rules_t const * fr_value_unescape_by_char[SBUFF_CHAR_CLASS]
Definition value.c:359
void fr_value_box_debug(FILE *fp, fr_value_box_t const *vb)
Print the value of a box as info messages.
Definition value.c:7795
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:1065
fr_sbuff_unescape_rules_t const fr_value_unescape_solidus
Definition value.c:312
fr_sbuff_escape_rules_t const * fr_value_escape_by_quote[T_TOKEN_LAST]
Definition value.c:455
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:5122
static fr_dict_attr_t const * fr_value_box_attr_enumv(fr_dict_attr_t const *da)
Definition value.c:5391
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:6972
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:5101
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:3125
fr_sbuff_escape_rules_t const * fr_value_escape_by_char[SBUFF_CHAR_CLASS]
Definition value.c:462
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:5255
#define VB_NAME_LOCATION(_x)
Definition value.c:7399
fr_sbuff_err_t fr_value_str_unescape(size_t *len, fr_sbuff_t *out, fr_sbuff_t *in, size_t max, char quote)
Convert a string value with escape sequences into its binary form.
Definition value.c:1232
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:3494
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:6793
fr_value_box_list_action_t
Actions to perform when we process a box in a list.
Definition value.h:261
@ FR_VALUE_BOX_LIST_NONE
Do nothing to processed boxes.
Definition value.h:262
@ FR_VALUE_BOX_LIST_REMOVE
Remove the box from the input list.
Definition value.h:263
@ FR_VALUE_BOX_LIST_FREE
Definition value.h:267
#define vb_should_free(_action)
Definition value.h:270
#define vb_ipv6addr
Definition value.h:295
#define vb_ether
Definition value.h:298
#define vb_date
Definition value.h:315
#define vb_int64
Definition value.h:310
#define vb_octets
Definition value.h:288
#define vb_should_free_value(_action)
Definition value.h:271
#define vb_should_remove(_action)
Definition value.h:272
static fr_sbuff_err_t char size_t fr_sbuff_t * in
Definition value.h:1061
#define vb_int32
Definition value.h:309
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:828
fr_value_box_safe_for_t safe_for
A unique value to indicate if that value box is safe for consumption by a particular module for a par...
Definition value.h:187
#define vb_int16
Definition value.h:308
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition value.h:1124
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:301
static fr_sbuff_err_t char size_t fr_sbuff_t size_t max
Definition value.h:1061
#define vb_length
Definition value.h:321
#define vb_int8
Definition value.h:307
static fr_slen_t data
Definition value.h:1366
static bool fr_value_box_contains_secret(fr_value_box_t const *box)
Definition value.h:1149
#define vb_float64
Definition value.h:313
unsigned int secret
Same as fr_dict_attr_flags_t secret.
Definition value.h:193
#define FR_VALUE_BOX_NET_ERROR
Special value to indicate fr_value_box_from_network experienced a general error.
Definition value.h:1078
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:804
#define fr_box_strvalue_len(_val, _len)
Definition value.h:340
#define FR_VALUE_BOX_MAGIC
Definition value.h:96
#define fr_value_box_init_null(_vb)
Initialise an empty/null box that will be filled later.
Definition value.h:640
#define fr_value_box_is_safe_for(_box, _safe_for)
Definition value.h:1131
static fr_sbuff_err_t char ** out
Definition value.h:1061
static fr_sbuff_err_t char size_t * len
Definition value.h:1061
#define vb_ip
Definition value.h:293
fr_value_box_safe_for_t safe_for
Definition value.h:706
#define vb_uint16
Definition value.h:302
#define vb_bool
Definition value.h:300
#define vb_size
Definition value.h:317
#define FR_VALUE_BOX_SAFE_FOR_NONE
Definition value.h:177
uintptr_t fr_value_box_safe_for_t
Escaping that's been applied to a value box.
Definition value.h:167
#define vb_strvalue
Definition value.h:287
#define VALUE_BOX_VERIFY(_x)
Definition value.h:1388
#define vb_uint32
Definition value.h:303
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:679
#define vb_ifid
Definition value.h:297
#define vb_attr
Definition value.h:291
#define vb_time_delta
Definition value.h:319
fr_value_box_escape_func_t func
Definition value.h:705
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:887
#define vb_ipv4addr
Definition value.h:294
#define vb_float32
Definition value.h:312
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:634
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:253
#define FR_VALUE_BOX_NET_OOM
Special value to indicate fr_value_box_from_network hit an out of memory error.
Definition value.h:1082
#define vb_uint64
Definition value.h:304
#define FR_VALUE_BOX_SAFE_FOR_ANY
Definition value.h:178
The safety of a value.
Definition value.h:186