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