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: 59aaf0595cae0a1d224215f43dfaf9dc49b20c32 $")
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 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2902 src->vb_strvalue, src->vb_length,
2903 NULL);
2904
2906
2907 default:
2908 break;
2909 }
2910
2911 /*
2912 * Pre-initialise box for non-variable types
2913 */
2914 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2915 dst->vb_ip.af = AF_INET;
2916 dst->vb_ip.prefix = 32;
2917 dst->vb_ip.scope_id = 0;
2918
2919 switch (src_type) {
2920 case FR_TYPE_IPV6_ADDR:
2921 if (memcmp(src->vb_ipv6addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
2922 bad_v6_prefix_map:
2923 fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
2924 fr_type_to_str(src->type),
2925 fr_type_to_str(dst_type));
2926 return -1;
2927 }
2928
2929 memcpy(&dst->vb_ip.addr.v4, &src->vb_ipv6addr[sizeof(v4_v6_map)],
2930 sizeof(dst->vb_ip.addr.v4));
2931
2932 break;
2933
2935 if (src->vb_ip.prefix != 32) {
2936 fr_strerror_printf("Invalid cast from %s to %s. Only /32 (not %i/) prefixes may be "
2937 "cast to IP address types",
2938 fr_type_to_str(src->type),
2939 fr_type_to_str(dst_type),
2940 src->vb_ip.prefix);
2941 return -1;
2942 }
2944
2945 case FR_TYPE_IPV4_ADDR: /* Needed for handling combo addresses */
2946 memcpy(&dst->vb_ip.addr.v4, &src->vb_ip.addr.v4, sizeof(dst->vb_ip.addr.v4));
2947 break;
2948
2950 if (src->vb_ip.prefix != 128) {
2951 fr_strerror_printf("Invalid cast from %s to %s. Only /128 (not /%i) prefixes may be "
2952 "cast to IP address types",
2953 fr_type_to_str(src->type),
2954 fr_type_to_str(dst_type),
2955 src->vb_ip.prefix);
2956 return -1;
2957 }
2958 if (memcmp(&src->vb_ipv6addr, v4_v6_map, sizeof(v4_v6_map)) != 0) goto bad_v6_prefix_map;
2959 memcpy(&dst->vb_ip.addr.v4, &src->vb_ipv6addr[sizeof(v4_v6_map)],
2960 sizeof(dst->vb_ip.addr.v4));
2961 break;
2962
2963 case FR_TYPE_OCTETS:
2964 if (src->vb_length != sizeof(dst->vb_ipv4addr)) {
2965 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2966 fr_type_to_str(src->type),
2967 fr_type_to_str(dst_type),
2968 sizeof(dst->vb_ipv4addr), src->vb_length);
2969 return -1;
2970 }
2971 memcpy(&dst->vb_ip.addr.v4, src->vb_octets, sizeof(dst->vb_ipv4addr));
2972 break;
2973
2974 case FR_TYPE_UINT32:
2975 {
2976 uint32_t net;
2977
2978 net = ntohl(src->vb_uint32);
2979 memcpy(&dst->vb_ip.addr.v4, (uint8_t *)&net, sizeof(dst->vb_ipv4addr));
2980 }
2981 break;
2982
2983 default:
2984 return fr_value_box_cast_unsupported(dst_type, src->type);
2985 }
2986
2987 return 0;
2988}
2989
2990/** Convert any supported type to an IPv6 address
2991 *
2992 * Allowed input types are:
2993 * - FR_TYPE_IPV4_ADDR
2994 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2995 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
2996 * - FR_TYPE_OCTETS (of length 16).
2997 *
2998 * @param ctx unused.
2999 * @param dst Where to write result of casting.
3000 * @param dst_type to cast to.
3001 * @param dst_enumv enumeration values.
3002 * @param src Input data.
3003 */
3004static inline int fr_value_box_cast_to_ipv4prefix(TALLOC_CTX *ctx, fr_value_box_t *dst,
3005 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3006 fr_value_box_t const *src)
3007{
3008 fr_type_t src_type = src->type;
3009
3010 fr_assert(dst_type == FR_TYPE_IPV4_PREFIX);
3012
3013 switch (src_type) {
3014 case FR_TYPE_STRING:
3015 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3016 src->vb_strvalue, src->vb_length,
3017 NULL);
3018
3020
3021 default:
3022 break;
3023 }
3024
3025 /*
3026 * Pre-initialise box for non-variable types
3027 */
3028 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3029 dst->vb_ip.af = AF_INET;
3030 dst->vb_ip.scope_id = 0;
3031
3032 switch (src_type) {
3033 case FR_TYPE_IPV4_PREFIX: /* Needed for handling combo prefixes */
3034 dst->vb_ip.prefix = src->vb_ip.prefix;
3036
3037 case FR_TYPE_IPV4_ADDR:
3038 memcpy(&dst->vb_ip, &src->vb_ip, sizeof(dst->vb_ip));
3039 break;
3040
3041 /*
3042 * Copy the last four bytes, to make an IPv4prefix
3043 */
3044 case FR_TYPE_IPV6_ADDR:
3045 if (memcmp(src->vb_ipv6addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
3046 bad_v6_prefix_map:
3047 fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
3048 fr_type_to_str(src->type),
3049 fr_type_to_str(dst_type));
3050 return -1;
3051 }
3052 memcpy(&dst->vb_ipv4addr, &src->vb_ipv6addr[sizeof(v4_v6_map)],
3053 sizeof(dst->vb_ipv4addr));
3054 dst->vb_ip.prefix = 32;
3055 break;
3056
3058 if (memcmp(src->vb_ipv6addr, v4_v6_map, sizeof(v4_v6_map)) != 0) goto bad_v6_prefix_map;
3059
3060 if (src->vb_ip.prefix < (sizeof(v4_v6_map) << 3)) {
3061 fr_strerror_printf("Invalid cast from %s to %s. Expected prefix >= %u bits got %u bits",
3062 fr_type_to_str(src->type),
3063 fr_type_to_str(dst_type),
3064 (unsigned int)(sizeof(v4_v6_map) << 3), src->vb_ip.prefix);
3065 return -1;
3066 }
3067 memcpy(&dst->vb_ipv4addr, &src->vb_ipv6addr[sizeof(v4_v6_map)],
3068 sizeof(dst->vb_ipv4addr));
3069
3070 /*
3071 * Subtract the bits used by the v4_v6_map to get the v4 prefix bits
3072 */
3073 dst->vb_ip.prefix = src->vb_ip.prefix - (sizeof(v4_v6_map) << 3);
3074 break;
3075
3076 case FR_TYPE_OCTETS:
3077 if (src->vb_length != sizeof(dst->vb_ipv4addr) + 1) {
3078 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
3079 fr_type_to_str(src->type),
3080 fr_type_to_str(dst_type),
3081 sizeof(dst->vb_ipv4addr) + 1, src->vb_length);
3082 return -1;
3083 }
3084 dst->vb_ip.prefix = src->vb_octets[0];
3085 memcpy(&dst->vb_ip.addr.v4, &src->vb_octets[1], sizeof(dst->vb_ipv4addr));
3086 break;
3087
3088 case FR_TYPE_UINT32:
3089 {
3090 uint32_t net;
3091
3092 net = ntohl(src->vb_uint32);
3093 memcpy(&dst->vb_ip.addr.v4, (uint8_t *)&net, sizeof(dst->vb_ipv4addr));
3094 dst->vb_ip.prefix = 32;
3095 break;
3096 }
3097
3098 default:
3099 return fr_value_box_cast_unsupported(dst_type, src->type);
3100 }
3101
3102 return 0;
3103}
3104
3105/** Convert any supported type to an IPv6 address
3106 *
3107 * Allowed input types are:
3108 * - FR_TYPE_IPV4_ADDR
3109 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
3110 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
3111 * - FR_TYPE_OCTETS (of length 16).
3112 *
3113 * @param ctx unused.
3114 * @param dst Where to write result of casting.
3115 * @param dst_type to cast to.
3116 * @param dst_enumv enumeration values.
3117 * @param src Input data.
3118 */
3119static inline int fr_value_box_cast_to_ipv6addr(TALLOC_CTX *ctx, fr_value_box_t *dst,
3120 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3121 fr_value_box_t const *src)
3122{
3123 fr_type_t src_type = src->type;
3124
3125 static_assert((sizeof(v4_v6_map) + sizeof(src->vb_ip.addr.v4)) <=
3126 sizeof(src->vb_ip.addr.v6), "IPv6 storage too small");
3127
3128 fr_assert(dst_type == FR_TYPE_IPV6_ADDR);
3130
3131 switch (src_type) {
3132 case FR_TYPE_STRING:
3133 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3134 src->vb_strvalue, src->vb_length,
3135 NULL);
3136
3138
3139 default:
3140 break;
3141 }
3142
3143 /*
3144 * Pre-initialise box for non-variable types
3145 */
3146 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3147 dst->vb_ip.af = AF_INET6;
3148 dst->vb_ip.prefix = 128;
3149
3150 switch (src_type) {
3151 case FR_TYPE_IPV4_ADDR:
3152 {
3153 uint8_t *p = dst->vb_ipv6addr;
3154
3155 /* Add the v4/v6 mapping prefix */
3156 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
3157 p += sizeof(v4_v6_map);
3158 memcpy(p, (uint8_t const *)&src->vb_ipv4addr, sizeof(src->vb_ipv4addr));
3159 dst->vb_ip.scope_id = 0;
3160 }
3161 break;
3162
3164 {
3165 uint8_t *p = dst->vb_ipv6addr;
3166
3167 if (src->vb_ip.prefix != 32) {
3168 fr_strerror_printf("Invalid cast from %s to %s. Only /32 (not /%i) prefixes may be "
3169 "cast to IP address types",
3170 fr_type_to_str(src->type),
3171 fr_type_to_str(dst_type),
3172 src->vb_ip.prefix);
3173 return -1;
3174 }
3175
3176 /* Add the v4/v6 mapping prefix */
3177 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
3178 p += sizeof(v4_v6_map);
3179 memcpy(p, (uint8_t const *)&src->vb_ipv4addr, sizeof(src->vb_ipv4addr));
3180 dst->vb_ip.scope_id = 0;
3181 }
3182 break;
3183
3185 if (src->vb_ip.prefix != 128) {
3186 fr_strerror_printf("Invalid cast from %s to %s. Only /128 (not /%i) prefixes may be "
3187 "cast to IP address types",
3188 fr_type_to_str(src->type),
3189 fr_type_to_str(dst_type),
3190 src->vb_ip.prefix);
3191 return -1;
3192 }
3194
3195 case FR_TYPE_IPV6_ADDR: /* Needed for handling combo addresses */
3196 memcpy(dst->vb_ipv6addr, src->vb_ipv6addr,
3197 sizeof(dst->vb_ipv6addr));
3198 dst->vb_ip.scope_id = src->vb_ip.scope_id;
3199 break;
3200
3201 case FR_TYPE_OCTETS:
3202 if (src->vb_length != sizeof(dst->vb_ipv6addr)) {
3203 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
3204 fr_type_to_str(src->type),
3205 fr_type_to_str(dst_type),
3206 sizeof(dst->vb_ipv6addr), src->vb_length);
3207 return -1;
3208 }
3209 memcpy(&dst->vb_ipv6addr, src->vb_octets, sizeof(dst->vb_ipv6addr));
3210 break;
3211
3212 default:
3213 return fr_value_box_cast_unsupported(dst_type, src->type);
3214 }
3215
3216 return 0;
3217}
3218
3219/** Convert any supported type to an IPv6 address
3220 *
3221 * Allowed input types are:
3222 * - FR_TYPE_IPV4_ADDR
3223 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
3224 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
3225 * - FR_TYPE_OCTETS (of length 16).
3226 *
3227 * @param ctx unused.
3228 * @param dst Where to write result of casting.
3229 * @param dst_type to cast to.
3230 * @param dst_enumv enumeration values.
3231 * @param src Input data.
3232 */
3233static inline int fr_value_box_cast_to_ipv6prefix(TALLOC_CTX *ctx, fr_value_box_t *dst,
3234 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3235 fr_value_box_t const *src)
3236{
3237 fr_type_t src_type = src->type;
3238
3239 fr_assert(dst_type == FR_TYPE_IPV6_PREFIX);
3241
3242 switch (src_type) {
3243 case FR_TYPE_STRING:
3244 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3245 src->vb_strvalue, src->vb_length,
3246 NULL);
3247
3249
3250 default:
3251 break;
3252 }
3253
3254 /*
3255 * Pre-initialise box for non-variable types
3256 */
3257 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3258 dst->vb_ip.af = AF_INET6;
3259
3260 switch (src_type) {
3261 case FR_TYPE_IPV4_ADDR:
3262 {
3263 uint8_t *p = dst->vb_ipv6addr;
3264
3265 /* Add the v4/v6 mapping prefix */
3266 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
3267 p += sizeof(v4_v6_map);
3268 memcpy(p, (uint8_t const *)&src->vb_ipv4addr, sizeof(src->vb_ipv4addr));
3269 dst->vb_ip.prefix = 128;
3270 dst->vb_ip.scope_id = 0;
3271 }
3272 break;
3273
3275 {
3276 uint8_t *p = dst->vb_ipv6addr;
3277
3278 /* Add the v4/v6 mapping prefix */
3279 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
3280 p += sizeof(v4_v6_map);
3281 memcpy(p, (uint8_t const *)&src->vb_ipv4addr, sizeof(src->vb_ipv4addr));
3282 dst->vb_ip.prefix = (sizeof(v4_v6_map) << 3) + src->vb_ip.prefix;
3283 dst->vb_ip.scope_id = 0;
3284 }
3285 break;
3286
3287 case FR_TYPE_IPV6_PREFIX: /* Needed for handling combo prefixes */
3288 dst->vb_ip.prefix = src->vb_ip.prefix;
3289 goto v6_common;
3290
3291 case FR_TYPE_IPV6_ADDR:
3292 dst->vb_ip.prefix = 128;
3293 v6_common:
3294 memcpy(dst->vb_ipv6addr, src->vb_ipv6addr,
3295 sizeof(dst->vb_ipv6addr));
3296 dst->vb_ip.scope_id = src->vb_ip.scope_id;
3297 break;
3298
3299 case FR_TYPE_OCTETS:
3300 if (src->vb_length != (sizeof(dst->vb_ipv6addr) + 2)) {
3301 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
3302 fr_type_to_str(src->type),
3303 fr_type_to_str(dst_type),
3304 sizeof(dst->vb_ipv6addr) + 2, src->vb_length);
3305 return -1;
3306 }
3307 dst->vb_ip.scope_id = src->vb_octets[0];
3308 dst->vb_ip.prefix = src->vb_octets[1];
3309 memcpy(&dst->vb_ipv6addr, src->vb_octets + 2, sizeof(dst->vb_ipv6addr));
3310 break;
3311
3312 default:
3313 return fr_value_box_cast_unsupported(dst_type, src->type);
3314 }
3315 return 0;
3316}
3317
3318/** Convert any supported type to an ethernet address
3319 *
3320 * Allowed input types are:
3321 * - FR_TYPE_STRING ("00:11:22:33:44:55")
3322 * - FR_TYPE_OCTETS (0x001122334455)
3323 *
3324 *
3325 * @param ctx unused.
3326 * @param dst Where to write result of casting.
3327 * @param dst_type to cast to.
3328 * @param dst_enumv enumeration values.
3329 * @param src Input data.
3330 */
3331static inline int fr_value_box_cast_to_ethernet(TALLOC_CTX *ctx, fr_value_box_t *dst,
3332 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3333 fr_value_box_t const *src)
3334{
3335 fr_assert(dst_type == FR_TYPE_ETHERNET);
3337
3338 switch (src->type) {
3339 case FR_TYPE_STRING:
3340 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3341 src->vb_strvalue, src->vb_length,
3342 NULL);
3343
3344 case FR_TYPE_OCTETS:
3345 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
3346
3347 default:
3348 break;
3349 }
3350
3351 /*
3352 * Pre-initialise box for non-variable types
3353 */
3354 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3355
3356 switch (src->type) {
3357 case FR_TYPE_UINT64: {
3358 uint8_t array[8];
3359
3360 fr_nbo_from_uint64(array, src->vb_uint64);
3361
3362 /*
3363 * For OUIs in the DB.
3364 */
3365 if ((array[0] != 0) || (array[1] != 0)) return -1;
3366
3367 memcpy(dst->vb_ether, &array[2], 6);
3368 break;
3369 }
3370
3371 default:
3372 return fr_value_box_cast_unsupported(dst_type, src->type);
3373 }
3374
3375 return 0;
3376}
3377
3378/** Convert any supported type to a bool
3379 *
3380 * Allowed input types are:
3381 * - FR_TYPE_STRING ("yes", "true", "no", "false")
3382 *
3383 * @param ctx unused.
3384 * @param dst Where to write result of casting.
3385 * @param dst_type to cast to.
3386 * @param dst_enumv enumeration values.
3387 * @param src Input data.
3388 */
3389static inline int fr_value_box_cast_to_bool(TALLOC_CTX *ctx, fr_value_box_t *dst,
3390 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3391 fr_value_box_t const *src)
3392{
3393 fr_assert(dst_type == FR_TYPE_BOOL);
3395
3396 switch (src->type) {
3397 case FR_TYPE_STRING:
3398 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3399 src->vb_strvalue, src->vb_length,
3400 NULL);
3401
3402 case FR_TYPE_OCTETS:
3403 /*
3404 * This is really "bool from network"
3405 */
3406 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
3407
3408 default:
3409 break;
3410 }
3411
3412 /*
3413 * Pre-initialise box for non-variable types
3414 */
3415 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3416
3417 switch (src->type) {
3418 case FR_TYPE_INT8:
3419 dst->vb_bool = (src->vb_int8 != 0);
3420 break;
3421
3422 case FR_TYPE_UINT8:
3423 dst->vb_bool = (src->vb_uint8 != 0);
3424 break;
3425
3426 case FR_TYPE_INT16:
3427 dst->vb_bool = (src->vb_int16 != 0);
3428 break;
3429
3430 case FR_TYPE_UINT16:
3431 dst->vb_bool = (src->vb_uint16 != 0);
3432 break;
3433
3434 case FR_TYPE_INT32:
3435 dst->vb_bool = (src->vb_int32 != 0);
3436 break;
3437
3438 case FR_TYPE_UINT32:
3439 dst->vb_bool = (src->vb_uint32 != 0);
3440 break;
3441
3442 case FR_TYPE_INT64:
3443 dst->vb_bool = (src->vb_int64 != 0);
3444 break;
3445
3446 case FR_TYPE_UINT64:
3447 dst->vb_bool = (src->vb_uint64 != 0);
3448 break;
3449
3450 case FR_TYPE_SIZE:
3451 dst->vb_bool = (src->vb_size != 0);
3452 break;
3453
3454 case FR_TYPE_TIME_DELTA:
3455 dst->vb_bool = (fr_time_delta_unwrap(src->vb_time_delta) != 0);
3456 break;
3457
3458 case FR_TYPE_FLOAT32:
3459 dst->vb_bool = (fpclassify(src->vb_float32) != FP_ZERO);
3460 break;
3461
3462 case FR_TYPE_FLOAT64:
3463 dst->vb_bool = (fpclassify(src->vb_float64) != FP_ZERO);
3464 break;
3465
3466 default:
3467 return fr_value_box_cast_unsupported(dst_type, src->type);
3468 }
3469
3470 return 0;
3471}
3472
3473/** Convert any signed or unsigned integer type to any other signed or unsigned integer type
3474 *
3475 */
3476static inline int fr_value_box_cast_integer_to_integer(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst,
3477 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3478 fr_value_box_t const *src)
3479{
3480 uint64_t tmp = 0;
3481 size_t len = fr_value_box_field_sizes[src->type];
3482 int64_t min;
3483
3485
3486#define SIGN_BIT_HIGH(_int, _len) ((((uint64_t)1) << (((_len) << 3) - 1)) & (_int))
3487#define SIGN_PROMOTE(_int, _len) ((_len) < sizeof(_int) ? \
3488 (_int) | (~((__typeof__(_int))0)) << ((_len) << 3) : (_int))
3489
3490#if !defined(NDEBUG) || defined(STATIC_ANALYZER)
3491 /*
3492 * Helps catch invalid fr_value_box_field_sizes
3493 * entries, and shuts up clang analyzer.
3494 */
3495 if (!fr_cond_assert_msg(len > 0, "Invalid cast from %s to %s. "
3496 "invalid source type len, expected > 0, got %zu",
3497 fr_type_to_str(src->type),
3498 fr_type_to_str(dst_type),
3499 len)) return -1;
3500
3501 if (!fr_cond_assert_msg(len <= sizeof(uint64_t),
3502 "Invalid cast from %s to %s. "
3503 "invalid source type len, expected <= %zu, got %zu",
3504 fr_type_to_str(src->type),
3505 fr_type_to_str(dst_type),
3506 sizeof(uint64_t), len)) return -1;
3507#endif
3508
3509 switch (src->type) {
3510 /*
3511 * Dates are always represented in nanoseconds
3512 * internally, but when we convert to another
3513 * integer type, we scale appropriately.
3514 *
3515 * i.e. if the attribute value resolution is
3516 * seconds, then the integer value is
3517 * nanoseconds -> seconds.
3518 */
3519 case FR_TYPE_DATE:
3520 {
3522 if (src->enumv) res = (fr_time_res_t)src->enumv->flags.flag_time_res;
3523
3524 tmp = fr_unix_time_to_integer(src->vb_date, res);
3525 }
3526 break;
3527
3528 /*
3529 * Same deal with time deltas. Note that
3530 * even though we store the value as an
3531 * unsigned integer, it'll be cast to a
3532 * signed integer for comparisons.
3533 */
3534 case FR_TYPE_TIME_DELTA:
3535 {
3537
3538 if (src->enumv) res = (fr_time_res_t)src->enumv->flags.flag_time_res;
3539
3540 tmp = (uint64_t)fr_time_delta_to_integer(src->vb_time_delta, res);
3541 }
3542 break;
3543
3544 default:
3545#ifdef WORDS_BIGENDIAN
3546 memcpy(((uint8_t *)&tmp) + (sizeof(tmp) - len),
3547 fr_value_box_raw(src, src->type), len);
3548#else
3549 memcpy(&tmp, fr_value_box_raw(src, src->type), len);
3550#endif
3551 break;
3552 }
3553
3554 min = fr_value_box_integer_min[dst_type];
3555
3556 /*
3557 * Sign promote the input if the source type is
3558 * signed, and the high bit is set.
3559 */
3560 if (fr_value_box_integer_min[src->type] < 0) {
3561 if (SIGN_BIT_HIGH(tmp, len)) tmp = SIGN_PROMOTE(tmp, len);
3562
3563 if ((int64_t)tmp < min) {
3564 fr_strerror_printf("Invalid cast from %s to %s. %"PRId64" "
3565 "outside value range %"PRId64"-%"PRIu64,
3566 fr_type_to_str(src->type),
3567 fr_type_to_str(dst_type),
3568 (int64_t)tmp,
3569 min, fr_value_box_integer_max[dst_type]);
3570 return -1;
3571 }
3572 } else if (tmp > fr_value_box_integer_max[dst_type]) {
3573 fr_strerror_printf("Invalid cast from %s to %s. %"PRIu64" "
3574 "outside value range 0-%"PRIu64,
3575 fr_type_to_str(src->type),
3576 fr_type_to_str(dst_type),
3577 tmp, fr_value_box_integer_max[dst_type]);
3578 return -1;
3579 }
3580
3581 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3582 switch (dst_type) {
3583 case FR_TYPE_DATE:
3584 {
3585 bool overflow;
3587 if (dst->enumv) res = (fr_time_res_t)dst->enumv->flags.flag_time_res;
3588
3589 dst->vb_date = fr_unix_time_from_integer(&overflow, tmp, res);
3590 if (overflow) {
3591 fr_strerror_const("Input to date type would overflow");
3592 return -1;
3593 }
3594 }
3595 break;
3596
3597 case FR_TYPE_TIME_DELTA:
3598 {
3599 bool overflow;
3601 if (dst->enumv) res = (fr_time_res_t)dst->enumv->flags.flag_time_res;
3602
3603 dst->vb_time_delta = fr_time_delta_from_integer(&overflow, tmp, res);
3604 if (overflow) {
3605 fr_strerror_const("Input to time_delta type would overflow");
3606 return -1;
3607 }
3608 }
3609 break;
3610
3611 default:
3612#ifdef WORDS_BIGENDIAN
3613 memcpy(fr_value_box_raw(dst, dst->type),
3614 ((uint8_t *)&tmp) + (sizeof(tmp) - len), fr_value_box_field_sizes[dst_type]);
3615#else
3616 memcpy(fr_value_box_raw(dst, dst->type),
3617 &tmp, fr_value_box_field_sizes[dst_type]);
3618#endif
3619 break;
3620 }
3621
3622 return 0;
3623}
3624
3625/** Convert any value to a signed or unsigned integer
3626 *
3627 * @param ctx unused.
3628 * @param dst Where to write result of casting.
3629 * @param dst_type to cast to.
3630 * @param dst_enumv enumeration values.
3631 * @param src Input data.
3632 */
3633static inline int fr_value_box_cast_to_integer(TALLOC_CTX *ctx, fr_value_box_t *dst,
3634 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3635 fr_value_box_t const *src)
3636{
3637 switch (src->type) {
3638 case FR_TYPE_STRING:
3639 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3640 src->vb_strvalue, src->vb_length,
3641 NULL);
3642
3643 case FR_TYPE_OCTETS:
3644 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
3645
3646 case FR_TYPE_INTEGER:
3647 fr_value_box_init(dst, dst_type, dst_enumv, false);
3648 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, src);
3649
3650 case FR_TYPE_IPV4_ADDR:
3652 {
3653 fr_value_box_t tmp;
3654
3655 switch (dst_type) {
3656 case FR_TYPE_UINT32:
3657 case FR_TYPE_INT64:
3658 case FR_TYPE_UINT64:
3659 case FR_TYPE_DATE:
3660 case FR_TYPE_TIME_DELTA:
3661 break;
3662
3663 default:
3664 goto bad_cast;
3665 }
3666
3667 fr_value_box_init(&tmp, FR_TYPE_UINT32, src->enumv, src->tainted);
3668 memcpy(&tmp.vb_uint32, &src->vb_ip.addr.v4, sizeof(tmp.vb_uint32));
3669 fr_value_box_hton(&tmp, &tmp);
3670 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, &tmp);
3671 }
3672
3673 case FR_TYPE_ETHERNET:
3674 {
3675 fr_value_box_t tmp;
3676
3677 switch (dst_type) {
3678 case FR_TYPE_INT64:
3679 case FR_TYPE_UINT64:
3680 case FR_TYPE_DATE:
3681 case FR_TYPE_TIME_DELTA:
3682 break;
3683
3684 default:
3685 goto bad_cast;
3686 }
3687
3688 fr_value_box_init(&tmp, FR_TYPE_UINT64, src->enumv, src->tainted);
3689 memcpy(((uint8_t *)&tmp.vb_uint64) + (sizeof(tmp.vb_uint64) - sizeof(src->vb_ether)),
3690 &src->vb_ether, sizeof(src->vb_ether));
3691#ifndef WORDS_BIGENDIAN
3692 /*
3693 * Ethernet addresses are always stored bigendian,
3694 * convert to native on little endian systems
3695 */
3696 fr_value_box_hton(&tmp, &tmp);
3697#endif
3698 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, &tmp);
3699 }
3700
3701 case FR_TYPE_IFID:
3702 {
3703 switch (dst_type) {
3704 case FR_TYPE_UINT64:
3705 break;
3706
3707 default:
3708 goto bad_cast;
3709 }
3710
3711 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3712 dst->vb_uint64 = fr_nbo_to_uint64(&src->vb_ifid[0]);
3713 return 0;
3714 }
3715
3716 case FR_TYPE_FLOAT32:
3717 if ((double) src->vb_float32 < (double) fr_value_box_integer_min[dst_type]) {
3718 underflow:
3719 fr_strerror_const("Source value for cast would underflow destination type");
3720 return -1;
3721 }
3722
3723 if ((double) src->vb_float32 > (double) fr_value_box_integer_max[dst_type]) {
3724 overflow:
3725 fr_strerror_const("Source value for cast would overflow destination type");
3726 return -1;
3727 }
3728
3729 switch (dst_type) {
3730 case FR_TYPE_UINT8:
3731 dst->vb_uint8 = src->vb_float32;
3732 break;
3733
3734 case FR_TYPE_UINT16:
3735 dst->vb_uint16 = src->vb_float32;
3736 break;
3737
3738 case FR_TYPE_UINT32:
3739 dst->vb_uint32 = src->vb_float32;
3740 break;
3741
3742 case FR_TYPE_UINT64:
3743 dst->vb_uint64 = src->vb_float32;
3744 break;
3745
3746 case FR_TYPE_INT8:
3747 dst->vb_int8 = src->vb_float32;
3748 break;
3749
3750 case FR_TYPE_INT16:
3751 dst->vb_int16 = src->vb_float32;
3752 break;
3753
3754 case FR_TYPE_INT32:
3755 dst->vb_int32 = src->vb_float32;
3756 break;
3757
3758 case FR_TYPE_INT64:
3759 dst->vb_int64 = src->vb_float32;
3760 break;
3761
3762 case FR_TYPE_SIZE:
3763 dst->vb_size = src->vb_float32;
3764 break;
3765
3766 case FR_TYPE_DATE: {
3767 int64_t sec, nsec;
3768
3769 sec = src->vb_float32;
3770 sec *= NSEC;
3771 nsec = ((src->vb_float32 * NSEC) - ((float) sec));
3772
3773 dst->vb_date = fr_unix_time_from_nsec(sec + nsec);
3774 }
3775 break;
3776
3777 case FR_TYPE_TIME_DELTA: {
3778 int64_t sec, nsec;
3779 int64_t res = NSEC;
3780 bool fail = false;
3781
3782 if (dst->enumv) res = fr_time_multiplier_by_res[(fr_time_res_t)dst->enumv->flags.flag_time_res];
3783
3784 sec = src->vb_float32;
3785 sec *= res;
3786 nsec = (((double) src->vb_float32 * res) - ((double) sec));
3787
3788 dst->vb_time_delta = fr_time_delta_from_integer(&fail, sec + nsec,
3789 dst->enumv ? (fr_time_res_t)dst->enumv->flags.flag_time_res : FR_TIME_RES_NSEC);
3790 if (fail) goto overflow;
3791 }
3792 break;
3793
3794 default:
3795 goto bad_cast;
3796 }
3797 return 0;
3798
3799 case FR_TYPE_FLOAT64:
3800 if (src->vb_float64 < (double) fr_value_box_integer_min[dst_type]) goto underflow;
3801
3802 if (src->vb_float64 > (double) fr_value_box_integer_max[dst_type]) goto overflow;
3803
3804 switch (dst_type) {
3805 case FR_TYPE_UINT8:
3806 dst->vb_uint8 = src->vb_float64;
3807 break;
3808
3809 case FR_TYPE_UINT16:
3810 dst->vb_uint16 = src->vb_float64;
3811 break;
3812
3813 case FR_TYPE_UINT32:
3814 dst->vb_uint32 = src->vb_float64;
3815 break;
3816
3817 case FR_TYPE_UINT64:
3818 dst->vb_uint64 = src->vb_float64;
3819 break;
3820
3821 case FR_TYPE_INT8:
3822 dst->vb_int8 = src->vb_float64;
3823 break;
3824
3825 case FR_TYPE_INT16:
3826 dst->vb_int16 = src->vb_float64;
3827 break;
3828
3829 case FR_TYPE_INT32:
3830 dst->vb_int32 = src->vb_float64;
3831 break;
3832
3833 case FR_TYPE_INT64:
3834 dst->vb_int64 = src->vb_float64;
3835 break;
3836
3837 case FR_TYPE_SIZE:
3838 dst->vb_size = src->vb_float64;
3839 break;
3840
3841 case FR_TYPE_DATE: {
3842 int64_t sec, nsec;
3843
3844 sec = src->vb_float64;
3845
3846 if (unlikely((sec > INT64_MAX / NSEC) || (sec < INT64_MIN / NSEC))) goto overflow;
3847 sec *= NSEC;
3848 nsec = ((src->vb_float64 * NSEC) - ((double) sec));
3849
3850 dst->vb_date = fr_unix_time_from_nsec(sec + nsec);
3851 }
3852 break;
3853
3854 case FR_TYPE_TIME_DELTA: {
3855 int64_t sec, nsec;
3856 int64_t res = NSEC;
3857 bool fail = false;
3858
3859 if (dst->enumv) res = fr_time_multiplier_by_res[(fr_time_res_t)dst->enumv->flags.flag_time_res];
3860
3861 sec = src->vb_float64;
3862
3863 if (unlikely((sec > INT64_MAX / res) || (sec < INT64_MIN / res))) goto overflow;
3864 sec *= res;
3865 nsec = ((src->vb_float64 * res) - ((double) sec));
3866
3867 dst->vb_time_delta = fr_time_delta_from_integer(&fail, sec + nsec,
3868 dst->enumv ? (fr_time_res_t)dst->enumv->flags.flag_time_res : FR_TIME_RES_NSEC);
3869 if (fail) goto overflow;
3870 }
3871 break;
3872
3873 default:
3874 goto bad_cast;
3875 }
3876 return 0;
3877
3878 default:
3879 break;
3880 }
3881
3882bad_cast:
3883 return fr_value_box_cast_unsupported(dst_type, src->type);
3884}
3885
3886/** Convert any value to a floating point value
3887 *
3888 * @param ctx unused.
3889 * @param dst Where to write result of casting.
3890 * @param dst_type to cast to.
3891 * @param dst_enumv enumeration values.
3892 * @param src Input data.
3893 */
3894static inline int fr_value_box_cast_to_float(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst,
3895 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3896 fr_value_box_t const *src)
3897{
3898 double num;
3899
3900 switch (src->type) {
3901 case FR_TYPE_FLOAT32:
3902 if (dst_type == FR_TYPE_FLOAT64) {
3903 num = (double) src->vb_float32;
3904 goto good_cast;
3905 }
3906
3907 goto bad_cast;
3908
3909 case FR_TYPE_FLOAT64:
3910 if (dst_type == FR_TYPE_FLOAT32) {
3911 num = src->vb_float64;
3912 goto good_cast;
3913 }
3914
3915 goto bad_cast;
3916
3917 case FR_TYPE_BOOL:
3918 num = src->vb_bool;
3919 goto good_cast;
3920
3921 case FR_TYPE_INT8:
3922 num = src->vb_int8;
3923 goto good_cast;
3924
3925 case FR_TYPE_INT16:
3926 num = src->vb_int16;
3927 goto good_cast;
3928
3929 case FR_TYPE_INT32:
3930 num = src->vb_int32;
3931 goto good_cast;
3932
3933 case FR_TYPE_INT64:
3934 num = src->vb_int64;
3935 goto good_cast;
3936
3937 case FR_TYPE_UINT8:
3938 num = src->vb_uint8;
3939 goto good_cast;
3940
3941 case FR_TYPE_UINT16:
3942 num = src->vb_uint16;
3943 goto good_cast;
3944
3945 case FR_TYPE_UINT32:
3946 num = src->vb_uint32;
3947 goto good_cast;
3948
3949 case FR_TYPE_UINT64:
3950 num = src->vb_uint64;
3951 goto good_cast;
3952
3953 case FR_TYPE_DATE:
3954 /*
3955 * Unix times are in nanoseconds
3956 */
3957 num = fr_unix_time_unwrap(src->vb_date);
3958 num /= NSEC;
3959 goto good_cast;
3960
3961 case FR_TYPE_TIME_DELTA:
3962 /*
3963 * Time deltas are in nanoseconds, but scaled.
3964 */
3965 num = fr_time_delta_unwrap(src->vb_time_delta);
3966 if (src->enumv) {
3967 num /= fr_time_multiplier_by_res[(fr_time_res_t)src->enumv->flags.flag_time_res];
3968 } else {
3969 num /= NSEC;
3970 }
3971 goto good_cast;
3972
3973 case FR_TYPE_SIZE:
3974 num = src->vb_size;
3975
3976 good_cast:
3977 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3979
3980 if (dst_type == FR_TYPE_FLOAT32) {
3981 dst->vb_float32 = num;
3982 } else {
3983 dst->vb_float64 = num;
3984 }
3985 return 0;
3986
3987 default:
3988 break;
3989 }
3990
3991bad_cast:
3992 return fr_value_box_cast_unsupported(dst_type, src->type);
3993}
3994
3995
3996/** Convert one type of fr_value_box_t to another
3997 *
3998 * This should be the canonical function used to convert between INTERNAL data formats.
3999 *
4000 * If you want to convert from PRESENTATION format, use #fr_value_box_from_substr.
4001 *
4002 * @note src and dst must not be the same box. We do not support casting in place.
4003 *
4004 * @param ctx to allocate buffers in (usually the same as dst)
4005 * @param dst Where to write result of casting.
4006 * @param dst_type to cast to.
4007 * @param dst_enumv Aliases for values contained within this fr_value_box_t.
4008 * If #fr_value_box_t is passed to #fr_value_box_aprint
4009 * names will be printed instead of actual value.
4010 * @param src Input data.
4011 * @return
4012 * - 0 on success.
4013 * - -1 on failure.
4014 */
4015int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst,
4016 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
4017 fr_value_box_t const *src)
4018{
4019 if (!fr_cond_assert(src != dst)) return -1;
4020
4021 if (fr_type_is_non_leaf(dst_type)) {
4022 fr_strerror_printf("Invalid cast from %s to %s. Can only cast simple data types",
4023 fr_type_to_str(src->type),
4024 fr_type_to_str(dst_type));
4025 return -1;
4026 }
4027
4028 /*
4029 * If it's the same type, copy, but set the enumv
4030 * in the destination box to be the one provided.
4031 *
4032 * The theory here is that the attribute value isn't
4033 * being converted into its presentation format and
4034 * re-parsed, and the enumv names only get applied
4035 * when converting internal values to/from strings,
4036 * so it's OK just to swap out the enumv.
4037 *
4038 * If there's a compelling case in the future we
4039 * might revisit this, but it'd likely mean fixing
4040 * all the casting functions to treat any value
4041 * with an enumv as a string, which seems weird.
4042 */
4043 if (dst_type == src->type) {
4044 int ret;
4045
4046 ret = fr_value_box_copy(ctx, dst, src);
4047 if (ret < 0) return ret;
4048
4049 if (dst_enumv) dst->enumv = dst_enumv;
4050
4051 return ret;
4052 }
4053
4054 /*
4055 * Initialise dst
4056 */
4057 fr_value_box_init(dst, dst_type, NULL, src->tainted);
4058
4059 /*
4060 * Dispatch to specialised cast functions
4061 */
4062 switch (dst_type) {
4063 case FR_TYPE_STRING:
4064 return fr_value_box_cast_to_strvalue(ctx, dst, dst_type, dst_enumv, src);
4065
4066 case FR_TYPE_OCTETS:
4067 return fr_value_box_cast_to_octets(ctx, dst, dst_type, dst_enumv, src);
4068
4069 case FR_TYPE_IPV4_ADDR:
4070 return fr_value_box_cast_to_ipv4addr(ctx, dst, dst_type, dst_enumv, src);
4071
4073 return fr_value_box_cast_to_ipv4prefix(ctx, dst, dst_type, dst_enumv, src);
4074
4075 case FR_TYPE_IPV6_ADDR:
4076 return fr_value_box_cast_to_ipv6addr(ctx, dst, dst_type, dst_enumv, src);
4077
4079 return fr_value_box_cast_to_ipv6prefix(ctx, dst, dst_type, dst_enumv, src);
4080
4083 break;
4084 /*
4085 * Need func
4086 */
4087 case FR_TYPE_IFID:
4088 break;
4089
4090 case FR_TYPE_ETHERNET:
4091 return fr_value_box_cast_to_ethernet(ctx, dst, dst_type, dst_enumv, src);
4092
4093 case FR_TYPE_BOOL:
4094 return fr_value_box_cast_to_bool(ctx, dst, dst_type, dst_enumv, src);
4095
4096 case FR_TYPE_DATE:
4097 if (src->type != FR_TYPE_TIME_DELTA) return fr_value_box_cast_to_integer(ctx, dst, dst_type, dst_enumv, src);
4098
4099 if (fr_time_delta_isneg(src->vb_time_delta)) {
4100 fr_strerror_const("Input to data type would underflow");
4101 return -1;
4102 }
4103
4105 dst->enumv = dst_enumv;
4106 dst->vb_date = fr_unix_time_wrap(fr_time_delta_unwrap(src->vb_time_delta));
4107 return 0;
4108
4109 case FR_TYPE_TIME_DELTA:
4110 /*
4111 * Unix time cast to time_delta is just nanoseconds since the epoch.
4112 *
4113 * Note that we do NOT change time resolution, but we DO change enumv. Both unix time
4114 * and time_delta are tracked internally as nanoseconds, and the only use of precision is
4115 * for printing / parsing.
4116 */
4117 if (src->type == FR_TYPE_DATE) {
4118 uint64_t when;
4119
4120 when = fr_unix_time_unwrap(src->vb_date);
4121 if (when > INT64_MAX) {
4122 fr_strerror_const("Input to data type would overflow");
4123 return -1;
4124 }
4125
4127 dst->enumv = dst_enumv;
4128 dst->vb_time_delta = fr_time_delta_wrap((int64_t) when);
4129 return 0;
4130 }
4132
4133 case FR_TYPE_UINT8:
4134 case FR_TYPE_UINT16:
4135 case FR_TYPE_UINT32:
4136 case FR_TYPE_UINT64:
4137 case FR_TYPE_INT8:
4138 case FR_TYPE_INT16:
4139 case FR_TYPE_INT32:
4140 case FR_TYPE_INT64:
4141 case FR_TYPE_SIZE:
4142 return fr_value_box_cast_to_integer(ctx, dst, dst_type, dst_enumv, src);
4143
4144 case FR_TYPE_FLOAT32:
4145 case FR_TYPE_FLOAT64:
4146 if (fr_type_is_fixed_size(src->type)) {
4147 return fr_value_box_cast_to_float(ctx, dst, dst_type, dst_enumv, src);
4148 }
4149 break; /* use generic string/octets stuff below */
4150
4151#if 0
4152 case FR_TYPE_ATTR:
4153 /*
4154 * Convert it to an integer of the correct length. Then, cast it in place.
4155 */
4156 switch (src->vb_attr->flags.length) {
4157 case 1:
4158 fr_value_box_init(dst, FR_TYPE_UINT8, NULL, false);
4159 dst->vb_uint8 = src->vb_attr->attr;
4160 break;
4161
4162 case 2:
4163 fr_value_box_init(dst, FR_TYPE_UINT16, NULL, false);
4164 dst->vb_uint16 = src->vb_attr->attr;
4165 break;
4166
4167 case 4:
4168 fr_value_box_init(dst, FR_TYPE_UINT32, NULL, false);
4169 dst->vb_uint32 = src->vb_attr->attr;
4170 break;
4171
4172 default:
4173 fr_strerror_printf("Unsupported length '%d' for attribute %s",
4174 src->vb_attr->flags.length, src->vb_attr->name);
4175 return 0;
4176 }
4177
4178 return fr_value_box_cast_in_place(ctx, dst, dst_type, dst_enumv);
4179#else
4180 case FR_TYPE_ATTR:
4181 if (src->type == FR_TYPE_STRING) break;
4182
4184
4185#endif
4186 /*
4187 * Invalid types for casting (were caught earlier)
4188 */
4189 case FR_TYPE_NON_LEAF:
4190 fr_strerror_printf("Invalid cast from %s to %s. Invalid destination type",
4191 fr_type_to_str(src->type),
4192 fr_type_to_str(dst_type));
4193 return -1;
4194 }
4195
4196 /*
4197 * Deserialise a fr_value_box_t
4198 */
4199 if (src->type == FR_TYPE_STRING) return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
4200 src->vb_strvalue, src->vb_length,
4201 NULL);
4202
4203 if (src->type == FR_TYPE_OCTETS) {
4204 fr_value_box_t tmp;
4205
4206 if (src->vb_length < network_min_size(dst_type)) {
4207 fr_strerror_printf("Invalid cast from %s to %s. Source is length %zu is smaller than "
4208 "destination type size %zu",
4209 fr_type_to_str(src->type),
4210 fr_type_to_str(dst_type),
4211 src->vb_length,
4212 network_min_size(dst_type));
4213 return -1;
4214 }
4215
4216 if (src->vb_length > network_max_size(dst_type)) {
4217 fr_strerror_printf("Invalid cast from %s to %s. Source length %zu is greater than "
4218 "destination type size %zu",
4219 fr_type_to_str(src->type),
4220 fr_type_to_str(dst_type),
4221 src->vb_length,
4222 network_max_size(dst_type));
4223 return -1;
4224 }
4225
4226 fr_value_box_init(&tmp, dst_type, NULL, false);
4227
4228 /*
4229 * Copy the raw octets into the datum of a value_box
4230 * inverting bytesex for uint32s (if LE).
4231 */
4232 memcpy(&tmp.datum, src->vb_octets, fr_value_box_field_sizes[dst_type]);
4233 tmp.type = dst_type;
4234 dst->enumv = dst_enumv;
4235
4236 fr_value_box_hton(dst, &tmp);
4237 fr_value_box_safety_copy(dst, src);
4238 return 0;
4239 }
4240
4241 memcpy(&dst->datum, &src->datum, fr_value_box_field_sizes[src->type]);
4242
4244 dst->enumv = dst_enumv;
4245
4246 return 0;
4247}
4248
4249/** Convert one type of fr_value_box_t to another in place
4250 *
4251 * This should be the canonical function used to convert between INTERNAL data formats.
4252 *
4253 * If you want to convert from PRESENTATION format, use #fr_value_box_from_substr.
4254 *
4255 * @param ctx to allocate buffers in (usually the same as dst)
4256 * @param vb to cast.
4257 * @param dst_type to cast to.
4258 * @param dst_enumv Aliases for values contained within this fr_value_box_t.
4259 * If #fr_value_box_t is passed to #fr_value_box_aprint
4260 * names will be printed instead of actual value.
4261 * @return
4262 * - 0 on success.
4263 * - -1 on failure.
4264 */
4266 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
4267{
4268 fr_value_box_t tmp;
4269 /*
4270 * Store list pointers to restore later - fr_value_box_cast clears them
4271 */
4272 fr_value_box_entry_t entry = vb->entry;
4273
4274 /*
4275 * Simple case, destination type and current
4276 * type are the same.
4277 */
4278 if (vb->type == dst_type) {
4279 vb->enumv = dst_enumv; /* Update the enumv as this may be different */
4280 return 0;
4281 }
4282
4283 /*
4284 * Copy meta data and any existing buffers to
4285 * a temporary box. We then clear that value
4286 * box after the cast has been completed,
4287 * freeing any old buffers.
4288 */
4289 fr_value_box_copy_shallow(NULL, &tmp, vb);
4290
4291 if (fr_value_box_cast(ctx, vb, dst_type, dst_enumv, &tmp) < 0) {
4292 /*
4293 * On error, make sure the original
4294 * box is left in a consistent state.
4295 */
4296 fr_value_box_copy_shallow(NULL, vb, &tmp);
4297 vb->entry = entry;
4298 return -1;
4299 }
4300 fr_value_box_clear_value(&tmp); /* Clear out any old buffers */
4301
4302 /*
4303 * Restore list pointers
4304 */
4305 vb->entry = entry;
4306
4307 return 0;
4308}
4309
4310/** Return a uint64_t from a #fr_value_box_t
4311 *
4312 * @param[in] vb the value-box. Must be an unsigned integer data type.
4313 * @return the value as uint64_t.
4314 */
4316{
4317#undef O
4318#define O(_x, _y) case FR_TYPE_##_x: return vb->vb_##_y
4319
4320
4321 switch (vb->type) {
4322 O(BOOL, bool);
4323 O(UINT8, uint8);
4324 O(UINT16, uint16);
4325 O(UINT32, uint32);
4326 O(UINT64, uint64);
4327 O(SIZE, size);
4328
4329 default:
4330 fr_assert(0);
4331 return 0;
4332 }
4333}
4334
4335
4336/** Assign a #fr_value_box_t value from an #fr_ipaddr_t
4337 *
4338 * Automatically determines the type of the value box from the ipaddr address family
4339 * and the length of the prefix field.
4340 *
4341 * @param[in] dst to assign ipaddr to.
4342 * @param[in] enumv Aliases for values.
4343 * @param[in] ipaddr to copy address from.
4344 * @param[in] tainted Whether the value came from a trusted source.
4345 * @return
4346 * - 0 on success.
4347 * - -1 on failure.
4348 */
4349int fr_value_box_ipaddr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, fr_ipaddr_t const *ipaddr, bool tainted)
4350{
4352
4353 switch (ipaddr->af) {
4354 case AF_INET:
4356 break;
4357
4358 case AF_INET6:
4360 break;
4361
4362 default:
4363 fr_strerror_printf("Invalid address family %i", ipaddr->af);
4364 return -1;
4365 }
4366
4367 fr_value_box_init(dst, type, enumv, tainted);
4368 memcpy(&dst->vb_ip, ipaddr, sizeof(dst->vb_ip));
4369
4370 return 0;
4371}
4372
4373/** Unbox an IP address performing a type check
4374 *
4375 * @param[out] dst Where to copy the IP address to.
4376 * @param[in] src Where to copy the IP address from.
4377 * @return
4378 * - 0 on success.
4379 * - -1 on type mismatch.
4380 */
4382{
4383 if (!fr_type_is_ip(src->type)) {
4384 fr_strerror_printf("Unboxing failed. Needed IPv4/6 addr/prefix, had type %s",
4385 fr_type_to_str(src->type));
4386 return -1;
4387 }
4388
4389 memcpy(dst, &src->vb_ip, sizeof(*dst));
4390
4391 return 0;
4392}
4393
4394/** Clear/free any existing value
4395 *
4396 * @note Do not use on uninitialised memory.
4397 *
4398 * @param[in] data to clear.
4399 */
4401{
4403
4404 switch (data->type) {
4405 case FR_TYPE_OCTETS:
4406 case FR_TYPE_STRING:
4407 if (data->vb_secret) memset_explicit(data->datum.ptr, 0, data->vb_length);
4408 talloc_free(data->datum.ptr);
4409 break;
4410
4411 case FR_TYPE_GROUP:
4412 /*
4413 * Depth first freeing of children
4414 *
4415 * This ensures orderly freeing, regardless
4416 * of talloc hierarchy.
4417 */
4418 {
4419 fr_value_box_t *vb;
4420
4421 while ((vb = fr_value_box_list_pop_head(&data->vb_group)) != NULL) {
4423 talloc_free(vb);
4424 }
4425 }
4426 return;
4427
4428 case FR_TYPE_NULL:
4429 break;
4430
4432 talloc_free(data->vb_cursor);
4433 break;
4434
4435 default:
4436 break;
4437 }
4438
4439 memset(&data->datum, 0, sizeof(data->datum));
4440}
4441
4442/** Clear/free any existing value and metadata
4443 *
4444 * @note Do not use on uninitialised memory.
4445 *
4446 * @param[in] data to clear.
4447 */
4453
4454/** Copy value data verbatim duplicating any buffers
4455 *
4456 * @note Will free any exiting buffers associated with the dst #fr_value_box_t.
4457 *
4458 * @param ctx To allocate buffers in.
4459 * @param dst Where to copy value_box to.
4460 * @param src Where to copy value_box from.
4461 * @return
4462 * - 0 on success.
4463 * - -1 on failure.
4464 */
4465int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
4466{
4467 switch (src->type) {
4468 case FR_TYPE_NUMERIC:
4469 case FR_TYPE_IP:
4470 case FR_TYPE_IFID:
4471 case FR_TYPE_ETHERNET:
4472 fr_value_box_memcpy_out(fr_value_box_raw(dst, src->type), src);
4473 fr_value_box_copy_meta(dst, src);
4474 break;
4475
4476 case FR_TYPE_NULL:
4477 fr_value_box_copy_meta(dst, src);
4478 break;
4479
4480 case FR_TYPE_STRING:
4481 {
4482 char *str = NULL;
4483
4484 /*
4485 * Zero length strings still have a one uint8 buffer
4486 */
4487 str = talloc_bstrndup(ctx, src->vb_strvalue, src->vb_length);
4488 if (!str) {
4489 fr_strerror_const("Failed allocating string buffer");
4490 return -1;
4491 }
4492 dst->vb_strvalue = str;
4493 fr_value_box_copy_meta(dst, src);
4494 }
4495 break;
4496
4497 case FR_TYPE_OCTETS:
4498 {
4499 uint8_t *bin;
4500
4501 if (src->vb_length) {
4502 bin = talloc_memdup(ctx, src->vb_octets, src->vb_length);
4503 if (!bin) {
4504 fr_strerror_const("Failed allocating octets buffer");
4505 return -1;
4506 }
4507 talloc_set_type(bin, uint8_t);
4508 } else {
4509 bin = talloc_array(ctx, uint8_t, 0);
4510 }
4511 dst->vb_octets = bin;
4512 fr_value_box_copy_meta(dst, src);
4513 }
4514 break;
4515
4516 case FR_TYPE_GROUP:
4517 {
4518 fr_value_box_t *child = NULL;
4519
4520 fr_value_box_copy_meta(dst, src); /* Initialises group child dlist */
4521
4522 while ((child = fr_value_box_list_next(&src->vb_group, child))) {
4523 fr_value_box_t *new;
4524
4525 /*
4526 * Build out the child
4527 */
4528 new = fr_value_box_alloc_null(ctx);
4529 if (unlikely(!new)) {
4530 group_error:
4531 fr_strerror_const("Failed duplicating group child");
4532 fr_value_box_list_talloc_free(&dst->vb_group);
4533 return -1;
4534 }
4535
4536 /*
4537 * Populate it with the data from the original child.
4538 *
4539 * We do NOT update the dst safety. The individual boxes have safety. A group
4540 * doesn't.
4541 */
4542 if (unlikely(fr_value_box_copy(new, new, child) < 0)) goto group_error;
4543 fr_value_box_list_insert_tail(&dst->vb_group, new);
4544 }
4545 }
4546 break;
4547
4548 case FR_TYPE_ATTR:
4549 fr_value_box_copy_meta(dst, src);
4550
4551 /* raw also sets is_unknown */
4552 if (src->vb_attr->flags.is_unknown) {
4553 dst->vb_attr = fr_dict_attr_unknown_copy(ctx, src->vb_attr);
4554 if (!dst->vb_attr) return -1;
4555 break;
4556 }
4557 dst->vb_attr = src->vb_attr;
4558 break;
4559
4560 case FR_TYPE_TLV:
4561 case FR_TYPE_STRUCT:
4562 case FR_TYPE_VSA:
4563 case FR_TYPE_VENDOR:
4564 case FR_TYPE_UNION:
4565 case FR_TYPE_VOID:
4566 case FR_TYPE_VALUE_BOX:
4569 case FR_TYPE_MAX:
4570 fr_assert(0);
4571 fr_strerror_printf("Cannot copy data type '%s'", fr_type_to_str(src->type));
4572 return -1;
4573 }
4574
4575 VERIFY_CLEAR(dst);
4576
4577 return 0;
4578}
4579
4580/** Perform a shallow copy of a value_box
4581 *
4582 * Like #fr_value_box_copy, but does not duplicate the buffers of the src value_box.
4583 *
4584 * For #FR_TYPE_STRING and #FR_TYPE_OCTETS adds a reference from ctx so that the
4585 * buffer cannot be freed until the ctx is freed.
4586 *
4587 * @param[in] ctx to add reference from. If NULL no reference will be added.
4588 * @param[in] dst to copy value to.
4589 * @param[in] src to copy value from.
4590 */
4591void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
4592{
4593 switch (src->type) {
4594 default:
4595 if (unlikely(fr_value_box_copy(NULL, dst, src) < 0)) return;
4596 break;
4597
4598 case FR_TYPE_STRING:
4599 case FR_TYPE_OCTETS:
4600 dst->datum.ptr = ctx ? talloc_reference(ctx, src->datum.ptr) : src->datum.ptr;
4601 fr_value_box_copy_meta(dst, src);
4602 break;
4603
4604 case FR_TYPE_ATTR:
4605 dst->vb_attr = src->vb_attr;
4606 fr_value_box_copy_meta(dst, src);
4607 break;
4608
4609 case FR_TYPE_VOID:
4610 dst->vb_void = src->vb_void;
4611 fr_value_box_copy_meta(dst, src);
4612 break;
4613 }
4614
4615 VERIFY_CLEAR(dst);
4616}
4617
4618/** Copy value data verbatim moving any buffers to the specified context
4619 *
4620 * @param[in] ctx to allocate any new buffers in.
4621 * @param[in] dst to copy value to.
4622 * @param[in] src to copy value from.
4623 * @return
4624 * - 0 on success.
4625 * - -1 on failure.
4626 */
4627int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
4628{
4629 VALUE_BOX_VERIFY(src);
4630
4631 switch (src->type) {
4632 default:
4633 return fr_value_box_copy(ctx, dst, src);
4634
4635 case FR_TYPE_STRING:
4636 {
4637 char const *str;
4638
4639 str = talloc_steal(ctx, src->vb_strvalue);
4640 if (!str) {
4641 fr_strerror_const("Failed stealing string buffer");
4642 return -1;
4643 }
4644 talloc_set_type(str, char);
4645 dst->vb_strvalue = str;
4646 fr_value_box_copy_meta(dst, src);
4647 memset(&src->datum, 0, sizeof(src->datum));
4648 }
4649 break;
4650
4651 case FR_TYPE_OCTETS:
4652 {
4653 uint8_t const *bin;
4654
4655 bin = talloc_steal(ctx, src->vb_octets);
4656 if (!bin) {
4657 fr_strerror_const("Failed stealing octets buffer");
4658 return -1;
4659 }
4660 talloc_set_type(bin, uint8_t);
4661
4662 dst->vb_octets = bin;
4663 fr_value_box_copy_meta(dst, src);
4664 memset(&src->datum, 0, sizeof(src->datum));
4665 }
4666 break;
4667
4668 case FR_TYPE_GROUP:
4669 {
4670 fr_value_box_t *child;
4671
4672 while ((child = fr_value_box_list_pop_head(&src->vb_group))) {
4673 child = talloc_steal(ctx, child);
4674 if (unlikely(!child)) {
4675 fr_strerror_const("Failed stealing child");
4676 return -1;
4677 }
4678 fr_value_box_list_insert_tail(&dst->vb_group, child);
4679
4680 VERIFY_CLEAR(child);
4681 }
4682 }
4683 break;
4684 }
4685
4686 VERIFY_CLEAR(dst);
4687
4688 return 0;
4689}
4690
4691/** Copy a nul terminated string to a #fr_value_box_t
4692 *
4693 * @param[in] ctx to allocate any new buffers in.
4694 * @param[in] dst to assign new buffer to.
4695 * @param[in] enumv Aliases for values.
4696 * @param[in] src a nul terminated buffer.
4697 * @param[in] tainted Whether the value came from a trusted source.
4698 * @return
4699 * - 0 on success.
4700 * - -1 on failure.
4701 */
4702int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4703 char const *src, bool tainted)
4704{
4705 char const *str;
4706
4707 str = talloc_strdup(ctx, src);
4708 if (!str) {
4709 fr_strerror_const("Failed allocating string buffer");
4710 return -1;
4711 }
4712
4713 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4714 dst->vb_strvalue = str;
4715 dst->vb_length = talloc_strlen(str);
4716
4717 return 0;
4718}
4719
4720/** Trim the length of the string buffer to match the length of the C string
4721 *
4722 * @param[in] ctx to re-alloc the buffer in.
4723 * @param[in,out] vb to trim.
4724 * @return
4725 * - 0 on success.
4726 * - -1 on failure.
4727 */
4728int fr_value_box_strtrim(TALLOC_CTX *ctx, fr_value_box_t *vb)
4729{
4730 size_t len;
4731 char *str;
4732
4733 if (!fr_cond_assert(vb->type == FR_TYPE_STRING)) return -1;
4734
4735 len = strlen(vb->vb_strvalue);
4736 str = talloc_realloc(ctx, UNCONST(char *, vb->vb_strvalue), char, len + 1);
4737 if (!str) {
4738 fr_strerror_const("Failed re-allocing string buffer");
4739 return -1;
4740 }
4741 vb->vb_strvalue = str;
4742 vb->vb_length = len;
4743
4744 return 0;
4745}
4746
4747/** Print a formatted string using our internal printf wrapper and assign it to a value box
4748 *
4749 * @param[in] ctx to allocate any new buffers in.
4750 * @param[in] dst to assign new buffer to.
4751 * @param[in] enumv Aliases for values.
4752 * @param[in] fmt The printf format string to process.
4753 * @param[in] tainted Whether the value came from a trusted source.
4754 * @param[in] ap Substitution arguments.
4755 * @return
4756 * - 0 on success.
4757 * - -1 on failure.
4758 */
4759int fr_value_box_vasprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted,
4760 char const *fmt, va_list ap)
4761{
4762 va_list aq;
4763 char *str;
4764
4765 va_copy(aq, ap); /* See vlog_module_failure_msg for why */
4766 str = fr_vasprintf(ctx, fmt, aq);
4767 va_end(aq);
4768
4769 if (!str) return -1;
4770
4771 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4772 dst->vb_strvalue = str;
4773 dst->vb_length = talloc_strlen(str);
4774
4775 return 0;
4776}
4777
4778/** Print a formatted string using our internal printf wrapper and assign it to a value box
4779 *
4780 * @param[in] ctx to allocate any new buffers in.
4781 * @param[in] dst to assign new buffer to.
4782 * @param[in] enumv Aliases for values.
4783 * @param[in] tainted Whether the value came from a trusted source.
4784 * @param[in] fmt The printf format string to process.
4785 * @param[in] ... Substitution arguments.
4786 * @return
4787 * - 0 on success.
4788 * - -1 on failure.
4789 */
4790int fr_value_box_asprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted,
4791 char const *fmt, ...)
4792{
4793 va_list ap;
4794 int ret;
4795
4796 va_start(ap, fmt);
4797 ret = fr_value_box_vasprintf(ctx, dst, enumv, tainted, fmt, ap);
4798 va_end(ap);
4799
4800 return ret;
4801}
4802
4803/** Assign a buffer containing a nul terminated string to a box, but don't copy it
4804 *
4805 * @note Input string will not be duplicated.
4806 *
4807 * @param[in] dst to assign string to.
4808 * @param[in] enumv Aliases for values.
4809 * @param[in] src to copy string from.
4810 * @param[in] tainted Whether the value came from a trusted source.
4811 */
4813 char const *src, bool tainted)
4814{
4815 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4816 dst->vb_strvalue = src;
4817 dst->vb_length = strlen(src);
4818}
4819
4820/** Free the existing buffer (if talloced) associated with the valuebox, and replace it with a new one
4821 *
4822 * @note Input string will not be duplicated.
4823 *
4824 * @param[in] vb to replace string in.
4825 * @param[in] src to assign string from.
4826 * @param[in] len of src.
4827 */
4829{
4831 vb->vb_strvalue = src;
4832 vb->vb_length = len < 0 ? strlen(src) : (size_t)len;
4833}
4834
4835/** Free the existing buffer (if talloced) associated with the valuebox, and replace it with a copy of a new one
4836 *
4837 * The box's flags are left as they were. src may alias the existing value,
4838 * the copy is taken before the existing value is freed.
4839 *
4840 * @param[in] ctx to allocate the copy in.
4841 * @param[in] vb to replace string in.
4842 * @param[in] src to copy string from.
4843 * @param[in] len of src. If negative, src must be NUL terminated.
4844 * @return
4845 * - 0 on success.
4846 * - -1 on allocation failure.
4847 */
4848int fr_value_box_bstrndup_replace(TALLOC_CTX *ctx, fr_value_box_t *vb, char const *src, ssize_t len)
4849{
4850 char *str;
4851
4852 if (len < 0) len = strlen(src);
4853
4854 str = talloc_bstrndup(ctx, src, (size_t)len);
4855 if (unlikely(!str)) {
4856 fr_strerror_const("Failed allocating string buffer");
4857 return -1;
4858 }
4859
4861 vb->vb_strvalue = str;
4862 vb->vb_length = (size_t)len;
4863
4864 return 0;
4865}
4866
4867/** Alloc and assign an empty \0 terminated string to a #fr_value_box_t
4868 *
4869 * @param[in] ctx to allocate any new buffers in.
4870 * @param[out] out if non-null where to write a pointer to the new buffer.
4871 * @param[in] dst to assign new buffer to.
4872 * @param[in] enumv Aliases for values.
4873 * @param[in] len of buffer to allocate.
4874 * @param[in] tainted Whether the value came from a trusted source.
4875 * @return
4876 * - 0 on success.
4877 * - -1 on failure.
4878 */
4879int fr_value_box_bstr_alloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4880 size_t len, bool tainted)
4881{
4882 char *str;
4883
4884 str = talloc_zero_array(ctx, char, len + 1);
4885 if (!str) {
4886 fr_strerror_const("Failed allocating string buffer");
4887 return -1;
4888 }
4889 str[len] = '\0';
4890
4891 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4892 dst->vb_strvalue = str;
4893 dst->vb_length = len;
4894
4895 if (out) *out = str;
4896
4897 return 0;
4898}
4899
4900/** Change the length of a buffer already allocated to a value box
4901 *
4902 * @note Do not use on an uninitialised box.
4903 *
4904 * @param[in] ctx to realloc buffer in.
4905 * @param[out] out if non-null where to write a pointer to the new buffer.
4906 * @param[in] dst to realloc buffer for.
4907 * @param[in] len to realloc to (don't include nul byte).
4908 * @return
4909 * - 0 on success.
4910 * - -1 on failure.
4911 */
4912int fr_value_box_bstr_realloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, size_t len)
4913{
4914 size_t dstlen;
4915 char *str;
4916
4917 fr_assert(dst->type == FR_TYPE_STRING);
4918
4919 dstlen = talloc_strlen(dst->vb_strvalue);
4920 if (dstlen == len) return 0; /* No change */
4921
4922 str = talloc_realloc(ctx, UNCONST(char *, dst->vb_strvalue), char, len + 1);
4923 if (!str) {
4924 fr_strerror_printf("Failed reallocing value box buffer to %zu bytes", len + 1);
4925 return -1;
4926 }
4927
4928 /*
4929 * Zero out the additional bytes
4930 */
4931 if (dstlen < len) {
4932 memset(str + dstlen, '\0', (len - dstlen) + 1);
4933 } else {
4934 str[len] = '\0';
4935 }
4936 dst->vb_strvalue = str;
4937 dst->vb_length = len;
4938
4939 if (out) *out = str;
4940
4941 return 0;
4942}
4943
4944/** Copy a string to to a #fr_value_box_t
4945 *
4946 * @param[in] ctx to allocate any new buffers in.
4947 * @param[in] dst to assign buffer to.
4948 * @param[in] enumv Aliases for values.
4949 * @param[in] src a string. May be NULL only if len == 0.
4950 * @param[in] len of src.
4951 * @param[in] tainted Whether the value came from a trusted source.
4952 */
4953int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4954 char const *src, size_t len, bool tainted)
4955{
4956 char const *str;
4957
4958 if (unlikely((len > 0) && !src)) {
4959 fr_strerror_printf("Invalid arguments to %s. Len > 0 (%zu) but src string was NULL",
4960 __FUNCTION__, len);
4961 return -1;
4962 }
4963
4964 str = talloc_bstrndup(ctx, src, len);
4965 if (!str) {
4966 fr_strerror_const("Failed allocating string buffer");
4967 return -1;
4968 }
4969
4970 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4971 dst->vb_strvalue = str;
4972 dst->vb_length = len;
4973
4974 return 0;
4975}
4976
4977int fr_value_box_bstrndup_dbuff(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4978 fr_dbuff_t *dbuff, size_t len, bool tainted)
4979{
4980 char *str;
4981
4982 str = talloc_array(ctx, char, len + 1);
4983 if (!str) {
4984 fr_strerror_printf("Failed allocating string buffer");
4985 return -1;
4986 }
4987
4988 if (fr_dbuff_out_memcpy((uint8_t *)str, dbuff, len) < 0) {
4989 talloc_free(str);
4990 return -1;
4991 }
4992 str[len] = '\0';
4993
4994 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4995 dst->vb_strvalue = str;
4996 dst->vb_length = len;
4997
4998 return 0;
4999}
5000
5001/** Copy a nul terminated talloced buffer to a #fr_value_box_t
5002 *
5003 * Copy a talloced nul terminated buffer, setting fields in the dst value box appropriately.
5004 *
5005 * The buffer must be \0 terminated, or an error will be returned.
5006 *
5007 * @param[in] ctx to allocate any new buffers in.
5008 * @param[in] dst to assign new buffer to.
5009 * @param[in] enumv Aliases for values.
5010 * @param[in] src a talloced nul terminated buffer.
5011 * @param[in] tainted Whether the value came from a trusted source.
5012 * @return
5013 * - 0 on success.
5014 * - -1 on failure.
5015 */
5016int fr_value_box_bstrdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
5017 char const *src, bool tainted)
5018{
5019 size_t len;
5020
5021 (void)talloc_get_type_abort_const(src, char);
5022
5023 len = talloc_array_length(src);
5024 if ((len == 0) || (src[len - 1] != '\0')) {
5025 fr_strerror_const("Input buffer not \\0 terminated");
5026 return -1;
5027 }
5028
5029 return fr_value_box_bstrndup(ctx, dst, enumv, src, len - 1, tainted);
5030}
5031
5032/** Assign a string to to a #fr_value_box_t
5033 *
5034 * @param[in] dst to assign new buffer to.
5035 * @param[in] enumv Aliases for values.
5036 * @param[in] src a string.
5037 * @param[in] len of src.
5038 * @param[in] tainted Whether the value came from a trusted source.
5039 */
5041 char const *src, size_t len, bool tainted)
5042{
5043 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
5044 dst->vb_strvalue = src;
5045 dst->vb_length = len;
5046}
5047
5048/** Assign a talloced buffer containing a nul terminated string to a box, but don't copy it
5049 *
5050 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
5051 *
5052 * @param[in] ctx to add reference from. If NULL no reference will be added.
5053 * @param[in] dst to assign string to.
5054 * @param[in] enumv Aliases for values.
5055 * @param[in] src to copy string from.
5056 * @param[in] tainted Whether the value came from a trusted source.
5057 * @return
5058 * - 0 on success.
5059 * - -1 on failure.
5060 */
5062 char const *src, bool tainted)
5063{
5064 size_t len;
5065
5066 (void) talloc_get_type_abort_const(src, char);
5067
5068 len = talloc_array_length(src);
5069 if ((len == 0) || (src[len - 1] != '\0')) {
5070 fr_strerror_const("Input buffer not \\0 terminated");
5071 return -1;
5072 }
5073
5074 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
5075 dst->vb_strvalue = ctx ? talloc_reference(ctx, src) : src;
5076 dst->vb_length = len - 1;
5077
5078 return 0;
5079}
5080
5081/** Pre-allocate an octets buffer for filling by the caller
5082 *
5083 * @note Buffer will not be zeroed, as it's assumed the caller will be filling it.
5084 *
5085 * @param[in] ctx to allocate any new buffers in.
5086 * @param[out] out If non-null will be filled with a pointer to the
5087 * new buffer.
5088 * @param[in] dst to assign new buffer to.
5089 * @param[in] enumv Aliases for values.
5090 * @param[in] len of data in the buffer. If 0, a zero length
5091 * talloc buffer will be alloced. dst->vb_octets
5092 * will *NOT* be NULL. You should use the length
5093 * field of the box to determine if any value
5094 * is assigned.
5095 * @param[in] tainted Whether the value came from a trusted source.
5096 * @return
5097 * - 0 on success.
5098 * - -1 on failure.
5099 */
5100int fr_value_box_mem_alloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
5101 size_t len, bool tainted)
5102{
5103 uint8_t *bin;
5104
5105 bin = talloc_array(ctx, uint8_t, len);
5106 if (!bin) {
5107 fr_strerror_const("Failed allocating octets buffer");
5108 return -1;
5109 }
5110 talloc_set_type(bin, uint8_t);
5111
5112 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
5113 dst->vb_octets = bin;
5114 dst->vb_length = len;
5115
5116 if (out) *out = bin;
5117
5118 return 0;
5119}
5120
5121/** Change the length of a buffer already allocated to a value box
5122 *
5123 * @note Do not use on an uninitialised box.
5124 *
5125 * @param[in] ctx to realloc buffer in.
5126 * @param[out] out if non-null where to write a pointer to the new buffer.
5127 * @param[in] dst to realloc buffer for.
5128 * @param[in] len to realloc to.
5129 * @return
5130 * - 0 on success.
5131 * - -1 on failure.
5132 */
5133int fr_value_box_mem_realloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, size_t len)
5134{
5135 size_t dstlen;
5136 uint8_t *bin;
5137
5138 fr_assert(dst->type == FR_TYPE_OCTETS);
5139
5140 dstlen = talloc_array_length(dst->vb_octets);
5141 if (dstlen == len) return 0; /* No change */
5142
5143 /*
5144 * Realloc the buffer. If the new length is 0, we
5145 * need to call talloc_array() instead of talloc_realloc()
5146 * as talloc_realloc() will fail.
5147 */
5148 if (len > 0) {
5149 bin = talloc_realloc(ctx, UNCONST(uint8_t *, dst->vb_octets), uint8_t, len);
5150 } else {
5151 bin = talloc_array(ctx, uint8_t, 0);
5152 }
5153 if (!bin) {
5154 fr_strerror_printf("Failed reallocing value box buffer to %zu bytes", len);
5155 return -1;
5156 }
5157
5158 /*
5159 * Only free the original buffer once we've allocated
5160 * a new empty array.
5161 */
5162 if (len == 0) talloc_const_free(dst->vb_octets);
5163
5164 /*
5165 * Zero out the additional bytes
5166 */
5167 if (dstlen < len) memset(bin + dstlen, 0x00, len - dstlen);
5168 dst->vb_octets = bin;
5169 dst->vb_length = len;
5170
5171 if (out) *out = bin;
5172
5173 return 0;
5174}
5175
5176/** Copy a buffer to a fr_value_box_t
5177 *
5178 * Copy a buffer containing binary data, setting fields in the dst value box appropriately.
5179 *
5180 * @param[in] ctx to allocate any new buffers in.
5181 * @param[in] dst to assign new buffer to.
5182 * @param[in] enumv Aliases for values.
5183 * @param[in] src a buffer.
5184 * @param[in] len of data in the buffer. If 0, a zero length
5185 * talloc buffer will be alloced. dst->vb_octets
5186 * will *NOT* be NULL. You should use the length
5187 * field of the box to determine if any value
5188 * is assigned.
5189 * @param[in] tainted Whether the value came from a trusted source.
5190 * @return
5191 * - 0 on success.
5192 * - -1 on failure.
5193 */
5194int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
5195 uint8_t const *src, size_t len, bool tainted)
5196{
5197 uint8_t *bin;
5198
5199 if (unlikely((len > 0) && !src)) {
5200 fr_strerror_printf("Invalid arguments to %s. Len > 0 (%zu) but src was NULL",
5201 __FUNCTION__, len);
5202 return -1;
5203 }
5204
5205 bin = talloc_memdup(ctx, src, len);
5206 if (!bin) {
5207 fr_strerror_const("Failed allocating octets buffer");
5208 return -1;
5209 }
5210 talloc_set_type(bin, uint8_t);
5211
5212 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
5213 dst->vb_octets = bin;
5214 dst->vb_length = len;
5215
5216 return 0;
5217}
5218
5219int fr_value_box_memdup_dbuff(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
5220 fr_dbuff_t *dbuff, size_t len, bool tainted)
5221{
5222 uint8_t *bin;
5223
5224 bin = talloc_size(ctx, len);
5225 if (!bin) {
5226 fr_strerror_printf("Failed allocating octets buffer");
5227 return -1;
5228 }
5229
5230 if (fr_dbuff_out_memcpy(bin, dbuff, len) < (ssize_t) len) {
5231 talloc_free(bin);
5232 return -1;
5233 }
5234 talloc_set_type(bin, uint8_t);
5235
5236 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
5237 dst->vb_octets = bin;
5238 dst->vb_length = len;
5239
5240 return 0;
5241}
5242
5243/** Copy a talloced buffer to a fr_value_box_t
5244 *
5245 * Copy a buffer containing binary data, setting fields in the dst value box appropriately.
5246 *
5247 * @param[in] ctx to allocate any new buffers in.
5248 * @param[in] dst to assign new buffer to.
5249 * @param[in] enumv Aliases for values.
5250 * @param[in] src a buffer.
5251 * @param[in] tainted Whether the value came from a trusted source.
5252 * @return
5253 * - 0 on success.
5254 * - -1 on failure.
5255 */
5256int fr_value_box_memdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
5257 uint8_t const *src, bool tainted)
5258{
5260
5261 return fr_value_box_memdup(ctx, dst, enumv, src, talloc_array_length(src), tainted);
5262}
5263
5264/** Assign a buffer to a box, but don't copy it
5265 *
5266 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
5267 *
5268 * Caller should set dst->taint = true, where the value was acquired from an untrusted source.
5269 *
5270 * @note Will free any exiting buffers associated with the value box.
5271 *
5272 * @param[in] dst to assign buffer to.
5273 * @param[in] enumv Aliases for values.
5274 * @param[in] src a talloced buffer.
5275 * @param[in] len of buffer.
5276 * @param[in] tainted Whether the value came from a trusted source.
5277 */
5279 uint8_t const *src, size_t len, bool tainted)
5280{
5281 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
5282 dst->vb_octets = src;
5283 dst->vb_length = len;
5284}
5285
5286/** Assign a talloced buffer to a box, but don't copy it
5287 *
5288 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
5289 *
5290 * @param[in] ctx to allocate any new buffers in.
5291 * @param[in] dst to assign buffer to.
5292 * @param[in] enumv Aliases for values.
5293 * @param[in] src a talloced buffer.
5294 * @param[in] tainted Whether the value came from a trusted source.
5295 */
5297 uint8_t const *src, bool tainted)
5298{
5300
5301 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
5302 dst->vb_octets = ctx ? talloc_reference(ctx, src) : src;
5303 dst->vb_length = talloc_array_length(src);
5304}
5305
5306/*
5307 * Assign a cursor to the data type.
5308 */
5310{
5312
5313 fr_value_box_init(dst, type, NULL, false);
5314 dst->vb_cursor = cursor;
5315 dst->vb_cursor_name = name;
5316}
5317
5318
5319/** Assign a void pointer to a box
5320 *
5321 * @param[in] dst to assign void pointer to.
5322 * @param[in] ptr to assign.
5323 */
5325{
5326 fr_value_box_init(dst, FR_TYPE_VOID, NULL, false);
5327 dst->vb_void = UNCONST(void *, ptr);
5328}
5329
5331{
5333
5334 /*
5335 * If the DA points to a root (e.g. OID-Tree), then use that.
5336 *
5337 * Otherwise if it doesn't have ENUMs defined, then point it at the dict root.
5338 *
5339 * If it does have enums, then the enumv is itself.
5340 */
5342 if (ext) {
5344 fr_assert(!da->flags.has_value);
5345
5346 return ext->ref;
5347 }
5348
5349 if (!da->flags.has_value) {
5350 return fr_dict_root(da->dict);
5351 }
5352
5353 return da;
5354}
5355
5357{
5358 fr_value_box_init(dst, FR_TYPE_ATTR, NULL, false);
5359 dst->vb_attr = da;
5360
5361 dst->enumv = fr_value_box_attr_enumv(da);
5362}
5363
5364/** Increment a boxed value
5365 *
5366 * Implements safe integer overflow.
5367 *
5368 * @param[in] vb to increment.
5369 */
5371{
5372 switch (vb->type) {
5373 case FR_TYPE_UINT8:
5374 vb->vb_uint8 = vb->vb_uint8 == UINT8_MAX ? 0 : vb->vb_uint8 + 1;
5375 return;
5376
5377 case FR_TYPE_UINT16:
5378 vb->vb_uint16 = vb->vb_uint16 == UINT16_MAX ? 0 : vb->vb_uint16 + 1;
5379 return;
5380
5381 case FR_TYPE_UINT32:
5382 vb->vb_uint32 = vb->vb_uint32 == UINT32_MAX ? 0 : vb->vb_uint32 + 1;
5383 return;
5384
5385 case FR_TYPE_UINT64:
5386 vb->vb_uint64 = vb->vb_uint64 == UINT64_MAX ? 0 : vb->vb_uint64 + 1;
5387 return;
5388
5389 case FR_TYPE_INT8:
5390 vb->vb_int8 = vb->vb_int8 == INT8_MAX ? INT8_MIN : vb->vb_int8 + 1;
5391 return;
5392
5393 case FR_TYPE_INT16:
5394 vb->vb_int16 = vb->vb_int16 == INT16_MAX ? INT16_MIN : vb->vb_int16 + 1;
5395 return;
5396
5397 case FR_TYPE_INT32:
5398 vb->vb_int32 = vb->vb_int32 == INT32_MAX ? INT32_MIN : vb->vb_int32 + 1;
5399 return;
5400
5401 case FR_TYPE_INT64:
5402 vb->vb_int64 = vb->vb_int64 == INT64_MAX ? INT64_MIN : vb->vb_int64 + 1;
5403 return;
5404
5405 default:
5406 fr_assert_fail(NULL);
5407 return;
5408 }
5409}
5410
5411/** Convert integer encoded as string to a fr_value_box_t type
5412 *
5413 * @param[out] dst where to write parsed value.
5414 * @param[in] dst_type type of integer to convert string to.
5415 * @param[in] dst_enumv Enumeration values.
5416 * @param[in] in String to convert to integer.
5417 * @param[in] rules for parsing string.
5418 * @param[in] tainted Whether the value came from a trusted source.
5419 * @return
5420 * - >= 0 on success (number of bytes parsed).
5421 * - < 0 on error (where the parse error occurred).
5422 */
5423static inline CC_HINT(always_inline)
5425 fr_dict_attr_t const *dst_enumv,
5426 fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules, bool tainted)
5427{
5428 fr_sbuff_t our_in = FR_SBUFF(in);
5429 fr_sbuff_err_t err;
5430
5431 fr_value_box_init(dst, dst_type, dst_enumv, tainted);
5432
5433 switch (dst_type) {
5434 case FR_TYPE_UINT8:
5435 err = fr_sbuff_out(&dst->vb_uint8, &our_in);
5436 break;
5437
5438 case FR_TYPE_UINT16:
5439 err = fr_sbuff_out(&dst->vb_uint16, &our_in);
5440 break;
5441
5442 case FR_TYPE_UINT32:
5443 err = fr_sbuff_out(&dst->vb_uint32, &our_in);
5444 break;
5445
5446 case FR_TYPE_UINT64:
5447 err = fr_sbuff_out(&dst->vb_uint64, &our_in);
5448 break;
5449
5450 case FR_TYPE_INT8:
5451 err = fr_sbuff_out(&dst->vb_int8, &our_in);
5452 break;
5453
5454 case FR_TYPE_INT16:
5455 err = fr_sbuff_out(&dst->vb_int16, &our_in);
5456 break;
5457
5458 case FR_TYPE_INT32:
5459 err = fr_sbuff_out(&dst->vb_int32, &our_in);
5460 break;
5461
5462 case FR_TYPE_INT64:
5463 err = fr_sbuff_out(&dst->vb_int64, &our_in);
5464 break;
5465
5466 case FR_TYPE_SIZE:
5467 err = fr_sbuff_out(&dst->vb_size, &our_in);
5468 break;
5469
5470 case FR_TYPE_FLOAT32:
5471 err = fr_sbuff_out(&dst->vb_float32, &our_in);
5472 break;
5473
5474 case FR_TYPE_FLOAT64:
5475 err = fr_sbuff_out(&dst->vb_float64, &our_in);
5476 break;
5477
5478 default:
5479 fr_assert_fail(NULL);
5480 return -1;
5481 }
5482
5483 if (err < 0) {
5484 /*
5485 * If an enumeration attribute is provided and we
5486 * don't find an integer, assume this is an enumv
5487 * lookup fail, and produce a better error.
5488 */
5489 if (dst_enumv && dst_enumv->flags.has_value && (err == FR_SBUFF_ERR_NOT_FOUND)) {
5490 fr_sbuff_adv_until(&our_in, SIZE_MAX, rules->terminals,
5491 rules->escapes ? rules->escapes->chr : '\0');
5492
5493 fr_strerror_printf("Invalid enumeration value \"%pV\" for attribute %s",
5495 dst_enumv->name);
5496 return -1;
5497 }
5498
5499 if (err == FR_SBUFF_ERR_NOT_FOUND) {
5500 fr_strerror_printf("Failed parsing string as type '%s'",
5501 fr_type_to_str(dst_type));
5502 } else {
5503 fr_sbuff_err_to_strerror(err);
5504 }
5505 FR_SBUFF_ERROR_RETURN(&our_in);
5506 }
5507
5508 FR_SBUFF_SET_RETURN(in, &our_in);
5509}
5510
5511/** Convert string value to a fr_value_box_t type
5512 *
5513 * @param[in] ctx to alloc strings in.
5514 * @param[out] dst where to write parsed value.
5515 * @param[in,out] dst_type of value data to create/dst_type of value created.
5516 * @param[in] dst_enumv fr_dict_attr_t with string names for uint32 values.
5517 * @param[in] in sbuff to read data from.
5518 * @param[in] rules unescape and termination rules.
5519 * @return
5520 * - >0 on success.
5521 * - <= 0 on parse error.
5522 */
5524 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
5525 fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules)
5526{
5527 static fr_sbuff_parse_rules_t default_rules;
5528 fr_sbuff_t *unescaped = NULL;
5529 fr_sbuff_t our_in = FR_SBUFF(in);
5530 fr_ipaddr_t addr;
5531 fr_slen_t slen;
5532 char buffer[256];
5533
5534 if (!rules) rules = &default_rules;
5535
5537 fr_value_box_init(dst, dst_type, NULL, false);
5538
5539 /*
5540 * Lookup any names before continuing
5541 */
5542 if (dst_enumv && dst_enumv->flags.has_value && (dst_type != FR_TYPE_ATTR)) {
5543 size_t name_len;
5544 fr_dict_enum_value_t const *enumv;
5545
5546 /*
5547 * @todo - allow enum names for IPv6 addresses and prefixes. See also
5548 * tmpl_afrom_enum().
5549 */
5550 (void) fr_sbuff_adv_past_str_literal(&our_in, "::");
5551
5552 /*
5553 * If there is no escaping, then we ignore the terminals. The list of allowed characters
5554 * in enum names will ensure that the parsing doesn't go too far. i.e. to '\r', '\n'. '}', etc.
5555 *
5556 * The reason is that the list of terminals may include things like '-', which is also a
5557 * valid character in enum names. We don't want to parse "Framed-User" as "Framed - User".
5558 */
5559 if (!rules->escapes) {
5560 size_t len;
5562
5563 fr_sbuff_marker(&m, &our_in);
5564
5567 fr_sbuff_set(&our_in, &m);
5568 fr_sbuff_marker_release(&m);
5569
5570 if (!len) goto parse; /* Zero length name can't match enum */
5571
5572 enumv = fr_dict_enum_by_name(dst_enumv, fr_sbuff_current(&our_in), len);
5573 if (!enumv) {
5574 goto parse; /* No enumeration matches escaped string */
5575 }
5576
5577 (void) fr_sbuff_advance(&our_in, len);
5578 goto cast_enum;
5579 }
5580
5581 /*
5582 * Create a thread-local extensible buffer to
5583 * store unescaped data.
5584 *
5585 * This is created once per-thread (the first time
5586 * this function is called), and freed when the
5587 * thread exits.
5588 */
5589 FR_SBUFF_TALLOC_THREAD_LOCAL(&unescaped, 256, 4096);
5590
5591 /*
5592 * This function only does escaping until a terminal character, such as '-'. So
5593 * Framed-User will get parsed as "Framed - User".
5594 *
5595 * Pretty much no other enum has this problem. For Service-Type, it defines "Framed" ss
5596 * an equivalent name to "Framed-User". The parser sees "Framed-User", stops at the '-',
5597 * and then finds the enum named "Framed". It then returns the trailing "-User" as
5598 * something more to parse.
5599 *
5600 * As a result, when the user passes in "Framed-User", the output is "Framed-User -
5601 * User", which is more than a bit surprising.
5602 */
5603 if (fr_sbuff_out_unescape_until(&name_len, unescaped, &our_in, SIZE_MAX,
5604 rules->terminals, rules->escapes) < 0) {
5605 fr_strerror_const("Failed reading enumeration name");
5606 FR_SBUFF_ERROR_RETURN(&our_in);
5607 }
5608 if (!name_len) {
5609 fr_sbuff_set_to_start(&our_in);
5610 goto parse; /* Zero length name can't match enum */
5611 }
5612
5613 enumv = fr_dict_enum_by_name(dst_enumv, fr_sbuff_start(unescaped), fr_sbuff_used(unescaped));
5614 if (!enumv) {
5615 fr_sbuff_set_to_start(&our_in);
5616 goto parse; /* No enumeration matches escaped string */
5617 }
5618
5619 cast_enum:
5620 /*
5621 * dst_type may not match enumv type
5622 */
5623 if (fr_value_box_cast(ctx, dst, dst_type, dst_enumv, enumv->value) < 0) return -1;
5624
5625 FR_SBUFF_SET_RETURN(in, &our_in);
5626 }
5627
5628parse:
5629 /*
5630 * It's a variable ret src->dst_type so we just alloc a new buffer
5631 * of size len and copy.
5632 */
5633 switch (dst_type) {
5634 case FR_TYPE_STRING:
5635 /*
5636 * We've not unescaped the string yet, produce an unescaped version
5637 */
5638 if (!dst_enumv || !unescaped) {
5639 char *buff;
5640
5641 if (unlikely(fr_sbuff_out_aunescape_until(ctx, &buff, NULL, &our_in, SIZE_MAX,
5642 rules->terminals, rules->escapes) < 0)) {
5643 return -1;
5644 }
5645 fr_value_box_bstrdup_buffer_shallow(NULL, dst, dst_enumv, buff, false);
5646 /*
5647 * We already have an unescaped version, just use that
5648 */
5649 } else {
5650 fr_value_box_bstrndup(ctx, dst, dst_enumv,
5651 fr_sbuff_start(unescaped), fr_sbuff_used(unescaped), false);
5652 }
5653 FR_SBUFF_SET_RETURN(in, &our_in);
5654
5655 /* raw octets: 0x01020304... */
5656 case FR_TYPE_OCTETS:
5657 {
5658 fr_sbuff_marker_t hex_start;
5659 size_t hex_len;
5660 uint8_t *bin_buff;
5661
5662 /*
5663 * If there's escape sequences that need to be processed
5664 * or the string doesn't start with 0x, then assume this
5665 * is literal data, not hex encoded data.
5666 */
5667 if (rules->escapes || !fr_sbuff_adv_past_strcase_literal(&our_in, "0x")) {
5668 if (!dst_enumv || !unescaped) {
5669 char *buff = NULL;
5670 uint8_t *bin;
5671 size_t len;
5672
5673 if (fr_sbuff_extend(&our_in)) {
5674 if (fr_sbuff_out_aunescape_until(ctx, &buff, &len, &our_in, SIZE_MAX,
5675 rules->terminals, rules->escapes) < 0) {
5676 return -1;
5677 }
5678
5679 if (len == 0) {
5681 goto zero;
5682 }
5683
5684 /*
5685 * Trim off the trailing '\0', and change the data type.
5686 */
5688 if (unlikely(!bin)) {
5689 fr_strerror_const("Failed trimming string buffer");
5691 return -1;
5692 }
5693
5694 /*
5695 * Input data is zero
5696 *
5697 * talloc realloc will refuse to realloc to
5698 * a zero length buffer. This is probably
5699 * a bug, because we can create zero length
5700 * arrays normally
5701 */
5702 } else {
5703 zero:
5704 bin = talloc_zero_array(ctx, uint8_t, 0);
5705 }
5706
5707 fr_value_box_memdup_buffer_shallow(NULL, dst, dst_enumv, bin, false);
5708 /*
5709 * We already have an unescaped version, just use that
5710 */
5711 } else {
5712 fr_value_box_memdup(ctx, dst, dst_enumv,
5713 (uint8_t *)fr_sbuff_start(unescaped),
5714 fr_sbuff_used(unescaped), false);
5715 }
5716 FR_SBUFF_SET_RETURN(in, &our_in);
5717 }
5718
5719 fr_sbuff_marker(&hex_start, &our_in); /* Record where the hexits start */
5720
5721 /*
5722 * Find the end of the hex sequence.
5723 *
5724 * We don't technically need to do this, fr_base16_decode
5725 * will find the end on its own.
5726 *
5727 * We do this so we can alloc the correct sized
5728 * output buffer.
5729 */
5730 hex_len = fr_sbuff_adv_past_allowed(&our_in, SIZE_MAX, sbuff_char_class_hex, rules->terminals);
5731 if (hex_len == 0) {
5732 if (fr_value_box_memdup(ctx, dst, dst_enumv, (uint8_t[]){ 0x00 }, 0, false) < 0) return -1;
5733 FR_SBUFF_SET_RETURN(in, &our_in);
5734 }
5735
5736 if ((hex_len & 0x01) != 0) {
5737 fr_strerror_printf("Length of hex string is not even, got %zu bytes", hex_len);
5738 FR_SBUFF_ERROR_RETURN(&our_in);
5739 }
5740
5741 /*
5742 * Pre-allocate the bin buff and initialise the box
5743 */
5744 if (fr_value_box_mem_alloc(ctx, &bin_buff, dst, dst_enumv, (hex_len >> 1), false) < 0) return -1;
5745
5746 /*
5747 * Reset to the start of the hex string
5748 */
5749 fr_sbuff_set(&our_in, &hex_start);
5750
5751 if (unlikely(fr_base16_decode(NULL, &FR_DBUFF_TMP(bin_buff, hex_len), &our_in, false) < 0)) {
5752 talloc_free(bin_buff);
5753 FR_SBUFF_ERROR_RETURN(&our_in);
5754 }
5755
5756 FR_SBUFF_SET_RETURN(in, &our_in);
5757 }
5758
5759 case FR_TYPE_IPV4_ADDR:
5760 {
5761 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5762 if (!name_len) goto empty_is_invalid;
5763
5764 if (fr_inet_pton4(&addr, fr_sbuff_current(in), name_len,
5765 fr_hostname_lookups, false, true) < 0) return -1;
5766
5767 /*
5768 * We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
5769 * print them this way.
5770 */
5771 if (addr.prefix != 32) {
5772 fail_ipv4_prefix:
5773 fr_strerror_printf("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted "
5774 "for non-prefix types", addr.prefix);
5775 return -1;
5776 }
5777
5778 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5779 }
5780 goto finish;
5781
5783 {
5784 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5785 if (!name_len) goto empty_is_invalid;
5786
5787 if (fr_inet_pton4(&dst->vb_ip, fr_sbuff_current(in), name_len,
5788 fr_hostname_lookups, false, true) < 0) return -1;
5789 }
5790 goto finish;
5791
5792 case FR_TYPE_IPV6_ADDR:
5793 {
5794 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5795 if (!name_len) goto empty_is_invalid;
5796
5797 /*
5798 * Parse scope, too.
5799 */
5800 if (fr_sbuff_next_if_char(&our_in, '%')) {
5801 name_len += fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_uint, rules->terminals);
5802 }
5803
5804 if (fr_inet_pton6(&addr, fr_sbuff_current(in), name_len,
5805 fr_hostname_lookups, false, true) < 0) return -1;
5806
5807 /*
5808 * We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
5809 * print them this way.
5810 */
5811 if (addr.prefix != 128) {
5812 fail_ipv6_prefix:
5813 fr_strerror_printf("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted "
5814 "for non-prefix types", addr.prefix);
5815 return -1;
5816 }
5817
5818 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5819 }
5820 goto finish;
5821
5823 {
5824 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5825 if (!name_len) goto empty_is_invalid;
5826
5827 if (fr_inet_pton6(&dst->vb_ip, fr_sbuff_current(in), name_len,
5828 fr_hostname_lookups, false, true) < 0) return -1;
5829 }
5830 goto finish;
5831
5833 {
5834 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5835 if (!name_len) goto empty_is_invalid;
5836
5837 /*
5838 * Parse scope, too.
5839 */
5840 if (fr_sbuff_next_if_char(&our_in, '%')) {
5841 name_len += fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_uint, rules->terminals);
5842 }
5843
5844 if (fr_inet_pton(&addr, fr_sbuff_current(in), name_len, AF_UNSPEC,
5845 fr_hostname_lookups, true) < 0) return -1;
5846
5847 if ((addr.af == AF_INET) && (addr.prefix != 32)) {
5848 goto fail_ipv4_prefix;
5849 }
5850
5851 if ((addr.af == AF_INET6) && (addr.prefix != 128)) {
5852 goto fail_ipv6_prefix;
5853 }
5854
5855 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5856 }
5857 goto finish;
5858
5860 {
5861 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5862 if (!name_len) goto empty_is_invalid;
5863
5864 if (fr_inet_pton(&dst->vb_ip, fr_sbuff_current(in), name_len, AF_UNSPEC,
5865 fr_hostname_lookups, true) < 0) return -1;
5866 }
5867 goto finish;
5868
5869 case FR_TYPE_UINT8:
5870 case FR_TYPE_UINT16:
5871 case FR_TYPE_UINT32:
5872 case FR_TYPE_UINT64:
5873 case FR_TYPE_INT8:
5874 case FR_TYPE_INT16:
5875 case FR_TYPE_INT32:
5876 case FR_TYPE_INT64:
5877 case FR_TYPE_FLOAT32:
5878 case FR_TYPE_FLOAT64:
5879 return fr_value_box_from_numeric_substr(dst, dst_type, dst_enumv, in, rules, false);
5880
5881 case FR_TYPE_SIZE:
5882 if (fr_size_from_str(&dst->datum.size, &our_in) < 0) return -1;
5883 goto finish;
5884
5885 case FR_TYPE_BOOL:
5886 {
5887 fr_sbuff_t bool_in = FR_SBUFF(in);
5888
5889 fr_value_box_init(dst, dst_type, dst_enumv, false);
5890
5891 /*
5892 * Quoted boolean values are "yes", "no", "true", "false"
5893 */
5894 if (fr_sbuff_out(&dst->vb_bool, &bool_in) >= 0) FR_SBUFF_SET_RETURN(in, &bool_in);
5895
5896 /*
5897 * For barewords we also allow 0 for false and any other
5898 * integer value for true.
5899 */
5900 if (!rules->escapes) {
5901 int64_t stmp;
5902 uint64_t utmp;
5903
5904 if (fr_sbuff_out(&stmp, &bool_in) >= 0) {
5905 dst->vb_bool = (stmp != 0);
5906 FR_SBUFF_SET_RETURN(in, &bool_in);
5907 }
5908
5909 if (fr_sbuff_out(&utmp, &bool_in) >= 0) {
5910 dst->vb_bool = (utmp != 0);
5911 FR_SBUFF_SET_RETURN(in, &bool_in);
5912 }
5913 }
5914
5915 fr_strerror_const("Invalid boolean value. Accepted values are "
5916 "\"yes\", \"no\", \"true\", \"false\" or any unquoted integer");
5917
5918 FR_SBUFF_ERROR_RETURN(&bool_in);
5919 }
5920
5921 case FR_TYPE_ETHERNET:
5922 {
5923 uint64_t num;
5924 fr_ethernet_t ether;
5925 fr_dbuff_t dbuff;
5926 fr_sbuff_err_t err;
5927
5928 fr_dbuff_init(&dbuff, ether.addr, sizeof(ether.addr));
5929
5930 /*
5931 * Convert things which are obviously integers to Ethernet addresses
5932 *
5933 * We assume the number is the decimal
5934 * representation of the ethernet address.
5935 * i.e. the ethernet address converted to a
5936 * number, and printed.
5937 *
5938 * The string gets converted to a network-order
5939 * 8-byte number, and then the lower bytes of
5940 * that get copied to the ethernet address.
5941 *
5942 * Note: We need to check for a terminal sequence
5943 * after the number, else we may just end up
5944 * parsing the first hexit and returning.
5945 *
5946 * i.e. 1c:00:00:00:00 -> 1
5947 */
5948 if ((fr_sbuff_out(&num, &our_in) >= 0) && fr_sbuff_is_terminal(&our_in, rules->terminals)) {
5949 num = htonll(num);
5950
5951 FR_DBUFF_IN_MEMCPY_RETURN(&dbuff, ((uint8_t *) &num) + 2, sizeof(dst->vb_ether));
5952 fr_value_box_ethernet_addr(dst, dst_enumv, &ether, false);
5953
5954 FR_SBUFF_SET_RETURN(in, &our_in);
5955 }
5956
5957 fr_sbuff_set_to_start(&our_in);
5958
5959 fr_base16_decode(&err, &dbuff, &our_in, true);
5960 if (err != FR_SBUFF_OK) {
5961 ether_error:
5962 fr_sbuff_err_to_strerror(err);
5963 FR_SBUFF_ERROR_RETURN(&our_in);
5964 }
5965
5966 if (!fr_sbuff_next_if_char(&our_in, ':')) {
5967 ether_sep_error:
5968 fr_strerror_const("Missing separator, expected ':'");
5969 FR_SBUFF_ERROR_RETURN(&our_in);
5970 }
5971
5972 fr_base16_decode(&err, &dbuff, &our_in, true);
5973 if (err != FR_SBUFF_OK) goto ether_error;
5974
5975 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5976
5977 fr_base16_decode(&err, &dbuff, &our_in, true);
5978 if (err != FR_SBUFF_OK) goto ether_error;
5979
5980 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5981
5982 fr_base16_decode(&err, &dbuff, &our_in, true);
5983 if (err != FR_SBUFF_OK) goto ether_error;
5984
5985 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5986
5987 fr_base16_decode(&err, &dbuff, &our_in, true);
5988 if (err != FR_SBUFF_OK) goto ether_error;
5989
5990 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5991
5992 fr_base16_decode(&err, &dbuff, &our_in, true);
5993 if (err != FR_SBUFF_OK) goto ether_error;
5994
5995 fr_value_box_ethernet_addr(dst, dst_enumv, (fr_ethernet_t * const)fr_dbuff_start(&dbuff), false);
5996
5997 FR_SBUFF_SET_RETURN(in, &our_in);
5998 }
5999
6000 case FR_TYPE_TIME_DELTA:
6001 fr_value_box_init(dst, FR_TYPE_TIME_DELTA, dst_enumv, false);
6002
6003 slen = fr_time_delta_from_substr(&dst->datum.time_delta, &our_in,
6004 dst_enumv ? (fr_time_res_t)dst_enumv->flags.flag_time_res : FR_TIME_RES_SEC,
6005 false, rules->terminals);
6006 if (slen < 0) return slen;
6007 if (!slen) {
6008 empty_is_invalid:
6009 fr_strerror_const("Empty input is invalid");
6010 return -1;
6011 }
6012 FR_SBUFF_SET_RETURN(in, &our_in);
6013
6014 case FR_TYPE_NULL:
6015 if (!rules->escapes && fr_sbuff_adv_past_str_literal(&our_in, "NULL")) {
6016 fr_value_box_init(dst, dst_type, dst_enumv, false);
6017 FR_SBUFF_SET_RETURN(in, &our_in);
6018 }
6019
6020 fr_strerror_const("Unexpected value for data type NULL");
6021 return -1;
6022
6023 case FR_TYPE_ATTR:
6024 if (!dst_enumv) {
6025 fr_strerror_const("No dictionary passed for data type 'attr'");
6026 return -1;
6027 }
6028
6029 /*
6030 * @todo - have attributes of FR_TYPE_ATTR also
6031 * carry a ref to where their values are taken from.
6032 */
6033 if (dst_enumv->type == FR_TYPE_ATTR) {
6034 dst_enumv = fr_value_box_attr_enumv(dst_enumv);
6035
6036 } else if (dst_enumv->type != FR_TYPE_TLV) {
6037 fr_strerror_printf("Can only start from data type 'tlv' for data type 'attribute', and not from %s", dst_enumv->name);
6038 return -1;
6039 }
6040
6041 fr_value_box_init(dst, dst_type, dst_enumv, false);
6042
6043 (void) fr_sbuff_adv_past_str_literal(&our_in, "::");
6044
6045 /*
6046 * Allow '@' references in values.
6047 */
6048 if (fr_sbuff_is_char(&our_in, '@')) {
6049 size_t len;
6051
6052 fr_sbuff_marker(&m, &our_in);
6053 fr_sbuff_advance(&our_in, 1); /* '@' is not an allowed character for dictionary names */
6054
6057 fr_sbuff_set(&our_in, &m);
6058 fr_sbuff_marker_release(&m);
6059
6060 len++; /* account for '@' */
6061
6062 /*
6063 * This function needs the '@'.
6064 */
6065 if (fr_dict_protocol_reference(&dst->vb_attr, fr_dict_root(dst_enumv->dict), &FR_SBUFF_IN(fr_sbuff_current(&our_in), len)) < 0) {
6066 return -1;
6067 }
6068
6069 if (!dst->vb_attr) {
6070 fr_strerror_printf("Failed to find attribute reference %.*s", (int) len, fr_sbuff_current(&our_in));
6071 return -1;
6072 }
6073
6074 fr_assert(dst->vb_attr != NULL);
6075
6076 if (dst->vb_attr->dict != dst_enumv->dict) {
6077 fr_strerror_const("Type 'attribute' cannot reference a different protocol");
6078 return -1;
6079 }
6080
6081 fr_sbuff_advance(&our_in, len);
6082 FR_SBUFF_SET_RETURN(in, &our_in);
6083
6084 } else {
6085 fr_dict_attr_t const *da;
6086
6087 fr_assert(dst_enumv != NULL);
6088
6089 slen = fr_dict_attr_by_oid_substr(NULL, &dst->vb_attr, dst_enumv, &our_in, rules->terminals);
6090 if (slen > 0) {
6091 fr_assert(dst->vb_attr != NULL);
6092
6093 if (!fr_sbuff_next_if_char(&our_in, '.')) {
6094 FR_SBUFF_SET_RETURN(in, &our_in);
6095 }
6096
6097 /*
6098 * The next bit MUST be an unknown attribute.
6099 */
6100 }
6101
6102 if (!fr_sbuff_is_digit(&our_in)) {
6103 invalid_attr:
6104 fr_strerror_printf_push("Failed to find the attribute in %s", dst_enumv->name);
6105 return -2;
6106 }
6107
6108 slen = fr_dict_attr_unknown_afrom_oid_substr(ctx, &da, dst->vb_attr, &our_in, FR_TYPE_OCTETS);
6109 if (slen <= 0) goto invalid_attr;
6110
6111 dst->vb_attr = da;
6112 FR_SBUFF_SET_RETURN(in, &our_in);
6113 }
6114
6115 /*
6116 * Dealt with below
6117 */
6118 default:
6119 break;
6120 }
6121
6122 /*
6123 * We may have terminals. If so, respect them.
6124 */
6125 if (rules && rules->terminals) {
6126 size_t len;
6127 fr_sbuff_err_t sberr;
6128
6129 sberr = fr_sbuff_out_unescape_until(&len, &FR_SBUFF_OUT(buffer, sizeof(buffer)), &our_in, SIZE_MAX,
6130 rules->terminals, rules->escapes);
6131 if (sberr < 0) {
6132 fr_strerror_printf("Failed reading value: %s", fr_sbuff_err_to_str(sberr));
6133 return -1;
6134 }
6135
6136 buffer[len] = '\0';
6137
6138 } else {
6139 /*
6140 * It's a fixed size src->dst_type, copy to a temporary buffer and
6141 * \0 terminate.
6142 *
6143 * @todo - note that this brute-force copy means that the input sbuff
6144 * is NOT advanced, and this function will return 0, even though it parsed data!
6145 */
6146 if (fr_sbuff_remaining(in) >= sizeof(buffer)) {
6147 fr_strerror_const("Temporary buffer too small");
6148 return -1;
6149 }
6150
6152 buffer[fr_sbuff_remaining(in)] = '\0';
6153 }
6154
6155 switch (dst_type) {
6156 case FR_TYPE_DATE:
6157 {
6158 if (dst_enumv) {
6159 if (fr_unix_time_from_str(&dst->vb_date, buffer, (fr_time_res_t)dst_enumv->flags.flag_time_res) < 0) return -1;
6160 } else {
6161 if (fr_unix_time_from_str(&dst->vb_date, buffer, FR_TIME_RES_SEC) < 0) return -1;
6162 }
6163
6164 dst->enumv = dst_enumv;
6165 }
6166 break;
6167
6168 case FR_TYPE_IFID:
6169 if (fr_inet_ifid_pton((void *) dst->vb_ifid, buffer) == NULL) {
6170 fr_strerror_printf("Failed to parse interface-id string \"%s\"", buffer);
6171 return -1;
6172 }
6173 break;
6174
6175 default:
6176 fr_strerror_printf("Cannot parse input as data type %s", fr_type_to_str(dst_type));
6177 return -1;
6178 }
6179
6180finish:
6181 dst->type = dst_type;
6182 dst->tainted = false;
6184
6185 /*
6186 * Fixup enumvs
6187 */
6188 dst->enumv = dst_enumv;
6189 fr_value_box_list_entry_init(dst);
6190 VALUE_BOX_VERIFY(dst);
6191
6192 FR_SBUFF_SET_RETURN(in, &our_in);
6193}
6194
6196 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
6197 char const *in, size_t inlen,
6198 fr_sbuff_unescape_rules_t const *erules)
6199{
6200 fr_slen_t slen;
6201 fr_sbuff_parse_rules_t prules = { .escapes = erules };
6202
6203 slen = fr_value_box_from_substr(ctx, dst, dst_type, dst_enumv, &FR_SBUFF_IN(in, inlen), &prules);
6204 if (slen <= 0) return slen;
6205
6206 if (slen != (ssize_t)inlen) {
6207 fr_strerror_printf("Failed parsing '%s'. %zu bytes of trailing data after string value \"%pV\"",
6208 fr_type_to_str(dst_type),
6209 inlen - slen,
6210 fr_box_strvalue_len(in + slen, inlen - slen));
6211 return (slen - inlen) - 1;
6212 }
6213
6214 return slen;
6215}
6216
6217/** Print one boxed value to a string
6218 *
6219 * This function should primarily be used when a #fr_value_box_t is being
6220 * serialized in some non-standard way, i.e. as a value for a field
6221 * in a database, in all other instances it's better to use
6222 * #fr_value_box_print_quoted.
6223 *
6224 * @note - this function does NOT respect tainting! The escaping rules
6225 * are ONLY for escaping quotation characters, CR, LF, etc.
6226 *
6227 * @param[in] out Where to write the printed string.
6228 * @param[in] data Value box to print.
6229 * @param[in] e_rules To apply to FR_TYPE_STRING types, for escaping quotation characters _only_.
6230 * Is not currently applied to any other box type.
6231 */
6233{
6234 fr_sbuff_t our_out = FR_SBUFF(out);
6235
6236 char buf[1024]; /* Interim buffer to use with poorly behaved printing functions */
6237
6238 if (data->enumv && data->enumv->flags.has_value) {
6239 char const *name;
6240
6242 if (name) {
6243 FR_SBUFF_IN_ESCAPE_BUFFER_RETURN(&our_out, name, NULL);
6244 goto done;
6245 }
6246 }
6247
6248 switch (data->type) {
6249 case FR_TYPE_STRING:
6250 if (data->vb_length) FR_SBUFF_IN_ESCAPE_RETURN(&our_out,
6251 data->vb_strvalue, data->vb_length, e_rules);
6252 break;
6253
6254 case FR_TYPE_OCTETS:
6255 FR_SBUFF_IN_CHAR_RETURN(&our_out, '0', 'x');
6256 if (data->vb_length) FR_SBUFF_RETURN(fr_base16_encode, &our_out,
6257 &FR_DBUFF_TMP(data->vb_octets, data->vb_length));
6258 break;
6259
6260 /*
6261 * We need to use the proper inet_ntop functions for IP
6262 * addresses, else the output might not match output of
6263 * other functions, which makes testing difficult.
6264 *
6265 * An example is tunneled ipv4 in ipv6 addresses.
6266 */
6267 case FR_TYPE_IPV4_ADDR:
6268 case FR_TYPE_IPV6_ADDR:
6270 if (!fr_inet_ntop(buf, sizeof(buf), &data->vb_ip)) return 0;
6271 FR_SBUFF_IN_STRCPY_RETURN(&our_out, buf);
6272 break;
6273
6277 if (!fr_inet_ntop_prefix(buf, sizeof(buf), &data->vb_ip)) return 0;
6278 FR_SBUFF_IN_STRCPY_RETURN(&our_out, buf);
6279 break;
6280
6281 case FR_TYPE_IFID:
6282 if (!fr_inet_ifid_ntop(buf, sizeof(buf), data->vb_ifid)) return 0;
6283 FR_SBUFF_IN_STRCPY_RETURN(&our_out, buf);
6284 break;
6285
6286 case FR_TYPE_ETHERNET:
6287 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%02x:%02x:%02x:%02x:%02x:%02x",
6288 data->vb_ether[0], data->vb_ether[1],
6289 data->vb_ether[2], data->vb_ether[3],
6290 data->vb_ether[4], data->vb_ether[5]);
6291 break;
6292
6293 case FR_TYPE_BOOL:
6294 FR_SBUFF_IN_STRCPY_RETURN(&our_out, data->vb_uint8 ? "yes" : "no");
6295 break;
6296
6297 case FR_TYPE_UINT8:
6298 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", data->vb_uint8);
6299 break;
6300
6301 case FR_TYPE_UINT16:
6302 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", data->vb_uint16);
6303 break;
6304
6305 case FR_TYPE_UINT32:
6306 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", data->vb_uint32);
6307 break;
6308
6309 case FR_TYPE_UINT64:
6310 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%" PRIu64, data->vb_uint64);
6311 break;
6312
6313 case FR_TYPE_INT8:
6314 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%d", data->vb_int8);
6315 break;
6316
6317 case FR_TYPE_INT16:
6318 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%d", data->vb_int16);
6319 break;
6320
6321 case FR_TYPE_INT32:
6322 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%d", data->vb_int32);
6323 break;
6324
6325 case FR_TYPE_INT64:
6326 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%" PRId64, data->vb_int64);
6327 break;
6328
6329 case FR_TYPE_FLOAT32:
6330 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%f", (double) data->vb_float32);
6331 break;
6332
6333 case FR_TYPE_FLOAT64:
6334 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%g", data->vb_float64);
6335 break;
6336
6337 case FR_TYPE_DATE:
6338 {
6340
6341 if (data->enumv) res = (fr_time_res_t)data->enumv->flags.flag_time_res;
6342
6343 FR_SBUFF_RETURN(fr_unix_time_to_str, &our_out, data->vb_date, res, true);
6344 break;
6345 }
6346
6347 case FR_TYPE_SIZE:
6348 FR_SBUFF_RETURN(fr_size_to_str, &our_out, data->datum.size);
6349 break;
6350
6351 case FR_TYPE_TIME_DELTA:
6352 {
6354 bool is_unsigned = false;
6355
6356 if (data->enumv) {
6357 res = (fr_time_res_t)data->enumv->flags.flag_time_res;
6358 is_unsigned = data->enumv->flags.is_unsigned;
6359 }
6360
6361
6362 FR_SBUFF_RETURN(fr_time_delta_to_str, &our_out, data->vb_time_delta, res, is_unsigned);
6363 }
6364 break;
6365
6366 case FR_TYPE_GROUP:
6367 /*
6368 * If the caller didn't ask to escape binary data
6369 * in 'octets' types, then we force that now.
6370 * Otherwise any 'octets' type which is buried
6371 * inside of a 'group' will get copied verbatim
6372 * from input to output, with no escaping!
6373 */
6374 if (!e_rules || (!e_rules->do_oct && !e_rules->do_hex)) {
6375 e_rules = &fr_value_escape_double;
6376 }
6377
6378 /*
6379 * Represent groups as:
6380 *
6381 * { <value0>, <value1>, { <sub-value0>, <sub-value1>, <sub-valueN> }}
6382 */
6383 FR_SBUFF_IN_CHAR_RETURN(&our_out, '{');
6385 NULL, &our_out, UNCONST(fr_value_box_list_t *, &data->vb_group),
6386 ", ", (sizeof(", ") - 1), e_rules,
6388 FR_SBUFF_IN_CHAR_RETURN(&our_out, '}');
6389 break;
6390
6391 case FR_TYPE_ATTR: {
6392 fr_dict_attr_t const *parent = NULL;
6393 fr_sbuff_t *unescaped = NULL;
6394
6395 FR_SBUFF_IN_CHAR_RETURN(&our_out, ':', ':');
6396
6397 if (!data->enumv) {
6398 fr_strerror_const("Value of type 'attribute' is missing the enum");
6399 return -1;
6400 }
6401
6402 switch (data->enumv->type) {
6403 case FR_TYPE_TLV:
6404 parent = data->enumv;
6405 break;
6406
6407 case FR_TYPE_ATTR: /* will print from the root */
6408 break;
6409
6410 default:
6411 fr_assert_msg(0, "Invalid data type for 'attr' enumv");
6412 break;
6413 }
6414
6415 /*
6416 * No escaping, just dump the name as-is.
6417 */
6418 if (!e_rules) {
6419 FR_DICT_ATTR_OID_PRINT_RETURN(&our_out, parent, data->vb_attr, false);
6420 break;
6421 }
6422
6423 /*
6424 * Escaping, use an intermediate buffer. Because
6425 * we can't pipe sbuffs together.
6426 */
6427 FR_SBUFF_TALLOC_THREAD_LOCAL(&unescaped, 256, 4096);
6428
6429 FR_DICT_ATTR_OID_PRINT_RETURN(unescaped, parent, data->vb_attr, false);
6430
6431 FR_SBUFF_IN_ESCAPE_RETURN(&our_out, fr_sbuff_start(unescaped),
6432 fr_sbuff_used(unescaped), e_rules);
6433 }
6434 break;
6435
6436 case FR_TYPE_NULL:
6437 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "NULL");
6438 break;
6439
6440 /*
6441 * Don't add default here
6442 */
6443 case FR_TYPE_TLV: /* Not a box type */
6444 case FR_TYPE_STRUCT: /* Not a box type */
6445 case FR_TYPE_VSA: /* Not a box type */
6446 case FR_TYPE_VENDOR: /* Not a box type */
6447 case FR_TYPE_UNION: /* Not a box type */
6448 case FR_TYPE_VALUE_BOX:
6449 case FR_TYPE_VOID:
6450 case FR_TYPE_MAX:
6451 (void)fr_cond_assert(0);
6452 return 0;
6453
6456 FR_SBUFF_IN_STRCPY_RETURN(&our_out, data->vb_cursor_name);
6457 break;
6458 }
6459
6460done:
6461 FR_SBUFF_SET_RETURN(out, &our_out);
6462}
6463
6464/** Print one boxed value to a string with quotes (where needed)
6465 *
6466 * @param[in] out Where to write the printed string.
6467 * @param[in] data Value box to print.
6468 * @param[in] quote To apply to FR_TYPE_STRING types.
6469 * Is not currently applied to any
6470 * other box type.
6471 */
6473{
6474 fr_sbuff_t our_out = FR_SBUFF(out);
6475
6476 if (quote == T_BARE_WORD) return fr_value_box_print(out, data, NULL);
6477
6478 switch (data->type) {
6479 case FR_TYPE_QUOTED:
6480 FR_SBUFF_IN_CHAR_RETURN(&our_out, fr_token_quote[quote]);
6482 FR_SBUFF_IN_CHAR_RETURN(&our_out, fr_token_quote[quote]);
6483 break;
6484
6485 default:
6486 return fr_value_box_print(out, data, NULL);
6487 }
6488
6489 FR_SBUFF_SET_RETURN(out, &our_out);
6490}
6491
6492/** Concatenate a list of value boxes together
6493 *
6494 * All boxes will be removed from the list.
6495 *
6496 * @param[out] safety if !NULL, the results of tainted / secret / safe_for will be stored here.
6497 * @param[out] sbuff to write the result of the concatenation to.
6498 * @param[in] list to concatenate.
6499 * @param[in] sep Insert a separator between the values.
6500 * @param[in] sep_len Length of the separator.
6501 * @param[in] e_rules To apply to FR_TYPE_STRING types.
6502 * Is not currently applied to any other box type.
6503 * @param[in] proc_action What to do with the boxes in the list once
6504 * they've been processed.
6505 * @param[in] safe_for if value has this safe_for value, don't apply the escape rules.
6506 * for values which are escaped, mash the safe_for value to this.
6507 * @param[in] flatten If true and we encounter a #FR_TYPE_GROUP,
6508 * we concat the contents of its children together.
6509 * If false, the contents will be cast to #FR_TYPE_STRING.
6510 * @return
6511 * - >=0 the number of bytes written to the sbuff.
6512 * - <0 how many additional bytes we would have needed to
6513 * concat the next box.
6514 */
6516 char const *sep, size_t sep_len, fr_sbuff_escape_rules_t const *e_rules,
6517 fr_value_box_list_action_t proc_action, fr_value_box_safe_for_t safe_for, bool flatten)
6518{
6519 fr_sbuff_t our_sbuff = FR_SBUFF(sbuff);
6520 ssize_t slen;
6521
6522 if (fr_value_box_list_empty(list)) return 0;
6523
6524 fr_value_box_list_foreach(list, vb) {
6525 fr_value_box_safe_for_t box_safe_for = vb->vb_safefor;
6526
6527 switch (vb->type) {
6528 case FR_TYPE_GROUP:
6529 if (!flatten) goto print;
6530 slen = fr_value_box_list_concat_as_string(safety, &our_sbuff, &vb->vb_group,
6531 sep, sep_len, e_rules,
6532 proc_action, safe_for, flatten);
6533 break;
6534
6535 case FR_TYPE_OCTETS:
6536
6537 /*
6538 * Copy the raw string over, if necessary with escaping.
6539 */
6540 if (e_rules && (!fr_value_box_is_safe_for(vb, safe_for) || e_rules->do_oct || e_rules->do_hex)) {
6541 box_safe_for = safe_for;
6542
6543 slen = fr_sbuff_in_escape(&our_sbuff, (char const *)vb->vb_strvalue, vb->vb_length, e_rules);
6544 } else {
6545 slen = fr_sbuff_in_bstrncpy(&our_sbuff, (char const *)vb->vb_strvalue, vb->vb_length);
6546 }
6547 break;
6548
6549 case FR_TYPE_STRING:
6550 if (!fr_value_box_is_safe_for(vb, safe_for) && e_rules) goto print;
6551
6552 slen = fr_sbuff_in_bstrncpy(&our_sbuff, vb->vb_strvalue, vb->vb_length);
6553 break;
6554
6555 case FR_TYPE_NULL: /* Skip null */
6556 continue;
6557
6558 default:
6559 print:
6560 /*
6561 * If we escaped it, set the output safe_for value.
6562 */
6563 if (e_rules) box_safe_for = safe_for;
6564 slen = fr_value_box_print(&our_sbuff, vb, e_rules);
6565 break;
6566 }
6567 if (slen < 0) return slen;
6568
6569 /*
6570 * Add in the separator
6571 */
6572 if (sep && fr_value_box_list_next(list, vb)) {
6573 slen = fr_sbuff_in_bstrncpy(&our_sbuff, sep, sep_len);
6574 if (slen < 0) return slen;
6575 }
6576
6577 /*
6578 * Merge in the safety rules.
6579 */
6580 if (!safety || (vb->type == FR_TYPE_GROUP)) continue;
6581
6582 /*
6583 * We can't call fr_box_safety_merge(), as we may have escaped the input box.
6584 */
6585 if ((safety->safe_for != FR_VALUE_BOX_SAFE_FOR_NONE) &&
6586 (safety->safe_for != box_safe_for)) {
6587 if (safety->safe_for == FR_VALUE_BOX_SAFE_FOR_ANY) {
6588 safety->safe_for = box_safe_for;
6589 } else if (box_safe_for != FR_VALUE_BOX_SAFE_FOR_ANY) {
6591 }
6592 }
6593
6594 safety->secret |= vb->vb_secret;
6595 }
6596
6597 /*
6598 * Free the boxes last so if there's
6599 * an issue concatenating them, everything
6600 * is still in a known state.
6601 */
6602 fr_value_box_list_foreach(list, vb) {
6603 if (vb_should_remove(proc_action)) fr_value_box_list_remove(list, vb);
6604 if (vb_should_free_value(proc_action)) fr_value_box_clear_value(vb);
6605 if (vb_should_free(proc_action)) talloc_free(vb);
6606 }
6607
6608 FR_SBUFF_SET_RETURN(sbuff, &our_sbuff);
6609}
6610
6612
6613/** Concatenate a list of value boxes together
6614 *
6615 * All boxes will be removed from the list.
6616 *
6617 * @param[out] safety if !NULL, the results of tainted / secret / safe_for will be stored here.
6618 * @param[out] dbuff to write the result of the concatenation to.
6619 * @param[in] list to concatenate.
6620 * @param[in] sep Insert a separator between the values.
6621 * @param[in] sep_len Length of the separator.
6622 * @param[in] proc_action What to do with the boxes in the list once
6623 * they've been processed.
6624 * @param[in] flatten If true and we encounter a #FR_TYPE_GROUP,
6625 * we concat the contents of its children together.
6626 * If false, the contents will be cast to #FR_TYPE_OCTETS.
6627 * @return
6628 * - >=0 the number of bytes written to the sbuff.
6629 * - <0 how many additional bytes we would have needed to
6630 * concat the next box.
6631 */
6633 uint8_t const *sep, size_t sep_len,
6634 fr_value_box_list_action_t proc_action, bool flatten)
6635{
6636 fr_dbuff_t our_dbuff = FR_DBUFF(dbuff);
6637 TALLOC_CTX *tmp_ctx = NULL;
6638 ssize_t slen;
6639
6640 if (fr_value_box_list_empty(list)) return 0;
6641
6642 fr_value_box_list_foreach(list, vb) {
6643 switch (vb->type) {
6644 case FR_TYPE_GROUP:
6645 if (!flatten) goto cast;
6646 slen = fr_value_box_list_concat_as_octets(safety, &our_dbuff, &vb->vb_group,
6647 sep, sep_len,
6648 proc_action, flatten);
6649 break;
6650
6651 case FR_TYPE_OCTETS:
6652 slen = fr_dbuff_in_memcpy(&our_dbuff, vb->vb_octets, vb->vb_length);
6653 break;
6654
6655 case FR_TYPE_STRING:
6656 slen = fr_dbuff_in_memcpy(&our_dbuff, (uint8_t const *)vb->vb_strvalue, vb->vb_length);
6657 break;
6658
6659 case FR_TYPE_NULL: /* Skip null */
6660 continue;
6661
6662 default:
6663 cast:
6664 {
6665 fr_value_box_t tmp_vb;
6666
6667 if (!tmp_ctx) tmp_ctx = talloc_pool(NULL, 1024);
6668
6669 /*
6670 * Not equivalent to fr_value_box_to_network
6671 */
6672 if (fr_value_box_cast_to_octets(tmp_ctx, &tmp_vb, FR_TYPE_OCTETS, NULL, vb) < 0) {
6673 slen = -1;
6674 goto error;
6675 }
6676
6677 slen = fr_dbuff_in_memcpy(&our_dbuff, tmp_vb.vb_octets, tmp_vb.vb_length);
6678 fr_value_box_clear_value(&tmp_vb);
6679 break;
6680 }
6681 }
6682
6683 if (slen < 0) {
6684 error:
6685 talloc_free(tmp_ctx);
6686 return slen;
6687 }
6688
6689 if (sep && fr_value_box_list_next(list, vb)) {
6690 slen = fr_dbuff_in_memcpy(&our_dbuff, sep, sep_len);
6691 if (slen < 0) goto error;
6692 }
6693
6694 if (safety) _value_box_safety_merge(safety, &vb->safety);
6695 }
6696
6697 talloc_free(tmp_ctx);
6698
6699 /*
6700 * Free the boxes last so if there's
6701 * an issue concatenating them, everything
6702 * is still in a known state.
6703 */
6704 fr_value_box_list_foreach(list, vb) {
6705 if (vb_should_remove(proc_action)) fr_value_box_list_remove(list, vb);
6706 if (vb_should_free_value(proc_action)) fr_value_box_clear_value(vb);
6707 if (vb_should_free(proc_action)) talloc_free(vb);
6708 }
6709
6710 return fr_dbuff_set(dbuff, &our_dbuff);
6711}
6712
6713/** Concatenate a list of value boxes
6714 *
6715 * @note Will automatically cast all #fr_value_box_t to type specified.
6716 *
6717 * @param[in] ctx to allocate new value buffer in.
6718 * @param[out] out Where to write the resulting box.
6719 * @param[in] list to concatenate together.
6720 * @param[in] type May be #FR_TYPE_STRING or #FR_TYPE_OCTETS, no other types are
6721 * supported.
6722 * @param[in] proc_action What to do with the boxes in the list once
6723 * they've been processed.
6724 * @param[in] flatten If true and we encounter a #FR_TYPE_GROUP,
6725 * we concat the contents of its children together.
6726 * If false, the contents will be cast to the given type.
6727 * @param[in] max_size of the value.
6728 * @return
6729 * - 0 on success.
6730 * - -1 on failure.
6731 */
6733 fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type,
6734 fr_value_box_list_action_t proc_action, bool flatten,
6735 size_t max_size)
6736{
6737 fr_dbuff_t dbuff; /* FR_TYPE_OCTETS */
6738 fr_dbuff_uctx_talloc_t dbuff_tctx;
6739
6740 fr_sbuff_t sbuff; /* FR_TYPE_STRING */
6741 fr_sbuff_uctx_talloc_t sbuff_tctx;
6742
6743 fr_value_box_t *head_vb = fr_value_box_list_head(list);
6744
6745 fr_value_box_entry_t entry;
6746 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 */
6747
6748 if (fr_value_box_list_empty(list)) {
6749 fr_strerror_const("Invalid arguments. List contains no elements");
6750 return -1;
6751 }
6752
6753 /*
6754 * Exit quickly if the list is only one box of the correct type and
6755 * out points at that box.
6756 */
6757 if ((fr_value_box_list_num_elements(list) == 1) && (head_vb == out) && (head_vb->type == type)) return 0;
6758
6759 /*
6760 * The accumulator starts as "safe for anything", the identity for the merge,
6761 * and each box narrows it. The constructor below re-initialises out, so the
6762 * merged safety is applied to out afterwards.
6763 */
6764
6765 switch (type) {
6766 case FR_TYPE_STRING:
6767 if (unlikely(!fr_sbuff_init_talloc(ctx, &sbuff, &sbuff_tctx, 256, max_size))) return -1;
6768 break;
6769
6770 case FR_TYPE_OCTETS:
6771 if (unlikely(!fr_dbuff_init_talloc(ctx, &dbuff, &dbuff_tctx, 256, max_size))) return -1;
6772 break;
6773
6774 default:
6775 fr_strerror_printf("Invalid argument. Can't concatenate boxes to type %s",
6777 return -1;
6778 }
6779
6780 /*
6781 * Merge all siblings into list head.
6782 *
6783 * This is where the first element in the
6784 * list is the output box.
6785 *
6786 * i.e. we want to merge all its siblings
6787 * into it.
6788 */
6789 if (out == head_vb) {
6790 switch (type) {
6791 case FR_TYPE_STRING:
6792 /*
6793 * Head gets dealt with specially as we don't
6794 * want to free it, and we don't want to free
6795 * the buffer associated with it (just yet).
6796 *
6797 * Note that we don't convert 'octets' to a printable string
6798 * here. Doing so breaks the keyword tests.
6799 */
6800 if (fr_value_box_list_concat_as_string(&safety, &sbuff, list,
6801 NULL, 0, NULL,
6803 fr_strerror_printf("Concatenation exceeded max_size (%zu)", max_size);
6804 error:
6805 switch (type) {
6806 case FR_TYPE_STRING:
6807 talloc_free(fr_sbuff_buff(&sbuff));
6808 break;
6809
6810 case FR_TYPE_OCTETS:
6811 talloc_free(fr_dbuff_buff(&dbuff));
6812 break;
6813
6814 default:
6815 break;
6816 }
6817 return -1;
6818 }
6819
6820 /*
6821 * Concat the rest of the children...
6822 */
6823 if (fr_value_box_list_concat_as_string(&safety, &sbuff, list,
6824 NULL, 0, NULL,
6825 proc_action, FR_VALUE_BOX_SAFE_FOR_ANY, flatten) < 0) {
6826 fr_value_box_list_insert_head(list, head_vb);
6827 goto error;
6828 }
6829 (void)fr_sbuff_trim_talloc(&sbuff, SIZE_MAX);
6831 if (fr_value_box_bstrndup(ctx, out, NULL, fr_sbuff_buff(&sbuff), fr_sbuff_used(&sbuff), out->tainted) < 0) goto error;
6832 fr_value_box_safety_set(out, &safety);
6833 break;
6834
6835 case FR_TYPE_OCTETS:
6836 if (fr_value_box_list_concat_as_octets(&safety, &dbuff, list,
6837 NULL, 0,
6838 FR_VALUE_BOX_LIST_REMOVE, flatten) < 0) goto error;
6839
6840 if (fr_value_box_list_concat_as_octets(&safety, &dbuff, list,
6841 NULL, 0,
6842 proc_action, flatten) < 0) {
6843 fr_value_box_list_insert_head(list, head_vb);
6844 goto error;
6845 }
6846 (void)fr_dbuff_trim_talloc(&dbuff, SIZE_MAX);
6848 if (fr_value_box_memdup(ctx, out, NULL, fr_dbuff_buff(&dbuff), fr_dbuff_used(&dbuff), out->tainted) < 0) goto error;
6849 fr_value_box_safety_set(out, &safety);
6850 break;
6851
6852 default:
6853 break;
6854 }
6855
6856 fr_value_box_list_insert_head(list, out);
6857
6858 /*
6859 * Merge all the boxes in the list into
6860 * a single contiguous buffer.
6861 *
6862 * This deals with an unrelated out and list
6863 * and also where list is the children of
6864 * out.
6865 */
6866 } else {
6867 switch (type) {
6868 case FR_TYPE_STRING:
6869 if (fr_value_box_list_concat_as_string(&safety, &sbuff, list,
6870 NULL, 0, NULL,
6871 proc_action, FR_VALUE_BOX_SAFE_FOR_ANY, flatten) < 0) goto error;
6872 (void)fr_sbuff_trim_talloc(&sbuff, SIZE_MAX);
6873
6874 entry = out->entry;
6875 if (fr_value_box_bstrndup(ctx, out, NULL, fr_sbuff_buff(&sbuff), fr_sbuff_used(&sbuff), out->tainted) < 0) goto error;
6876 out->entry = entry;
6877 fr_value_box_safety_set(out, &safety);
6878 break;
6879
6880 case FR_TYPE_OCTETS:
6881 if (fr_value_box_list_concat_as_octets(&safety, &dbuff, list,
6882 NULL, 0,
6883 proc_action, flatten) < 0) goto error;
6884 (void)fr_dbuff_trim_talloc(&dbuff, SIZE_MAX);
6885
6886 entry = out->entry;
6887 if (fr_value_box_memdup(ctx, out, NULL, fr_dbuff_buff(&dbuff), fr_dbuff_used(&dbuff), out->tainted) < 0) goto error;
6888 out->entry = entry;
6889 fr_value_box_safety_set(out, &safety);
6890 break;
6891
6892 default:
6893 break;
6894 }
6895 }
6896
6897 return 0;
6898}
6899
6900/** Escape a single value box in place
6901 *
6902 * @note Applies recursively to the children of group boxes.
6903 *
6904 * @param[in] vb to escape.
6905 * @param[in] escape escape definition to apply to the value box.
6906 * @param[in] uctx user context to pass to the escape function.
6907 * @return
6908 * - 0 on success.
6909 * - -1 on failure.
6910 */
6912{
6913 int ret;
6914
6915 switch (vb->type) {
6916 case FR_TYPE_GROUP:
6917 return fr_value_box_list_escape_in_place(&vb->vb_group, escape, uctx);
6918
6919 case FR_TYPE_NULL:
6920 case FR_TYPE_TLV:
6921 case FR_TYPE_STRUCT:
6922 case FR_TYPE_VSA:
6923 case FR_TYPE_VENDOR:
6924 case FR_TYPE_INTERNAL:
6925 fr_strerror_printf("Cannot escape data type '%s'", fr_type_to_str(vb->type));
6926 return -1;
6927
6928 case FR_TYPE_ATTR:
6929 fr_assert(0); /* @todo - print to string, and then escape? */
6930 fr_strerror_printf("Cannot escape data type '%s'", fr_type_to_str(vb->type));
6931 return -1;
6932
6933 default:
6934 break;
6935 }
6936
6937 /*
6938 * Don't do double escaping.
6939 */
6940 if (!escape->always_escape && fr_value_box_is_safe_for(vb, escape->safe_for)) return 0;
6941
6942 ret = escape->func(vb, uctx);
6943 if (unlikely(ret < 0)) return ret;
6944
6945 /*
6946 * '1' means that the function mashed the safe_for value, so we don't need to.
6947 */
6948 if (!ret) vb->vb_safefor = escape->safe_for;
6949 vb->tainted = false;
6950
6951 return 0;
6952}
6953
6954/** Escape a list of value boxes in place
6955 *
6956 * @note Applies recursively to the children of group boxes.
6957 *
6958 * @note on error, the list may be left in an inconsistent/partially escaped state.
6959 *
6960 * @param[in] list to escape.
6961 * @param[in] escape escape definition to apply to the value box.
6962 * @param[in] uctx user context to pass to the escape function.
6963 * @return
6964 * - 0 on success.
6965 * - -1 on failure.
6966 */
6967int fr_value_box_list_escape_in_place(fr_value_box_list_t *list, fr_value_box_escape_t const *escape, void *uctx)
6968{
6969 int ret = 0;
6970
6971 fr_value_box_list_foreach(list, vb) {
6972 ret = fr_value_box_escape_in_place(vb, escape, uctx);
6973 if (unlikely(ret < 0)) return ret;
6974 }
6975
6976 return ret;
6977}
6978
6983
6984static int _value_box_escape_rules(fr_value_box_t *vb, void *uctx)
6985{
6987
6988 if (fr_type_is_leaf(vb->type)) {
6989 if (fr_value_box_escape_in_place_erules(ctx->ctx, vb, ctx->erules) < 0) return -1;
6990
6991 return 1; /* safe_for has been updated */
6992 }
6993
6997 .safe_for = (fr_value_box_safe_for_t) ctx->erules,
6998 .always_escape = false,
6999 },
7001 .ctx = vb,
7002 .erules = ctx->erules,
7003 }
7004 );
7005}
7006
7007/** Escape a value-box in place using sbuff escaping rules, and mark it safe-for.
7008 *
7009 * If the input type isn't a string, then it is converted to a string.
7010 *
7011 * The output type is always #FR_TYPE_STRING
7012 *
7013 * @param[in] ctx to allocate any new buffers in.
7014 * @param[in] vb which will be escaped
7015 * @param[in] erules escape rules
7016 * @return
7017 * - <0 for error, generally OOM
7018 * - 0 for success (did not set safe_for)
7019 * - 1 for success (did set safe_for)
7020 */
7022{
7023 ssize_t slen;
7024 fr_sbuff_t *escaped = NULL;
7025
7026 FR_SBUFF_TALLOC_THREAD_LOCAL(&escaped, 256, 4096);
7027
7028 /*
7029 * Structural types are much more complicated. :(
7030 */
7031 if (!fr_type_is_leaf(vb->type)) {
7032 int rcode;
7033
7037 .safe_for = (fr_value_box_safe_for_t) erules,
7038 .always_escape = false,
7039 },
7041 .ctx = ctx,
7042 .erules = erules,
7043 }
7044 );
7045 if (rcode < 0) return rcode;
7046
7047 rcode = fr_value_box_list_concat_as_string(NULL, escaped, &vb->vb_group, NULL, 0, NULL,
7049 (fr_value_box_safe_for_t) erules, true);
7050 if (rcode < 0) return rcode;
7051
7052 fr_assert(fr_value_box_list_num_elements(&vb->vb_group) == 0);
7053
7054 goto set_value;
7055 }
7056
7057 if (vb->type != FR_TYPE_STRING) {
7058 if (fr_value_box_cast_in_place(ctx, vb, FR_TYPE_STRING, NULL) < 0) return -1;
7059 } else {
7060 if (fr_value_box_is_safe_for(vb, erules)) return 0;
7061 }
7062
7063 slen = fr_sbuff_in_escape(escaped, vb->vb_strvalue, vb->vb_length, erules);
7064 if (slen < 0) return -1;
7065
7066set_value:
7067 if (fr_value_box_bstrndup(ctx, vb, NULL, fr_sbuff_start(escaped), fr_sbuff_used(escaped), false) < 0) return -1;
7068
7069 fr_value_box_mark_safe_for(vb, erules);
7070
7071 return 1;
7072}
7073
7074/** Escape a value-box in place using the supplied #fr_sbuff_escape_rules_t in uctx
7075 *
7076 * If the input type isn't a string, then it is converted to a string.
7077 *
7078 * The output type is always #FR_TYPE_STRING
7079 *
7080 * @param[in] vb which will be escaped
7081 * @param[in] uctx escape rules
7082 * @return
7083 * - <0 for error, generally OOM
7084 * - 0 for success (did not set safe_for)
7085 * - 1 for success (did set safe_for)
7086 */
7088{
7089 return fr_value_box_escape_in_place_erules(vb, vb, uctx);
7090}
7091
7092/** Escape a value box in place using an sbuff escape function
7093 *
7094 * If the input type isn't a string, then it is converted to a string.
7095 *
7096 * The output type is always #FR_TYPE_STRING. The safe_for and tainted
7097 * flags are left as they were. The caller marks the box once it knows
7098 * which dialect the escape function produced.
7099 *
7100 * @param[in] ctx to allocate the escaped string in.
7101 * @param[in] vb which will be escaped. Must be a leaf type.
7102 * @param[in] escape function to run over the string value.
7103 * @return
7104 * - <0 for error, generally OOM.
7105 * - 0 for success.
7106 */
7107int fr_value_box_escape_in_place_func(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_sbuff_escape_func_t escape)
7108{
7109 fr_sbuff_t *escaped = NULL;
7110
7111 fr_assert(fr_type_is_leaf(vb->type));
7112
7113 if ((vb->type != FR_TYPE_STRING) && (fr_value_box_cast_in_place(ctx, vb, FR_TYPE_STRING, NULL) < 0)) {
7114 return -1;
7115 }
7116
7117 FR_SBUFF_TALLOC_THREAD_LOCAL(&escaped, 256, SIZE_MAX);
7118
7119 if (escape(escaped, &FR_SBUFF_IN(vb->vb_strvalue, vb->vb_length)) < 0) return -1;
7120
7121 return fr_value_box_bstrndup_replace(ctx, vb, fr_sbuff_start(escaped), (ssize_t)fr_sbuff_used(escaped));
7122}
7123
7124
7125/** Removes a single layer of nesting, moving all children into the parent list
7126 *
7127 * @param[in] ctx to reparent children in if steal is true.
7128 * @param[in] list to flatten.
7129 * @param[in] steal whether to change the talloc ctx of children.
7130 * @param[in] free whether to free any group boxes which have had
7131 * their children removed.
7132 */
7133void fr_value_box_flatten(TALLOC_CTX *ctx, fr_value_box_list_t *list, bool steal, bool free)
7134{
7135 fr_value_box_list_foreach(list, child) {
7136 if (!fr_type_is_structural(child->type)) continue;
7137
7138 fr_value_box_list_foreach(&child->vb_group, grandchild) {
7139 fr_value_box_list_remove(&child->vb_group, grandchild);
7140 if (steal) talloc_steal(ctx, grandchild);
7141 fr_value_box_list_insert_before(list, child, grandchild);
7142 }
7143
7144 if (free) talloc_free(child);
7145 }
7146}
7147
7148/** Concatenate the string representations of a list of value boxes together
7149 *
7150 * @param[in] ctx to allocate the buffer in.
7151 * @param[in] list of value boxes.
7152 * @param[in] delim to insert between value box values.
7153 * @param[in] e_rules to control escaping of the concatenated elements.
7154 * @return
7155 * - NULL on error.
7156 * - The concatenation of the string values of the value box list on success.
7157 */
7158char *fr_value_box_list_aprint(TALLOC_CTX *ctx, fr_value_box_list_t const *list, char const *delim,
7159 fr_sbuff_escape_rules_t const *e_rules)
7160{
7161 fr_value_box_t const *vb = fr_value_box_list_head(list);
7162 char *aggr, *td = NULL;
7163 TALLOC_CTX *pool = NULL;
7164
7165 if (!vb) return NULL;
7166
7167 fr_value_box_aprint(ctx, &aggr, vb, e_rules);
7168 if (!aggr) return NULL;
7169 if (!fr_value_box_list_next(list, vb)) return aggr;
7170
7171 /*
7172 * If we're aggregating more values,
7173 * allocate a temporary pool.
7174 */
7175 pool = talloc_pool(NULL, 255);
7176 if (delim) td = talloc_strdup(pool, delim);
7177
7178 while ((vb = fr_value_box_list_next(list, vb))) {
7179 char *str, *new_aggr;
7180
7181 fr_value_box_aprint(pool, &str, vb, e_rules);
7182 if (!str) continue;
7183
7184 new_aggr = talloc_buffer_append_variadic_buffer(ctx, aggr, 2, td, str);
7185 if (unlikely(!new_aggr)) {
7186 talloc_free(aggr);
7187 talloc_free(pool);
7188 return NULL;
7189 }
7190 aggr = new_aggr;
7191 talloc_free(str);
7192 }
7193 talloc_free(pool);
7194
7195 return aggr;
7196}
7197
7198/** Concatenate the string representations of a list of value boxes together hiding "secret" values
7199 *
7200 * @param[in] ctx to allocate the buffer in.
7201 * @param[in] list of value boxes.
7202 * @param[in] delim to insert between value box values.
7203 * @param[in] e_rules to control escaping of the concatenated elements.
7204 * @return
7205 * - NULL on error.
7206 * - The concatenation of the string values of the value box list on success.
7207 */
7208char *fr_value_box_list_aprint_secure(TALLOC_CTX *ctx, fr_value_box_list_t const *list, char const *delim,
7209 fr_sbuff_escape_rules_t const *e_rules)
7210{
7211 fr_value_box_t const *vb = fr_value_box_list_head(list);
7212 char *aggr, *td = NULL;
7213 TALLOC_CTX *pool = NULL;
7214
7215 if (!vb) return NULL;
7216
7218 aggr = talloc_strdup(ctx, "<<< secret >>>");
7219 } else {
7220 fr_value_box_aprint(ctx, &aggr, vb, e_rules);
7221 }
7222 if (!aggr) return NULL;
7223 if (!fr_value_box_list_next(list, vb)) return aggr;
7224
7225 /*
7226 * If we're aggregating more values,
7227 * allocate a temporary pool.
7228 */
7229 pool = talloc_pool(NULL, 255);
7230 if (delim) td = talloc_strdup(pool, delim);
7231
7232 while ((vb = fr_value_box_list_next(list, vb))) {
7233 char *str, *new_aggr;
7234
7236 str = talloc_strdup(pool, "<<< secret >>>");
7237 } else {
7238 fr_value_box_aprint(pool, &str, vb, e_rules);
7239 }
7240 if (!str) continue;
7241
7242 new_aggr = talloc_buffer_append_variadic_buffer(ctx, aggr, 2, td, str);
7243 if (unlikely(!new_aggr)) {
7244 talloc_free(aggr);
7245 talloc_free(pool);
7246 return NULL;
7247 }
7248 aggr = new_aggr;
7249 talloc_free(str);
7250 }
7251 talloc_free(pool);
7252
7253 return aggr;
7254}
7255
7256/** Hash the contents of a value box
7257 *
7258 */
7260{
7261 switch (vb->type) {
7262 case FR_TYPE_FIXED_SIZE:
7263 return fr_hash(fr_value_box_raw(vb, vb->type),
7264 fr_value_box_field_sizes[vb->type]);
7265
7266 case FR_TYPE_STRING:
7267 return fr_hash(vb->vb_strvalue, vb->vb_length);
7268
7269 case FR_TYPE_OCTETS:
7270 return fr_hash(vb->vb_octets, vb->vb_length);
7271
7272 case FR_TYPE_ATTR:
7273 return fr_hash(&vb->vb_attr, sizeof(vb->vb_attr));
7274
7275 case FR_TYPE_STRUCTURAL:
7276 case FR_TYPE_INTERNAL:
7279 case FR_TYPE_NULL:
7280 fr_assert(0);
7281 break;
7282 }
7283
7284 return 0;
7285}
7286
7287/** Do a full copy of a list of value boxes
7288 *
7289 * @param[in] ctx to allocate boxes in.
7290 * @param[out] out Where to write the head of the new list.
7291 * @param[in] in boxes to copy.
7292 * @return
7293 * - A duplicate list of value boxes, allocated in the context of 'ctx'
7294 * - NULL on error, or empty input list.
7295 */
7296int fr_value_box_list_acopy(TALLOC_CTX *ctx, fr_value_box_list_t *out, fr_value_box_list_t const *in)
7297{
7298 fr_value_box_t const *in_p = NULL;
7299
7300 while ((in_p = fr_value_box_list_next(in, in_p))) {
7301 fr_value_box_t *n = NULL;
7302
7304 if (!n) {
7305 error:
7306 fr_value_box_list_talloc_free(out);
7307 return -1;
7308 }
7309
7310 if (fr_value_box_copy(n, n, in_p) < 0) goto error;
7311 fr_dlist_insert_tail(fr_value_box_list_dlist_head(out), n);
7312 }
7313
7314 return 0;
7315}
7316
7317/** Check to see if any list members (or their children) are tainted
7318 *
7319 * @param[in] head of list to check.
7320 * @return
7321 * - true if a list member is tainted.
7322 * - false if no list members are tainted.
7323 */
7324bool fr_value_box_list_tainted(fr_value_box_list_t const *head)
7325{
7326 fr_value_box_t *vb = NULL;
7327
7328 while ((vb = fr_value_box_list_next(head, vb))) {
7329 if (fr_type_is_group(vb->type) && fr_value_box_list_tainted(&vb->vb_group)) return true;
7330 if (vb->tainted) return true;
7331 }
7332
7333 return false;
7334}
7335
7336#if defined(WITH_VERIFY_PTR) || !defined(NDEBUG)
7337#define VB_NAME "fr_value_box_t %p (from %s:%d)"
7338#define VB_NAME_LOCATION(_x) (void const *) (_x), (_x)->file ? (_x)->file : "", (_x)->line
7339
7340/** Validation function to check that a fr_value_box_t is correctly initialised
7341 *
7342 */
7343void fr_value_box_verify(char const *file, int line, fr_value_box_t const *vb)
7344{
7346 /*
7347 * nonnull only does something if we're building
7348 * with ubsan... We still want to assert event
7349 * if we're building without sanitizers.
7350 */
7351 fr_fatal_assert_msg(vb, "CONSISTENCY CHECK FAILED %s[%i]: fr_value_box_t pointer was NULL", file, line);
7353
7354 if (VERIFY_IS_SET(vb)) return;
7355
7356 if (vb->talloced) vb = talloc_get_type_abort_const(vb, fr_value_box_t);
7357
7358#ifndef NDEBUG
7359 fr_fatal_assert_msg(vb->magic == FR_VALUE_BOX_MAGIC, "CONSISTENCY CHECK FAILED %s[%i]: " VB_NAME " magic "
7360 "incorrect, expected %" PRIx64 ", got %" PRIx64,
7361 file, line,
7362 VB_NAME_LOCATION(vb),
7363 FR_VALUE_BOX_MAGIC, vb->magic);
7364#endif
7365 switch (vb->type) {
7366 case FR_TYPE_STRING:
7367 if (!vb->vb_length) {
7368#if 0
7369 fr_fatal_assert_msg(!vb->vb_strvalue || (talloc_array_length(vb->vb_strvalue) == 1), "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " strvalue field "
7370 "wasn non-NULL, but length was %u",
7371 file, line,
7372 VB_NAME_LOCATION(vb),
7373 vb->vb_length);
7374#endif
7375 break;
7376 }
7377
7378 fr_fatal_assert_msg(vb->vb_strvalue, "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " strvalue field "
7379 "was NULL", file, line, VB_NAME_LOCATION(vb));
7380 fr_fatal_assert_msg(vb->vb_strvalue[vb->vb_length] == '\0',
7381 "CONSISTENCY CHECK FAILED %s[%i]: " VB_NAME " strvalue field "
7382 "not null terminated", file, line, VB_NAME_LOCATION(vb));
7383 if (vb->talloced) {
7384 size_t len = talloc_array_length(vb->vb_strvalue);
7385
7386 /* We always \0 terminate to be safe, even though most things should use the len field */
7387 if (len <= vb->vb_length) {
7388 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: Expected " VB_NAME " strvalue talloc buffer "
7389 "len >= %zu, got %zu",
7390 file, line,
7391 VB_NAME_LOCATION(vb),
7392 vb->vb_length + 1, len);
7393 }
7394 }
7395 break;
7396
7397 case FR_TYPE_OCTETS:
7398 if (!vb->vb_length) {
7399#if 0
7400 fr_fatal_assert_msg(!vb->vb_octets || (talloc_array_length(vb->vb_octets) == 0), "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " octets field "
7401 "wasn non-NULL, but length was %u",
7402 file, line,
7403 VB_NAME_LOCATION(vb).
7404 vb->vb_length);
7405#endif
7406 break;
7407 }
7408
7409 fr_fatal_assert_msg(vb->vb_octets, "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " octets field "
7410 "was NULL", file, line, VB_NAME_LOCATION(vb));
7411 break;
7412
7413 case FR_TYPE_VOID:
7414 fr_fatal_assert_msg(vb->vb_void, "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " ptr field "
7415 "was NULL", file, line, VB_NAME_LOCATION(vb));
7416 break;
7417
7418 case FR_TYPE_GROUP:
7419 fr_value_box_list_verify(file, line, &vb->vb_group);
7420 break;
7421
7422 case FR_TYPE_ATTR:
7423 fr_fatal_assert_msg(vb->vb_attr, "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " vb_attr field "
7424 "was NULL", file, line, VB_NAME_LOCATION(vb));
7425 break;
7426
7427 case FR_TYPE_BOOL:
7428 fr_fatal_assert_msg(vb->vb_uint8 <= 1, "CONSISTENCY CHECK FAILED %s[%d]: " VB_NAME " vb_bool field "
7429 "was not boolean!", file, line, VB_NAME_LOCATION(vb));
7430 break;
7431
7432 default:
7433 break;
7434 }
7435
7436 VERIFY_SET(vb);
7437}
7438
7439void fr_value_box_list_verify(char const *file, int line, fr_value_box_list_t const *list)
7440{
7442}
7443#endif
7444
7445/** Mark a value-box as "safe", of a particular type.
7446 *
7447 */
7449{
7450 /*
7451 * Don't over-ride value-boxes which are already safe, unless we want to mark them as being
7452 * completely unsafe.
7453 */
7454 if ((vb->vb_safefor == FR_VALUE_BOX_SAFE_FOR_ANY) &&
7455 (safe_for != FR_VALUE_BOX_SAFE_FOR_NONE)) {
7456 fr_assert(!vb->tainted);
7457 return;
7458 }
7459
7460 vb->vb_safefor = safe_for;
7461}
7462
7463/** Mark a value-box as "unsafe"
7464 *
7465 * This always succeeds, and there are no side effects.
7466 */
7468{
7469 vb->vb_safefor = FR_VALUE_BOX_SAFE_FOR_NONE;
7470}
7471
7472/** Set the escaped flag for all value boxes in a list
7473 *
7474 * @note Only operates on a single level.
7475 *
7476 * @param[in] list to operate on.
7477 * @param[in] safe_for value to set.
7478 */
7479void fr_value_box_list_mark_safe_for(fr_value_box_list_t *list, fr_value_box_safe_for_t safe_for)
7480{
7481 fr_value_box_list_foreach(list, vb) {
7482 /*
7483 * Don't over-ride value-boxes which are already safe.
7484 */
7485 if (vb->vb_safefor == FR_VALUE_BOX_SAFE_FOR_ANY) {
7486 fr_assert(!vb->tainted);
7487
7488 } else {
7489 vb->vb_safefor = safe_for;
7490 }
7491 }
7492}
7493
7494/** Copy the safety values from one box to another.
7495 *
7496 */
7498{
7499 if (out == in) return;
7500
7501 out->vb_safefor = in->vb_safefor;
7502 out->tainted = in->tainted;
7503 out->vb_secret = in->vb_secret;
7504}
7505
7506/** Copy the safety values from one box to another.
7507 *
7508 * But note that we have changed the output format, so we reset the "safe_for" value to NONE.
7509 */
7511{
7512 out->vb_safefor = FR_VALUE_BOX_SAFE_FOR_NONE;
7513 out->tainted = in->tainted;
7514 out->vb_secret = in->vb_secret;
7515}
7516
7517/** Merge one safety into another
7518 *
7519 * @param[in,out] out safety to narrow.
7520 * @param[in] in safety to merge in.
7521 */
7523{
7524 if (out == in) return;
7525
7526 /*
7527 * If we're already at no safety, then we don't need to do anything.
7528 *
7529 * Otherwise we update the safety only if we need to change it.
7530 */
7531 if ((out->safe_for != FR_VALUE_BOX_SAFE_FOR_NONE) &&
7532 (out->safe_for != in->safe_for)) {
7533 /*
7534 * If the output is anything, then the input is more restrictive, so we switch to that.
7535 *
7536 * If the input is anything, then the output is already the more restrictive of the
7537 * two, so we leave it alone.
7538 *
7539 * Otherwise the values are different. Either it's X/Y, or NONE/X, or X/NONE. In which
7540 * case the answer is always NONE.
7541 */
7542 if (out->safe_for == FR_VALUE_BOX_SAFE_FOR_ANY) {
7543 out->safe_for = in->safe_for;
7544
7545 } else if (in->safe_for != FR_VALUE_BOX_SAFE_FOR_ANY) {
7546 out->safe_for = FR_VALUE_BOX_SAFE_FOR_NONE;
7547 }
7548 }
7549
7550 out->secret |= in->secret;
7551}
7552
7553/** Merge safety results.
7554 */
7556{
7557 _value_box_safety_merge(&out->safety, &in->safety);
7558 out->tainted |= in->tainted;
7559}
7560
7561/** Replace the safety of a box
7562 *
7563 * @param[out] box to update.
7564 * @param[in] safety to copy into the box.
7565 */
7567{
7568 box->safety = *safety;
7569}
7570
7571/** Mark a box as holding a secret, or not
7572 *
7573 * A structural value has no safety of its own, the children carry theirs. In a
7574 * #fr_pair_t the children list overlays the safety field, so a structural box is
7575 * left alone rather than written to.
7576 */
7578{
7579 if (fr_type_is_structural(box->type)) return;
7580
7581 box->vb_secret = secret;
7582}
7583
7584/** Merge the safety of every leaf box in a list into out
7585 *
7586 * Recurses into group boxes, which carry no safety of their own.
7587 */
7588static void _value_box_list_safety_merge(fr_value_box_t *out, fr_value_box_list_t const *list)
7589{
7590 fr_value_box_list_foreach(list, vb) {
7591 if (fr_type_is_group(vb->type)) {
7592 _value_box_list_safety_merge(out, &vb->vb_group);
7593 continue;
7594 }
7595
7597 }
7598}
7599
7600/** Set the safety of out to the most restrictive safety of any leaf box in a list
7601 *
7602 * Use when a value is built from several boxes without going through
7603 * #fr_value_box_list_concat_in_place, e.g. when a separator is inserted between them.
7604 * A box safe for consumer X, joined with a box safe for X or for anything, is still
7605 * safe for X. Any other combination is safe for nothing.
7606 *
7607 * @param[out] out Box whose safety is replaced. Its value is left alone.
7608 * @param[in] list Boxes to merge. Group boxes are descended into.
7609 */
7610void fr_value_box_list_safety_merge(fr_value_box_t *out, fr_value_box_list_t const *list)
7611{
7612 out->vb_safefor = FR_VALUE_BOX_SAFE_FOR_ANY;
7613 out->vb_secret = false;
7614
7616}
7617
7618
7619/** Check truthiness of values.
7620 *
7621 * The casting rules for expressions / conditions are slightly
7622 * different than fr_value_box_cast(). Largely because that
7623 * function is used to parse configuration files, and parses "yes
7624 * / no" and "true / false" strings, even if there's no
7625 * fr_dict_attr_t passed to it.
7626 */
7628{
7629 fr_value_box_t box;
7630
7631 switch (in->type) {
7632 case FR_TYPE_NULL:
7636 case FR_TYPE_ATTR:
7637 case FR_TYPE_INTERNAL:
7638 break;
7639
7640 case FR_TYPE_GROUP:
7641 return (fr_value_box_list_num_elements(&in->vb_group) > 0);
7642
7643 case FR_TYPE_BOOL:
7644 return in->vb_bool;
7645
7646 case FR_TYPE_STRING:
7647 case FR_TYPE_OCTETS:
7648 return (in->vb_length > 0);
7649
7650 case FR_TYPE_IPV4_ADDR:
7651 case FR_TYPE_IPV6_ADDR:
7652 return !fr_ipaddr_is_inaddr_any(&in->vb_ip);
7653
7656 return !((in->vb_ip.prefix == 0) && fr_ipaddr_is_inaddr_any(&in->vb_ip));
7657
7659 case FR_TYPE_FLOAT32:
7660 case FR_TYPE_FLOAT64:
7661 case FR_TYPE_IFID:
7662 case FR_TYPE_ETHERNET:
7664 if (fr_value_box_cast(NULL, &box, FR_TYPE_BOOL, NULL, in) < 0) return false;
7665 return box.vb_bool;
7666 }
7667
7668 return false;
7669}
7670
7671#define INFO_INDENT(_fmt, ...) fprintf(fp, "%*s" _fmt "\n", depth * 2, " ", ## __VA_ARGS__)
7672
7673static void _fr_value_box_debug(FILE *fp, fr_value_box_t const *vb, int depth, int idx);
7674static void _fr_value_box_list_debug(FILE *fp, fr_value_box_list_t const *head, int depth)
7675{
7676 int i = 0;
7677
7678 INFO_INDENT("{");
7680 INFO_INDENT("}");
7681}
7682
7683/** Print a list of value boxes as info messages
7684 *
7685 * @note Call directly from the debugger
7686 */
7687void fr_value_box_list_debug(FILE *fp, fr_value_box_list_t const *head)
7688{
7690}
7691
7692static void _fr_value_box_debug(FILE *fp, fr_value_box_t const *vb, int depth, int idx)
7693{
7694 char *value;
7695 char buffer[64];
7696
7697 if (fr_type_is_structural(vb->type)) {
7698 _fr_value_box_list_debug(fp, &vb->vb_group, depth + 1);
7699 return;
7700 }
7701
7702 buffer[0] = '\0';
7703 if (vb->type == FR_TYPE_TIME_DELTA) {
7704 if (!vb->enumv) {
7705 snprintf(buffer, sizeof(buffer), " (sec!) %" PRId64, fr_time_delta_unwrap(vb->vb_time_delta));
7706 } else {
7707 snprintf(buffer, sizeof(buffer), " (%s) %" PRId64,
7708 fr_table_str_by_value(fr_time_precision_table, (fr_time_res_t)vb->enumv->flags.flag_time_res, "?"),
7709 fr_time_delta_unwrap(vb->vb_time_delta));
7710 }
7711 }
7712
7713 fr_value_box_aprint(NULL, &value, vb, NULL);
7714 if (idx >= 0) {
7715 INFO_INDENT("[%d] (%s) %s", idx, fr_type_to_str(vb->type), value);
7716 INFO_INDENT(" %s %s %lx%s",
7717 vb->vb_secret ? "s" : "-",
7718 vb->tainted ? "t" : "-",
7719 vb->vb_safefor, buffer);
7720 } else {
7721 INFO_INDENT("(%s) %s", fr_type_to_str(vb->type), value);
7722 INFO_INDENT(" %s %s %lx%s",
7723 vb->vb_secret ? "s" : "-",
7724 vb->tainted ? "t" : "-",
7725 vb->vb_safefor, buffer);
7726 }
7728}
7729
7730/** Print the value of a box as info messages
7731 *
7732 * @note Call directly from the debugger
7733 */
7734void fr_value_box_debug(FILE *fp, fr_value_box_t const *vb)
7735{
7736 _fr_value_box_debug(fp, vb, 0, -1);
7737}
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 fr_atomic_queue_t ** aq
static size_t min(size_t x, size_t y)
Definition dbuff.c:66
int fr_dbuff_trim_talloc(fr_dbuff_t *dbuff, size_t len)
Trim a talloced dbuff to the minimum length required to represent the contained string.
Definition dbuff.c:297
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h: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:772
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:624
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:824
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:713
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:454
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:1159
int64_t const fr_time_multiplier_by_res[]
Definition time.c:32
static fr_time_delta_t fr_time_delta_from_integer(bool *overflow, int64_t integer, fr_time_res_t res)
Definition time.h:548
static int64_t fr_time_delta_to_integer(fr_time_delta_t delta, fr_time_res_t res)
Definition time.h:627
static 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:944
#define fr_time_delta_wrap(_time)
Definition time.h:152
#define fr_unix_time_wrap(_time)
Definition time.h:160
fr_time_res_t
The base resolution for print parse operations.
Definition time.h:48
@ FR_TIME_RES_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:930
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:4977
void fr_value_box_list_verify(char const *file, int line, fr_value_box_list_t const *list)
Definition value.c:7439
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:5296
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:6195
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:4759
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:5324
static void _fr_value_box_list_debug(FILE *fp, fr_value_box_list_t const *head, int depth)
Definition value.c:7674
#define INFO_INDENT(_fmt,...)
Definition value.c:7671
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:7467
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:4728
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
Definition value.c:7259
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:6232
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:5424
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:7087
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:7208
#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:7337
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:5100
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:5256
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:5016
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:4015
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:4790
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:6632
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:7158
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:5133
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:3894
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:7692
#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:7107
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:4465
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:6967
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:4848
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:4315
bool fr_value_box_is_truthy(fr_value_box_t const *in)
Check truthiness of values.
Definition value.c:7627
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:4265
void fr_value_box_set_cursor_shallow(fr_value_box_t *dst, fr_type_t type, void *cursor, char const *name)
Definition value.c:5309
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:5278
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:7522
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:4591
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:5370
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:5523
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:7448
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:4400
void fr_value_box_set_attr(fr_value_box_t *dst, fr_dict_attr_t const *da)
Definition value.c:5356
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:7343
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:7577
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:4702
#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:4828
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:7566
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:6472
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:3633
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:6515
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:3233
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:7510
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:4349
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:7588
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:7479
#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:3389
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:4381
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:7021
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:7555
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:4812
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:7687
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:3004
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:3331
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:7497
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:6981
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:4879
#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:6984
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:4627
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:7133
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:7296
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:4448
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:7324
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
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:7610
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:4912
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:4953
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:5219
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:7734
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:5061
static fr_dict_attr_t const * fr_value_box_attr_enumv(fr_dict_attr_t const *da)
Definition value.c:5330
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:6911
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:5040
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:3119
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:5194
#define VB_NAME_LOCATION(_x)
Definition value.c:7338
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:3476
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:6732
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