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: 393de99c9c56acfe5f4725e2ee8f8e71bbc11211 $")
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_field(value->enumv)) {
1446 if (value->enumv->flags.subtype == FLAG_LENGTH_UINT8) {
1447 if (value->vb_length > 255) return 255;
1448
1449 } else if (value->enumv->flags.subtype == FLAG_LENGTH_UINT16) {
1450 if (value->vb_length > 65535) return 65535;
1451 }
1452 }
1453 }
1454 return value->vb_length;
1455
1456 /*
1457 * These can have different encodings, depending on the underlying protocol.
1458 */
1459 case FR_TYPE_DATE:
1460 case FR_TYPE_TIME_DELTA:
1461 if (value->enumv) return value->enumv->flags.length;
1463
1464 default:
1465 fr_assert(network_min_size(value->type) != 0);
1466 return network_min_size(value->type);
1467
1468 case FR_TYPE_TLV:
1469 case FR_TYPE_STRUCT:
1470 case FR_TYPE_VSA:
1471 case FR_TYPE_VENDOR:
1472 case FR_TYPE_INTERNAL:
1473 fr_assert(0);
1474 return -1;
1475 }
1476}
1477
1478/** Encode a single value box, serializing its contents in generic network format
1479 *
1480 * The serialized form of #fr_value_box_t may not match the requirements of your protocol
1481 * completely. In cases where they do not, you should overload specific types in the
1482 * function calling #fr_value_box_to_network.
1483 *
1484 * The general serialization rules are:
1485 *
1486 * - Octets are encoded in binary form (not hex).
1487 * - Strings are encoded without the trailing \0 byte.
1488 * - Integers are encoded big-endian.
1489 * - Bools are encoded using one byte, with value 0x00 (false) or 0x01 (true).
1490 * - Signed integers are encoded two's complement, with the MSB as the sign bit.
1491 * Byte order is big-endian.
1492 * - Network addresses are encoded big-endian.
1493 * - IPv4 prefixes are encoded with 1 byte for the prefix, then 4 bytes of address.
1494 * - IPv6 prefixes are encoded with 1 byte for the scope_id, 1 byte for the prefix,
1495 * and 16 bytes of address.
1496 * - Floats are encoded in IEEE-754 format with a big-endian byte order. We rely
1497 * on the fact that the C standards require floats to be represented in IEEE-754
1498 * format in memory.
1499 * - Dates are encoded as 16/32/64-bit unsigned UNIX timestamps.
1500 * - time_deltas are encoded as 16/32/64-bit signed integers.
1501 *
1502 * #FR_TYPE_SIZE is not encodable, as it is system specific.
1503 *
1504 * This function will not encode structural types (TLVs, VSAs etc...). These are usually
1505 * specific to the protocol anyway.
1506 *
1507 * All of the dictionary rules are respected. string/octets can have
1508 * a fixed length (which is zero-padded if necessary), or can have an
1509 * 8/16-bit "length" prefix.
1510 *
1511 * @param[out] dbuff Where to write serialized data.
1512 * @param[in] value to encode.
1513 * @return
1514 * - 0 no bytes were written.
1515 * - >0 the number of bytes written to out.
1516 * - <0 the number of bytes we'd need in dbuff to complete the operation.
1517 */
1519{
1520 size_t min, max;
1521 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1522
1523 /*
1524 * We cannot encode structural types here.
1525 */
1526 if (!fr_type_is_leaf(value->type)) {
1527 unsupported:
1528 fr_strerror_printf("%s: Cannot encode type \"%s\"",
1529 __FUNCTION__,
1530 fr_type_to_str(value->type));
1532 }
1533
1534 /*
1535 * Variable length types
1536 */
1537 switch (value->type) {
1538 case FR_TYPE_OCTETS:
1539 case FR_TYPE_STRING:
1540 max = value->vb_length;
1541
1542 /*
1543 * Sometimes variable length *inside* the server
1544 * has maximum length on the wire.
1545 */
1546 if (value->enumv) {
1547 if (value->enumv->flags.length) {
1548 /*
1549 * The field is fixed size, and the data is smaller than that, We zero-pad the field.
1550 */
1551 if (max < value->enumv->flags.length) {
1552 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *)value->datum.ptr, max);
1553 FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, value->enumv->flags.length - max);
1554 return fr_dbuff_set(dbuff, &work_dbuff);
1555
1556 } else if (max > value->enumv->flags.length) {
1557 /*
1558 * Truncate the input to the maximum allowed length.
1559 */
1560 max = value->enumv->flags.length;
1561 }
1562
1563 } else if (da_is_length_field(value->enumv)) {
1564 /*
1565 * Truncate the output to the max allowed for this field and encode the length.
1566 */
1567 if (value->enumv->flags.subtype == FLAG_LENGTH_UINT8) {
1568 if (max > 255) max = 255;
1569 FR_DBUFF_IN_RETURN(&work_dbuff, (uint8_t) max);
1570
1571 } else if (value->enumv->flags.subtype == FLAG_LENGTH_UINT16) {
1572 if (max > 65536) max = 65535;
1573 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t) max);
1574
1575 } else {
1576 return -1;
1577 }
1578 }
1579 }
1580
1581 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *)value->datum.ptr, max);
1582 return fr_dbuff_set(dbuff, &work_dbuff);
1583
1584 /*
1585 * The data can be encoded in a variety of widths.
1586 */
1587 case FR_TYPE_DATE:
1588 case FR_TYPE_TIME_DELTA:
1589 if (value->enumv) {
1590 min = value->enumv->flags.length;
1591 } else {
1592 min = 4;
1593 }
1594 break;
1595
1596 default:
1597 fr_assert(network_min_size(value->type) != 0);
1598 min = network_min_size(value->type);
1599 break;
1600
1601 case FR_TYPE_TLV:
1602 case FR_TYPE_STRUCT:
1603 case FR_TYPE_VSA:
1604 case FR_TYPE_VENDOR:
1605 case FR_TYPE_INTERNAL:
1606 fr_assert(0);
1607 return -1;
1608 }
1609
1610 /*
1611 * We have to encode actual data here.
1612 */
1613 fr_assert(min > 0);
1614
1615 switch (value->type) {
1616 case FR_TYPE_IPV4_ADDR:
1617 ipv4addr:
1618 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff,
1619 (uint8_t const *)&value->vb_ip.addr.v4.s_addr,
1620 sizeof(value->vb_ip.addr.v4.s_addr));
1621 break;
1622 /*
1623 * Needs special mangling
1624 */
1626 ipv4prefix:
1627 FR_DBUFF_IN_RETURN(&work_dbuff, value->vb_ip.prefix);
1628 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff,
1629 (uint8_t const *)&value->vb_ip.addr.v4.s_addr,
1630 sizeof(value->vb_ip.addr.v4.s_addr));
1631 break;
1632
1633 case FR_TYPE_IPV6_ADDR:
1634 ipv6addr:
1635 if (value->vb_ip.scope_id > 0) FR_DBUFF_IN_RETURN(&work_dbuff, value->vb_ip.scope_id);
1636 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value->vb_ip.addr.v6.s6_addr, sizeof(value->vb_ip.addr.v6.s6_addr));
1637 break;
1638
1640 ipv6prefix:
1641 if (value->vb_ip.scope_id > 0) FR_DBUFF_IN_RETURN(&work_dbuff, value->vb_ip.scope_id);
1642 FR_DBUFF_IN_RETURN(&work_dbuff, value->vb_ip.prefix);
1643 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value->vb_ip.addr.v6.s6_addr, sizeof(value->vb_ip.addr.v6.s6_addr));
1644 break;
1645
1646 case FR_TYPE_BOOL:
1647 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, value->datum.boolean);
1648 break;
1649
1651 switch (value->vb_ip.af) {
1652 case AF_INET:
1653 goto ipv4addr;
1654
1655 case AF_INET6:
1656 goto ipv6addr;
1657
1658 default:
1659 break;
1660 }
1661
1662 fr_strerror_const("Combo IP value missing af");
1663 return 0;
1664
1666 switch (value->vb_ip.af) {
1667 case AF_INET:
1668 goto ipv4prefix;
1669
1670 case AF_INET6:
1671 goto ipv6prefix;
1672
1673 default:
1674 break;
1675 }
1676
1677 fr_strerror_const("Combo IP value missing af");
1678 return 0;
1679
1680 /*
1681 * Already in network byte-order
1682 */
1683 case FR_TYPE_IFID:
1684 case FR_TYPE_ETHERNET:
1685 case FR_TYPE_UINT8:
1686 case FR_TYPE_INT8:
1688 break;
1689
1690 /*
1691 * Needs a bytesex operation
1692 */
1693 case FR_TYPE_UINT16:
1694 case FR_TYPE_UINT32:
1695 case FR_TYPE_UINT64:
1696 case FR_TYPE_INT16:
1697 case FR_TYPE_INT32:
1698 case FR_TYPE_INT64:
1699 case FR_TYPE_FLOAT32:
1700 case FR_TYPE_FLOAT64:
1701 {
1702 fr_value_box_t tmp;
1703
1704 fr_value_box_hton(&tmp, value);
1705
1706 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, fr_value_box_raw(&tmp, value->type), min);
1707 }
1708 break;
1709
1710 case FR_TYPE_ATTR:
1711 {
1712 fr_value_box_t tmp, base;
1713
1714 /*
1715 * For now, we only encode at depth 1. The protocol-specific encoders need to do
1716 * something special for attributes at other depths.
1717 */
1718 if (value->vb_attr->depth != 1) {
1719 fr_strerror_printf("Unsupported depth '%u' for encoding attribute %s",
1720 value->vb_attr->depth, value->vb_attr->name);
1721 return 0;
1722 }
1723
1724 switch (value->vb_attr->flags.length) {
1725 case 1:
1726 fr_value_box_init(&base, FR_TYPE_UINT8, NULL, false);
1727 base.vb_uint8 = value->vb_attr->attr;
1728 break;
1729
1730 case 2:
1731 fr_value_box_init(&base, FR_TYPE_UINT16, NULL, false);
1732 base.vb_uint16 = value->vb_attr->attr;
1733 break;
1734
1735 case 4:
1736 fr_value_box_init(&base, FR_TYPE_UINT32, NULL, false);
1737 base.vb_uint32 = value->vb_attr->attr;
1738 break;
1739
1740 default:
1741 fr_strerror_printf("Unsupported length '%d' for decoding attribute %s",
1742 value->vb_attr->flags.length, value->vb_attr->name);
1743 return 0;
1744 }
1745
1746 fr_value_box_hton(&tmp, &base);
1747
1748 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, fr_value_box_raw(&tmp, tmp.type), min);
1749 }
1750 break;
1751
1752 /*
1753 * Dates and deltas are stored internally as
1754 * 64-bit nanoseconds. We have to convert to the
1755 * network format. First by resolution (ns, us,
1756 * ms, s), and then by size (16/32/64-bit).
1757 */
1758 case FR_TYPE_DATE:
1759 {
1760 uint64_t date = 0;
1761 fr_time_res_t res;
1762
1763 if (!value->enumv) {
1764 res = FR_TIME_RES_SEC;
1765 } else {
1766 res = value->enumv->flags.flag_time_res;
1767 }
1768 date = fr_unix_time_to_integer(value->vb_date, res);
1769
1770 if (!value->enumv) {
1771 goto date_size4;
1772
1773 } else switch (value->enumv->flags.length) {
1774 case 2:
1775 if (date > UINT16_MAX) date = UINT16_MAX;
1776 FR_DBUFF_IN_RETURN(&work_dbuff, (int16_t) date);
1777 break;
1778
1779 date_size4:
1780 case 4:
1781 if (date > UINT32_MAX) date = UINT32_MAX;
1782 FR_DBUFF_IN_RETURN(&work_dbuff, (int32_t) date);
1783 break;
1784
1785 case 8:
1786 FR_DBUFF_IN_RETURN(&work_dbuff, date);
1787 break;
1788
1789 default:
1790 goto unsupported;
1791 }
1792
1793 }
1794 break;
1795
1796 case FR_TYPE_TIME_DELTA:
1797 {
1798 int64_t date = 0; /* may be negative */
1800 if (value->enumv) res = value->enumv->flags.flag_time_res;
1801
1802 date = fr_time_delta_to_integer(value->vb_time_delta, res);
1803
1804 if (!value->enumv) {
1805 goto delta_size4;
1806
1807 } else if (!value->enumv->flags.is_unsigned) {
1808 switch (value->enumv->flags.length) {
1809 case 2:
1810 if (date < INT16_MIN) {
1811 date = INT16_MIN;
1812 } else if (date > INT16_MAX) {
1813 date = INT16_MAX;
1814 }
1815 FR_DBUFF_IN_RETURN(&work_dbuff, (int16_t)date);
1816 break;
1817
1818 delta_size4:
1819 case 4:
1820 if (date < INT32_MIN) {
1821 date = INT32_MIN;
1822 } else if (date > INT32_MAX) {
1823 date = INT32_MAX;
1824 }
1825 FR_DBUFF_IN_RETURN(&work_dbuff, (int32_t)date);
1826 break;
1827
1828 case 8:
1829 FR_DBUFF_IN_RETURN(&work_dbuff, (int64_t)date);
1830 break;
1831
1832 default:
1833 goto unsupported;
1834 }
1835 } else { /* time delta is unsigned! */
1836 switch (value->enumv->flags.length) {
1837 case 2:
1838 if (date < 0) {
1839 date = 0;
1840 } else if (date > UINT16_MAX) {
1841 date = UINT16_MAX;
1842 }
1843 FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t)date);
1844 break;
1845
1846 case 4:
1847 if (date < 0) {
1848 date = 0;
1849 } else if (date > UINT32_MAX) {
1850 date = UINT32_MAX;
1851 }
1852 FR_DBUFF_IN_RETURN(&work_dbuff, (uint32_t)date);
1853 break;
1854
1855 case 8:
1856 FR_DBUFF_IN_RETURN(&work_dbuff, (uint64_t)date);
1857 break;
1858
1859 default:
1860 goto unsupported;
1861 }
1862 }
1863 }
1864 break;
1865
1866 case FR_TYPE_OCTETS:
1867 case FR_TYPE_STRING:
1868 case FR_TYPE_SIZE:
1869 case FR_TYPE_NON_LEAF:
1870 goto unsupported;
1871 }
1872
1873 return fr_dbuff_set(dbuff, &work_dbuff);
1874}
1875
1876/** Decode a #fr_value_box_t from serialized binary data
1877 *
1878 * The general deserialization rules are:
1879 *
1880 * - Octets are decoded in binary form (not hex).
1881 * - Strings are decoded without the trailing \0 byte. Strings must consist only of valid UTF8 chars.
1882 * - Integers are decoded big-endian.
1883 * - Bools are decoded using one byte, with value 0x00 (false) or 0x01 (true).
1884 * - Signed integers are decoded two's complement, with the MSB as the sign bit.
1885 * Byte order is big-endian.
1886 * - Network addresses are decoded big-endian.
1887 * - IPv4 prefixes are decoded with 1 byte for the prefix, then 4 bytes of address.
1888 * - IPv6 prefixes are decoded with 1 byte for the scope_id, 1 byte for the prefix,
1889 * and 16 bytes of address.
1890 * - Floats are decoded in IEEE-754 format with a big-endian byte order. We rely
1891 * on the fact that the C standards require floats to be represented in IEEE-754
1892 * format in memory.
1893 * - Dates are decoded as 32bit unsigned UNIX timestamps.
1894 *
1895 * All of the dictionary rules are respected. string/octets can have
1896 * a fixed length, or can have an 8/16-bit "length" prefix. If the
1897 * enumv is not an array, then the input # len MUST be the correct size
1898 * (not too large or small), otherwise an error is returned.
1899 *
1900 * If the enumv is an array, then the input must have the minimum
1901 * length, and the number of bytes decoded is capped at the maximum
1902 * length allowed to be decoded. This behavior allows the caller to
1903 * decode an array of values simply by calling this function in a
1904 * loop.
1905 *
1906 * @param[in] ctx Where to allocate any talloc buffers required.
1907 * @param[out] dst value_box to write the result to.
1908 * @param[in] type to decode data to.
1909 * @param[in] enumv Aliases for values.
1910 * @param[in] dbuff Binary data to decode.
1911 * @param[in] len Length of data to decode. For fixed length types we only
1912 * decode complete values.
1913 * @param[in] tainted Whether the value came from a trusted source.
1914 * @return
1915 * - >= 0 The number of bytes consumed.
1916 * - <0 - The negative offset where the error occurred.
1917 * - FR_VALUE_BOX_NET_OOM (negative value) - Out of memory.
1918 */
1920 fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv,
1921 fr_dbuff_t *dbuff, size_t len,
1922 bool tainted)
1923{
1924 size_t min, max;
1925 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1926
1928 max = network_max_size(type);
1929
1930 fr_assert(max > 0);
1931
1932 if (len < min) {
1933 fr_strerror_printf("Got truncated value parsing type \"%s\". "
1934 "Expected length >= %zu bytes, got %zu bytes",
1936 min, len);
1937 return -(len);
1938 }
1939
1940 /*
1941 * For array entries, we only decode one value at a time.
1942 */
1943 if (len > max) {
1944 if (enumv && !enumv->flags.array) {
1945 fr_strerror_printf("Found trailing garbage parsing type \"%s\". "
1946 "Expected length <= %zu bytes, got %zu bytes",
1948 max, len);
1949 return -(max);
1950 }
1951
1952 len = max;
1953 }
1954
1955 /*
1956 * String / octets are special.
1957 */
1959 size_t newlen = len;
1960 size_t offset = 0;
1961
1962 /*
1963 * Decode fixed-width fields.
1964 */
1965 if (enumv) {
1966 if (enumv->flags.length) {
1967 newlen = enumv->flags.length;
1968
1969 } else if (da_is_length_field(enumv)) {
1970 /*
1971 * Or fields with a length prefix.
1972 */
1973 if (enumv->flags.subtype == FLAG_LENGTH_UINT8) {
1974 uint8_t num = 0;
1975
1976 FR_DBUFF_OUT_RETURN(&num, &work_dbuff);
1977 newlen = num;
1978 offset = 1;
1979
1980 } else if (enumv->flags.subtype == FLAG_LENGTH_UINT16) {
1981 uint16_t num = 0;
1982
1983 FR_DBUFF_OUT_RETURN(&num, &work_dbuff);
1984 newlen = num;
1985 offset = 2;
1986
1987 } else {
1988 return -1;
1989 }
1990 }
1991 }
1992
1993 /*
1994 * If we need more data than exists, that's an error.
1995 *
1996 * Otherwise, bound the decoding to the count we found.
1997 */
1998 if (newlen > len) return -(newlen + offset);
1999 len = newlen;
2000
2001 switch (type) {
2002 case FR_TYPE_STRING:
2003 if (fr_value_box_bstrndup_dbuff(ctx, dst, enumv, &work_dbuff, len, tainted) < 0) {
2004 return FR_VALUE_BOX_NET_OOM;
2005 }
2006 return fr_dbuff_set(dbuff, &work_dbuff);
2007
2008 case FR_TYPE_OCTETS:
2009 if (fr_value_box_memdup_dbuff(ctx, dst, enumv, &work_dbuff, len, tainted) < 0) {
2010 return FR_VALUE_BOX_NET_OOM;
2011 }
2012 return fr_dbuff_set(dbuff, &work_dbuff);
2013
2014 default:
2015 return -1;
2016 }
2017 }
2018
2019 /*
2020 * Pre-Initialise box for non-variable types
2021 */
2022 fr_value_box_init(dst, type, enumv, tainted);
2023 switch (type) {
2024 /*
2025 * Already in network byte order
2026 */
2027 case FR_TYPE_IPV4_ADDR:
2028 ipv4addr:
2029 dst->vb_ip = (fr_ipaddr_t){
2030 .af = AF_INET,
2031 .prefix = 32,
2032 };
2033 FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *)&dst->vb_ip.addr.v4, &work_dbuff, len);
2034 break;
2035
2037 ipv4prefix:
2038 dst->vb_ip = (fr_ipaddr_t){
2039 .af = AF_INET,
2040 };
2041 FR_DBUFF_OUT_RETURN(&dst->vb_ip.prefix, &work_dbuff);
2042 FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *)&dst->vb_ip.addr.v4, &work_dbuff, len - 1);
2043 break;
2044
2045 case FR_TYPE_IPV6_ADDR:
2046 ipv6addr:
2047 dst->vb_ip = (fr_ipaddr_t){
2048 .af = AF_INET6,
2049 .scope_id = 0,
2050 .prefix = 128
2051 };
2052 if (len == max) {
2053 uint8_t scope_id = 0;
2054
2055 FR_DBUFF_OUT_RETURN(&scope_id, &work_dbuff);
2056 dst->vb_ip.scope_id = scope_id;
2057 len--;
2058 }
2059 FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *)&dst->vb_ip.addr.v6, &work_dbuff, len);
2060 break;
2061
2063 ipv6prefix:
2064 dst->vb_ip = (fr_ipaddr_t){
2065 .af = AF_INET6,
2066 .scope_id = 0,
2067 };
2068 if (len == max) {
2069 uint8_t scope_id = 0;
2070
2071 FR_DBUFF_OUT_RETURN(&scope_id, &work_dbuff);
2072 dst->vb_ip.scope_id = scope_id;
2073 len--;
2074 }
2075 FR_DBUFF_OUT_RETURN(&dst->vb_ip.prefix, &work_dbuff);
2076 FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *)&dst->vb_ip.addr.v6, &work_dbuff, len - 1);
2077 break;
2078
2080 if ((len >= network_min_size(FR_TYPE_IPV6_ADDR)) &&
2081 (len <= network_max_size(FR_TYPE_IPV6_ADDR))) goto ipv6addr; /* scope is optional */
2082 else if ((len >= network_min_size(FR_TYPE_IPV4_ADDR)) &&
2083 (len <= network_max_size(FR_TYPE_IPV4_ADDR))) goto ipv4addr;
2084 fr_strerror_const("Invalid combo ip address value");
2085 return 0;
2086
2088 if ((len >= network_min_size(FR_TYPE_IPV6_PREFIX)) &&
2089 (len <= network_max_size(FR_TYPE_IPV6_PREFIX))) goto ipv6prefix; /* scope is optional */
2090 else if ((len >= network_min_size(FR_TYPE_IPV4_PREFIX)) &&
2091 (len <= network_max_size(FR_TYPE_IPV4_PREFIX))) goto ipv4prefix;
2092 fr_strerror_const("Invalid combo ip prefix value");
2093 return 0;
2094
2095 case FR_TYPE_BOOL:
2096 {
2097 uint8_t val = 0;
2098
2099 FR_DBUFF_OUT_RETURN(&val, &work_dbuff);
2100 dst->datum.boolean = (val != 0);
2101 }
2102 break;
2103
2104 case FR_TYPE_IFID:
2105 case FR_TYPE_ETHERNET:
2106 FR_DBUFF_OUT_MEMCPY_RETURN(fr_value_box_raw(dst, type), &work_dbuff, len);
2107 break;
2108
2109 case FR_TYPE_UINT8:
2110 FR_DBUFF_OUT_RETURN(&dst->vb_uint8, &work_dbuff);
2111 break;
2112
2113 case FR_TYPE_UINT16:
2114 FR_DBUFF_OUT_RETURN(&dst->vb_uint16, &work_dbuff);
2115 break;
2116
2117 case FR_TYPE_UINT32:
2118 FR_DBUFF_OUT_RETURN(&dst->vb_uint32, &work_dbuff);
2119 break;
2120
2121 case FR_TYPE_UINT64:
2122 FR_DBUFF_OUT_RETURN(&dst->vb_uint64, &work_dbuff);
2123 break;
2124
2125 case FR_TYPE_INT8:
2126 FR_DBUFF_OUT_RETURN(&dst->vb_int8, &work_dbuff);
2127 break;
2128
2129 case FR_TYPE_INT16:
2130 FR_DBUFF_OUT_RETURN(&dst->vb_int16, &work_dbuff);
2131 break;
2132
2133 case FR_TYPE_INT32:
2134 FR_DBUFF_OUT_RETURN(&dst->vb_int32, &work_dbuff);
2135 break;
2136
2137 case FR_TYPE_INT64:
2138 FR_DBUFF_OUT_RETURN(&dst->vb_int64, &work_dbuff);
2139 break;
2140
2141 case FR_TYPE_FLOAT32:
2142 FR_DBUFF_OUT_RETURN(&dst->vb_float32, &work_dbuff);
2143 break;
2144
2145 case FR_TYPE_FLOAT64:
2146 FR_DBUFF_OUT_RETURN(&dst->vb_float64, &work_dbuff);
2147 break;
2148
2149 case FR_TYPE_ATTR:
2150 if (!enumv) {
2151 fr_strerror_const("No enumv (i.e. root) passed to fr_value_box_from_network for type 'attribute'");
2152 return 0;
2153 }
2154
2155 /*
2156 * Decode the number, and see if we can create a
2157 * matching attribute.
2158 */
2159 {
2160 unsigned int num;
2161 uint8_t num8;
2162 uint16_t num16;
2163 uint32_t num32;
2164
2165 switch (enumv->flags.length) {
2166 case 1:
2167 FR_DBUFF_OUT_RETURN(&num8, &work_dbuff);
2168 num = num8;
2169 break;
2170
2171 case 2:
2172 FR_DBUFF_OUT_RETURN(&num16, &work_dbuff);
2173 num = num16;
2174 break;
2175
2176 case 4:
2177 FR_DBUFF_OUT_RETURN(&num32, &work_dbuff);
2178 num = num32;
2179 break;
2180
2181 default:
2182 fr_strerror_const("Unsupported parent length");
2183 return 0;
2184 }
2185
2186 dst->vb_attr = fr_dict_attr_child_by_num(enumv, num);
2187 if (!dst->vb_attr) {
2188 dst->vb_attr = fr_dict_attr_unknown_raw_afrom_num(ctx, enumv, num);
2189 if (!dst->vb_attr) return 0;
2190 }
2191
2192 break;
2193 }
2194
2195 /*
2196 * Dates and deltas are stored internally as
2197 * 64-bit nanoseconds. We have to convert from
2198 * the network format. First by size
2199 * (16/32/64-bit), and then by resolution (ns,
2200 * us, ms, s).
2201 */
2202 case FR_TYPE_DATE:
2203 {
2204 size_t length = 4;
2205 fr_time_res_t precision = FR_TIME_RES_SEC;
2206 uint64_t date;
2207
2208 if (enumv) {
2209 length = enumv->flags.length;
2210 precision = (fr_time_res_t)enumv->flags.flag_time_res;
2211 }
2212
2213 /*
2214 * Input data doesn't match what we were told we
2215 * need.
2216 */
2217 if (len > length) return -(length);
2218
2219 dst->enumv = enumv;
2220
2221 FR_DBUFF_OUT_UINT64V_RETURN(&date, &work_dbuff, length);
2222
2223 if (!fr_multiply(&date, date, fr_time_multiplier_by_res[precision])) {
2224 fr_strerror_const("date would overflow");
2225 return 0;
2226 }
2227
2228 dst->vb_date = fr_unix_time_wrap(date);
2229 }
2230 break;
2231
2232 case FR_TYPE_TIME_DELTA:
2233 {
2234 size_t length = 4;
2235 fr_time_res_t precision = FR_TIME_RES_SEC;
2236 int64_t date;
2237
2238 if (enumv) {
2239 length = enumv->flags.length;
2240 precision = (fr_time_res_t)enumv->flags.flag_time_res;
2241 }
2242
2243 /*
2244 * Input data doesn't match what we were told we
2245 * need.
2246 */
2247 if (len > length) return -(length);
2248
2249 dst->enumv = enumv;
2250
2251 if (!enumv || !enumv->flags.is_unsigned) {
2252 FR_DBUFF_OUT_INT64V_RETURN(&date, &work_dbuff, length);
2253 } else {
2254 uint64_t tmp;
2255
2256 /*
2257 * Else it's an unsigned time delta, but
2258 * we do have to clamp it at the max
2259 * value for a signed 64-bit integer.
2260 */
2261 FR_DBUFF_OUT_UINT64V_RETURN(&tmp, &work_dbuff, length);
2262
2263 if (tmp > INT64_MAX) tmp = INT64_MAX;
2264
2265 date = tmp;
2266 }
2267
2268 dst->vb_time_delta = fr_time_delta_wrap(fr_time_scale(date, precision));
2269 }
2270 break;
2271
2272 case FR_TYPE_STRING:
2273 case FR_TYPE_OCTETS:
2274 break; /* Already dealt with */
2275
2276 case FR_TYPE_SIZE:
2277 case FR_TYPE_NON_LEAF:
2278 fr_strerror_printf("Cannot decode type \"%s\" - Is not a value",
2280 break;
2281 }
2282
2283 return fr_dbuff_set(dbuff, &work_dbuff);
2284}
2285
2286/** Get a key from a value box
2287 *
2288 * @param[in,out] out - set to a small buffer on input. If the callback has more data
2289 * than is available here, the callback can update "out" to point elsewhere
2290 * @param[in,out] outlen The number of bits available in the initial buffer. On output,
2291 * the number of bits available in the key
2292 * @param[in] value the value box which contains the key
2293 * @return
2294 * - <0 on error
2295 * - 0 on success
2296 */
2298{
2299 ssize_t slen;
2300 fr_dbuff_t dbuff;
2301
2302 switch (value->type) {
2303 case FR_TYPE_BOOL:
2304 if (*outlen < 8) return -1;
2305
2306 *out[0] = (value->vb_bool) << 7;
2307 *outlen = 1;
2308 break;
2309
2311 if (*outlen < (fr_value_box_network_sizes[value->type][1] * 8)) return -1;
2312
2313 /*
2314 * Integers are put into network byte order.
2315 */
2316 fr_dbuff_init(&dbuff, *out, *outlen >> 3);
2317
2318 slen = fr_value_box_to_network(&dbuff, value);
2319 if (slen < 0) return -1;
2320 *outlen = slen * 8; /* bits not bytes */
2321 break;
2322
2323 case FR_TYPE_IP:
2324 /*
2325 * IPs are already in network byte order.
2326 */
2327 *out = UNCONST(uint8_t *, &value->vb_ip.addr);
2328 *outlen = value->vb_ip.prefix;
2329 break;
2330
2331 case FR_TYPE_STRING:
2332 case FR_TYPE_OCTETS:
2333 *out = value->datum.ptr;
2334 *outlen = value->vb_length * 8;
2335 break;
2336
2337 case FR_TYPE_ETHERNET:
2338 *out = UNCONST(uint8_t *, &value->vb_ether[0]);
2339 *outlen = sizeof(value->vb_ether) * 8;
2340 break;
2341
2342 default:
2343 fr_strerror_printf("Invalid data type '%s' for getting key",
2344 fr_type_to_str(value->type));
2345 return -1;
2346 }
2347
2348 return 0;
2349}
2350
2351/** Convert octets to a fixed size value box value
2352 *
2353 * All fixed size types are allowed.
2354 *
2355 * @param dst Where to write result of casting.
2356 * @param dst_type to cast to.
2357 * @param dst_enumv enumeration values.
2358 * @param src Input data.
2359 */
2361 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2362 fr_value_box_t const *src)
2363{
2364 uint8_t *ptr;
2365
2366 if (!fr_type_is_fixed_size(dst_type)) if (!fr_cond_assert(false)) return -1;
2367
2368 if (src->vb_length > network_max_size(dst_type)) {
2369 fr_strerror_printf("Invalid cast from %s to %s. Source length %zu is greater than "
2370 "destination type size %zu",
2371 fr_type_to_str(src->type),
2372 fr_type_to_str(dst_type),
2373 src->vb_length,
2374 network_max_size(dst_type));
2375 return -1;
2376 }
2377
2378 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2379
2380 /*
2381 * No data to copy means just reset it to zero.
2382 */
2383 if (!src->vb_length) return 0;
2384
2385 ptr = (uint8_t *) &dst->datum;
2386
2387 /*
2388 * If the source is too small, just left-fill with zeroes.
2389 */
2390 if (src->vb_length < network_min_size(dst_type)) {
2391 ptr += network_min_size(dst_type) - src->vb_length;
2392 }
2393
2394 /*
2395 * Copy the raw octets into the datum of a value_box
2396 * inverting bytesex for uint32s (if LE).
2397 */
2398 memcpy(ptr, src->vb_octets, src->vb_length);
2399 fr_value_box_hton(dst, dst);
2400
2401 return 0;
2402}
2403
2404/** v4 to v6 mapping prefix
2405 *
2406 * Part of the IPv6 range is allocated to represent IPv4 addresses.
2407 */
2408static uint8_t const v4_v6_map[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2409 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
2410
2411
2412/** Convert any supported type to a string
2413 *
2414 * All non-structural types are allowed.
2415 *
2416 * @param ctx unused.
2417 * @param dst Where to write result of casting.
2418 * @param dst_type to cast to.
2419 * @param dst_enumv enumeration values.
2420 * @param src Input data.
2421 */
2422static inline int fr_value_box_cast_to_strvalue(TALLOC_CTX *ctx, fr_value_box_t *dst,
2423 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2424 fr_value_box_t const *src)
2425{
2426 if (!fr_cond_assert(dst_type == FR_TYPE_STRING)) return -1;
2427
2428 fr_value_box_init(dst, FR_TYPE_STRING, dst_enumv, false);
2429
2430 switch (src->type) {
2431 /*
2432 * The presentation format of octets is hex
2433 * What we actually want here is the raw string
2434 */
2435 case FR_TYPE_OCTETS:
2436 fr_value_box_safety_copy(dst, src);
2437 return fr_value_box_bstrndup(ctx, dst, dst_enumv,
2438 (char const *)src->vb_octets, src->vb_length, src->tainted);
2439
2440 case FR_TYPE_GROUP:
2442 dst, UNCONST(fr_value_box_list_t *, &src->vb_group),
2445 SIZE_MAX);
2446
2447 /*
2448 * Get the presentation format
2449 */
2450 default:
2451 {
2452 char *str;
2453
2454 fr_value_box_aprint(ctx, &str, src, NULL);
2455 if (unlikely(!str)) return -1;
2456
2458 return fr_value_box_bstrdup_buffer_shallow(NULL, dst, dst_enumv, str, src->tainted);
2459 }
2460 }
2461}
2462
2463/** Convert any supported type to octets
2464 *
2465 * All non-structural types are allowed.
2466 *
2467 * @param ctx unused.
2468 * @param dst Where to write result of casting.
2469 * @param dst_type to cast to.
2470 * @param dst_enumv enumeration values.
2471 * @param src Input data.
2472 */
2473static inline int fr_value_box_cast_to_octets(TALLOC_CTX *ctx, fr_value_box_t *dst,
2474 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2475 fr_value_box_t const *src)
2476{
2477 if (!fr_cond_assert(dst_type == FR_TYPE_OCTETS)) return -1;
2478
2479 fr_value_box_init(dst, FR_TYPE_OCTETS, dst_enumv, false);
2481
2482 switch (src->type) {
2483 /*
2484 * <string> (excluding terminating \0)
2485 */
2486 case FR_TYPE_STRING:
2487 fr_value_box_safety_copy(dst, src);
2488 return fr_value_box_memdup(ctx, dst, dst_enumv,
2489 (uint8_t const *)src->vb_strvalue, src->vb_length, src->tainted);
2490
2491 case FR_TYPE_GROUP:
2493 dst, UNCONST(fr_value_box_list_t *, &src->vb_group),
2496 SIZE_MAX);
2497 /*
2498 * <4 bytes address>
2499 */
2500 case FR_TYPE_IPV4_ADDR:
2501 return fr_value_box_memdup(ctx, dst, dst_enumv,
2502 (uint8_t const *)&src->vb_ip.addr.v4.s_addr,
2503 sizeof(src->vb_ip.addr.v4.s_addr), src->tainted);
2504
2505 /*
2506 * <1 uint8 prefix> + <4 bytes address>
2507 */
2509 {
2510 uint8_t *bin;
2511
2512 if (fr_value_box_mem_alloc(ctx, &bin, dst, dst_enumv,
2513 sizeof(src->vb_ip.addr.v4.s_addr) + 1, src->tainted) < 0) return -1;
2514
2515 bin[0] = src->vb_ip.prefix;
2516 memcpy(&bin[1], (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2517 }
2518 return 0;
2519
2520 /*
2521 * <16 bytes address>
2522 */
2523 case FR_TYPE_IPV6_ADDR:
2524 return fr_value_box_memdup(ctx, dst, dst_enumv,
2525 (uint8_t const *)src->vb_ip.addr.v6.s6_addr,
2526 sizeof(src->vb_ip.addr.v6.s6_addr), src->tainted);
2527
2528 /*
2529 * <1 uint8 prefix> + <1 uint8 scope> + <16 bytes address>
2530 */
2532 {
2533 uint8_t *bin;
2534
2535 if (fr_value_box_mem_alloc(ctx, &bin, dst, dst_enumv,
2536 sizeof(src->vb_ip.addr.v6.s6_addr) + 2, src->tainted) < 0) return -1;
2537 bin[0] = src->vb_ip.scope_id;
2538 bin[1] = src->vb_ip.prefix;
2539 memcpy(&bin[2], src->vb_ip.addr.v6.s6_addr, sizeof(src->vb_ip.addr.v6.s6_addr));
2540 }
2541 return 0;
2542
2543 /*
2544 * Get the raw binary in memory representation
2545 */
2546 case FR_TYPE_NUMERIC:
2547 {
2548 fr_value_box_t tmp;
2549
2550 fr_value_box_hton(&tmp, src); /* Flip any numeric representations */
2551 return fr_value_box_memdup(ctx, dst, dst_enumv,
2552 fr_value_box_raw(&tmp, src->type),
2553 fr_value_box_field_sizes[src->type], src->tainted);
2554 }
2555
2556 case FR_TYPE_TLV:
2557 case FR_TYPE_STRUCT:
2558 case FR_TYPE_VSA:
2559 case FR_TYPE_VENDOR:
2560 case FR_TYPE_UNION:
2561 case FR_TYPE_INTERNAL:
2562 case FR_TYPE_NULL:
2563 case FR_TYPE_ATTR:
2564 case FR_TYPE_COMBO_IP_ADDR: /* the types should have been realized to ipv4 / ipv6 */
2566 case FR_TYPE_OCTETS: /* handled above*/
2567 break;
2568
2569
2570 /* Not the same talloc_memdup call as above. The above memdup reads data from the dst */
2571 case FR_TYPE_IFID:
2572 case FR_TYPE_ETHERNET:
2573 return fr_value_box_memdup(ctx, dst, dst_enumv,
2574 fr_value_box_raw(src, src->type),
2575 fr_value_box_field_sizes[src->type], src->tainted);
2576 }
2577
2578 fr_assert(0);
2579 return -1;
2580}
2581
2582#define CAST_IP_FIX_COMBO \
2583 case FR_TYPE_COMBO_IP_ADDR: \
2584 if (src->vb_ip.af == AF_INET) { \
2585 src_type = FR_TYPE_IPV4_ADDR; \
2586 } else if (src->vb_ip.af == AF_INET6) { \
2587 src_type = FR_TYPE_IPV6_ADDR; \
2588 } \
2589 break; \
2590 case FR_TYPE_COMBO_IP_PREFIX: \
2591 if (src->vb_ip.af == AF_INET) { \
2592 src_type = FR_TYPE_IPV4_PREFIX; \
2593 } else if (src->vb_ip.af == AF_INET6) { \
2594 src_type = FR_TYPE_IPV6_PREFIX; \
2595 } \
2596 break
2597
2598
2600{
2601 fr_strerror_printf("Invalid cast from %s to %s. Unsupported",
2602 fr_type_to_str(src),
2603 fr_type_to_str(dst));
2604 return -1;
2605}
2606
2607
2608/** Convert any supported type to an IPv4 address
2609 *
2610 * Allowed input types are:
2611 * - FR_TYPE_IPV6_ADDR (with v4 prefix).
2612 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2613 * - FR_TYPE_IPV6_PREFIX (with v4 prefix and 128bit mask).
2614 * - FR_TYPE_OCTETS (of length 4).
2615 * - FR_TYPE_UINT32
2616 *
2617 * @param ctx unused.
2618 * @param dst Where to write result of casting.
2619 * @param dst_type to cast to.
2620 * @param dst_enumv enumeration values.
2621 * @param src Input data.
2622 */
2623static inline int fr_value_box_cast_to_ipv4addr(TALLOC_CTX *ctx, fr_value_box_t *dst,
2624 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2625 fr_value_box_t const *src)
2626{
2627 fr_type_t src_type = src->type;
2628
2629 fr_assert(dst_type == FR_TYPE_IPV4_ADDR);
2631
2632 switch (src_type) {
2633 case FR_TYPE_STRING:
2634 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2635 src->vb_strvalue, src->vb_length,
2636 NULL);
2637
2639
2640 default:
2641 break;
2642 }
2643
2644 /*
2645 * Pre-initialise box for non-variable types
2646 */
2647 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2648 dst->vb_ip.af = AF_INET;
2649 dst->vb_ip.prefix = 32;
2650 dst->vb_ip.scope_id = 0;
2651
2652 switch (src_type) {
2653 case FR_TYPE_IPV6_ADDR:
2654 if (memcmp(src->vb_ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
2655 bad_v6_prefix_map:
2656 fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
2657 fr_type_to_str(src->type),
2658 fr_type_to_str(dst_type));
2659 return -1;
2660 }
2661
2662 memcpy(&dst->vb_ip.addr.v4, &src->vb_ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
2663 sizeof(dst->vb_ip.addr.v4));
2664
2665 break;
2666
2668 if (src->vb_ip.prefix != 32) {
2669 fr_strerror_printf("Invalid cast from %s to %s. Only /32 (not %i/) prefixes may be "
2670 "cast to IP address types",
2671 fr_type_to_str(src->type),
2672 fr_type_to_str(dst_type),
2673 src->vb_ip.prefix);
2674 return -1;
2675 }
2677
2678 case FR_TYPE_IPV4_ADDR: /* Needed for handling combo addresses */
2679 memcpy(&dst->vb_ip.addr.v4, &src->vb_ip.addr.v4, sizeof(dst->vb_ip.addr.v4));
2680 break;
2681
2683 if (src->vb_ip.prefix != 128) {
2684 fr_strerror_printf("Invalid cast from %s to %s. Only /128 (not /%i) prefixes may be "
2685 "cast to IP address types",
2686 fr_type_to_str(src->type),
2687 fr_type_to_str(dst_type),
2688 src->vb_ip.prefix);
2689 return -1;
2690 }
2691 if (memcmp(&src->vb_ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) goto bad_v6_prefix_map;
2692 memcpy(&dst->vb_ip.addr.v4, &src->vb_ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
2693 sizeof(dst->vb_ip.addr.v4));
2694 break;
2695
2696 case FR_TYPE_OCTETS:
2697 if (src->vb_length != sizeof(dst->vb_ip.addr.v4.s_addr)) {
2698 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2699 fr_type_to_str(src->type),
2700 fr_type_to_str(dst_type),
2701 sizeof(dst->vb_ip.addr.v4.s_addr), src->vb_length);
2702 return -1;
2703 }
2704 memcpy(&dst->vb_ip.addr.v4, src->vb_octets, sizeof(dst->vb_ip.addr.v4.s_addr));
2705 break;
2706
2707 case FR_TYPE_UINT32:
2708 {
2709 uint32_t net;
2710
2711 net = ntohl(src->vb_uint32);
2712 memcpy(&dst->vb_ip.addr.v4, (uint8_t *)&net, sizeof(dst->vb_ip.addr.v4.s_addr));
2713 }
2714 break;
2715
2716 default:
2717 return fr_value_box_cast_unsupported(dst_type, src->type);
2718 }
2719
2720 return 0;
2721}
2722
2723/** Convert any supported type to an IPv6 address
2724 *
2725 * Allowed input types are:
2726 * - FR_TYPE_IPV4_ADDR
2727 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2728 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
2729 * - FR_TYPE_OCTETS (of length 16).
2730 *
2731 * @param ctx unused.
2732 * @param dst Where to write result of casting.
2733 * @param dst_type to cast to.
2734 * @param dst_enumv enumeration values.
2735 * @param src Input data.
2736 */
2737static inline int fr_value_box_cast_to_ipv4prefix(TALLOC_CTX *ctx, fr_value_box_t *dst,
2738 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2739 fr_value_box_t const *src)
2740{
2741 fr_type_t src_type = src->type;
2742
2743 fr_assert(dst_type == FR_TYPE_IPV4_PREFIX);
2745
2746 switch (src_type) {
2747 case FR_TYPE_STRING:
2748 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2749 src->vb_strvalue, src->vb_length,
2750 NULL);
2751
2753
2754 default:
2755 break;
2756 }
2757
2758 /*
2759 * Pre-initialise box for non-variable types
2760 */
2761 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2762 dst->vb_ip.af = AF_INET;
2763 dst->vb_ip.scope_id = 0;
2764
2765 switch (src_type) {
2766 case FR_TYPE_IPV4_PREFIX: /* Needed for handling combo prefixes */
2767 dst->vb_ip.prefix = src->vb_ip.prefix;
2769
2770 case FR_TYPE_IPV4_ADDR:
2771 memcpy(&dst->vb_ip, &src->vb_ip, sizeof(dst->vb_ip));
2772 break;
2773
2774 /*
2775 * Copy the last four bytes, to make an IPv4prefix
2776 */
2777 case FR_TYPE_IPV6_ADDR:
2778 if (memcmp(src->vb_ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
2779 bad_v6_prefix_map:
2780 fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
2781 fr_type_to_str(src->type),
2782 fr_type_to_str(dst_type));
2783 return -1;
2784 }
2785 memcpy(&dst->vb_ip.addr.v4.s_addr, &src->vb_ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
2786 sizeof(dst->vb_ip.addr.v4.s_addr));
2787 dst->vb_ip.prefix = 32;
2788 break;
2789
2791 if (memcmp(src->vb_ip.addr.v6.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) goto bad_v6_prefix_map;
2792
2793 if (src->vb_ip.prefix < (sizeof(v4_v6_map) << 3)) {
2794 fr_strerror_printf("Invalid cast from %s to %s. Expected prefix >= %u bits got %u bits",
2795 fr_type_to_str(src->type),
2796 fr_type_to_str(dst_type),
2797 (unsigned int)(sizeof(v4_v6_map) << 3), src->vb_ip.prefix);
2798 return -1;
2799 }
2800 memcpy(&dst->vb_ip.addr.v4.s_addr, &src->vb_ip.addr.v6.s6_addr[sizeof(v4_v6_map)],
2801 sizeof(dst->vb_ip.addr.v4.s_addr));
2802
2803 /*
2804 * Subtract the bits used by the v4_v6_map to get the v4 prefix bits
2805 */
2806 dst->vb_ip.prefix = src->vb_ip.prefix - (sizeof(v4_v6_map) << 3);
2807 break;
2808
2809 case FR_TYPE_OCTETS:
2810 if (src->vb_length != sizeof(dst->vb_ip.addr.v4.s_addr) + 1) {
2811 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2812 fr_type_to_str(src->type),
2813 fr_type_to_str(dst_type),
2814 sizeof(dst->vb_ip.addr.v4.s_addr) + 1, src->vb_length);
2815 return -1;
2816 }
2817 dst->vb_ip.prefix = src->vb_octets[0];
2818 memcpy(&dst->vb_ip.addr.v4, &src->vb_octets[1], sizeof(dst->vb_ip.addr.v4.s_addr));
2819 break;
2820
2821 case FR_TYPE_UINT32:
2822 {
2823 uint32_t net;
2824
2825 net = ntohl(src->vb_uint32);
2826 memcpy(&dst->vb_ip.addr.v4, (uint8_t *)&net, sizeof(dst->vb_ip.addr.v4.s_addr));
2827 dst->vb_ip.prefix = 32;
2828 break;
2829 }
2830
2831 default:
2832 return fr_value_box_cast_unsupported(dst_type, src->type);
2833 }
2834
2835 return 0;
2836}
2837
2838/** Convert any supported type to an IPv6 address
2839 *
2840 * Allowed input types are:
2841 * - FR_TYPE_IPV4_ADDR
2842 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2843 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
2844 * - FR_TYPE_OCTETS (of length 16).
2845 *
2846 * @param ctx unused.
2847 * @param dst Where to write result of casting.
2848 * @param dst_type to cast to.
2849 * @param dst_enumv enumeration values.
2850 * @param src Input data.
2851 */
2852static inline int fr_value_box_cast_to_ipv6addr(TALLOC_CTX *ctx, fr_value_box_t *dst,
2853 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2854 fr_value_box_t const *src)
2855{
2856 fr_type_t src_type = src->type;
2857
2858 static_assert((sizeof(v4_v6_map) + sizeof(src->vb_ip.addr.v4)) <=
2859 sizeof(src->vb_ip.addr.v6), "IPv6 storage too small");
2860
2861 fr_assert(dst_type == FR_TYPE_IPV6_ADDR);
2863
2864 switch (src_type) {
2865 case FR_TYPE_STRING:
2866 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2867 src->vb_strvalue, src->vb_length,
2868 NULL);
2869
2871
2872 default:
2873 break;
2874 }
2875
2876 /*
2877 * Pre-initialise box for non-variable types
2878 */
2879 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2880 dst->vb_ip.af = AF_INET6;
2881 dst->vb_ip.prefix = 128;
2882
2883 switch (src_type) {
2884 case FR_TYPE_IPV4_ADDR:
2885 {
2886 uint8_t *p = dst->vb_ip.addr.v6.s6_addr;
2887
2888 /* Add the v4/v6 mapping prefix */
2889 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
2890 p += sizeof(v4_v6_map);
2891 memcpy(p, (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2892 dst->vb_ip.scope_id = 0;
2893 }
2894 break;
2895
2897 {
2898 uint8_t *p = dst->vb_ip.addr.v6.s6_addr;
2899
2900 if (src->vb_ip.prefix != 32) {
2901 fr_strerror_printf("Invalid cast from %s to %s. Only /32 (not /%i) prefixes may be "
2902 "cast to IP address types",
2903 fr_type_to_str(src->type),
2904 fr_type_to_str(dst_type),
2905 src->vb_ip.prefix);
2906 return -1;
2907 }
2908
2909 /* Add the v4/v6 mapping prefix */
2910 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
2911 p += sizeof(v4_v6_map);
2912 memcpy(p, (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
2913 dst->vb_ip.scope_id = 0;
2914 }
2915 break;
2916
2918 if (src->vb_ip.prefix != 128) {
2919 fr_strerror_printf("Invalid cast from %s to %s. Only /128 (not /%i) prefixes may be "
2920 "cast to IP address types",
2921 fr_type_to_str(src->type),
2922 fr_type_to_str(dst_type),
2923 src->vb_ip.prefix);
2924 return -1;
2925 }
2927
2928 case FR_TYPE_IPV6_ADDR: /* Needed for handling combo addresses */
2929 memcpy(dst->vb_ip.addr.v6.s6_addr, src->vb_ip.addr.v6.s6_addr,
2930 sizeof(dst->vb_ip.addr.v6.s6_addr));
2931 dst->vb_ip.scope_id = src->vb_ip.scope_id;
2932 break;
2933
2934 case FR_TYPE_OCTETS:
2935 if (src->vb_length != sizeof(dst->vb_ip.addr.v6.s6_addr)) {
2936 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
2937 fr_type_to_str(src->type),
2938 fr_type_to_str(dst_type),
2939 sizeof(dst->vb_ip.addr.v6.s6_addr), src->vb_length);
2940 return -1;
2941 }
2942 memcpy(&dst->vb_ip.addr.v6.s6_addr, src->vb_octets, sizeof(dst->vb_ip.addr.v6.s6_addr));
2943 break;
2944
2945 default:
2946 return fr_value_box_cast_unsupported(dst_type, src->type);
2947 }
2948
2949 return 0;
2950}
2951
2952/** Convert any supported type to an IPv6 address
2953 *
2954 * Allowed input types are:
2955 * - FR_TYPE_IPV4_ADDR
2956 * - FR_TYPE_IPV4_PREFIX (with 32bit mask).
2957 * - FR_TYPE_IPV6_PREFIX (with 128bit mask).
2958 * - FR_TYPE_OCTETS (of length 16).
2959 *
2960 * @param ctx unused.
2961 * @param dst Where to write result of casting.
2962 * @param dst_type to cast to.
2963 * @param dst_enumv enumeration values.
2964 * @param src Input data.
2965 */
2966static inline int fr_value_box_cast_to_ipv6prefix(TALLOC_CTX *ctx, fr_value_box_t *dst,
2967 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
2968 fr_value_box_t const *src)
2969{
2970 fr_type_t src_type = src->type;
2971
2972 fr_assert(dst_type == FR_TYPE_IPV6_PREFIX);
2974
2975 switch (src_type) {
2976 case FR_TYPE_STRING:
2977 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
2978 src->vb_strvalue, src->vb_length,
2979 NULL);
2980
2982
2983 default:
2984 break;
2985 }
2986
2987 /*
2988 * Pre-initialise box for non-variable types
2989 */
2990 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
2991 dst->vb_ip.af = AF_INET6;
2992
2993 switch (src_type) {
2994 case FR_TYPE_IPV4_ADDR:
2995 {
2996 uint8_t *p = dst->vb_ip.addr.v6.s6_addr;
2997
2998 /* Add the v4/v6 mapping prefix */
2999 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
3000 p += sizeof(v4_v6_map);
3001 memcpy(p, (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
3002 dst->vb_ip.prefix = 128;
3003 dst->vb_ip.scope_id = 0;
3004 }
3005 break;
3006
3008 {
3009 uint8_t *p = dst->vb_ip.addr.v6.s6_addr;
3010
3011 /* Add the v4/v6 mapping prefix */
3012 memcpy(p, v4_v6_map, sizeof(v4_v6_map));
3013 p += sizeof(v4_v6_map);
3014 memcpy(p, (uint8_t const *)&src->vb_ip.addr.v4.s_addr, sizeof(src->vb_ip.addr.v4.s_addr));
3015 dst->vb_ip.prefix = (sizeof(v4_v6_map) << 3) + src->vb_ip.prefix;
3016 dst->vb_ip.scope_id = 0;
3017 }
3018 break;
3019
3020 case FR_TYPE_IPV6_PREFIX: /* Needed for handling combo prefixes */
3021 dst->vb_ip.prefix = src->vb_ip.prefix;
3022 goto v6_common;
3023
3024 case FR_TYPE_IPV6_ADDR:
3025 dst->vb_ip.prefix = 128;
3026 v6_common:
3027 memcpy(dst->vb_ip.addr.v6.s6_addr, src->vb_ip.addr.v6.s6_addr,
3028 sizeof(dst->vb_ip.addr.v6.s6_addr));
3029 dst->vb_ip.scope_id = src->vb_ip.scope_id;
3030 break;
3031
3032 case FR_TYPE_OCTETS:
3033 if (src->vb_length != (sizeof(dst->vb_ip.addr.v6.s6_addr) + 2)) {
3034 fr_strerror_printf("Invalid cast from %s to %s. Needed octet string of length %zu, got %zu",
3035 fr_type_to_str(src->type),
3036 fr_type_to_str(dst_type),
3037 sizeof(dst->vb_ip.addr.v6.s6_addr) + 2, src->vb_length);
3038 return -1;
3039 }
3040 dst->vb_ip.scope_id = src->vb_octets[0];
3041 dst->vb_ip.prefix = src->vb_octets[1];
3042 memcpy(&dst->vb_ip.addr.v6.s6_addr, src->vb_octets, sizeof(dst->vb_ip.addr.v6.s6_addr));
3043 break;
3044
3045 default:
3046 return fr_value_box_cast_unsupported(dst_type, src->type);
3047 }
3048 return 0;
3049}
3050
3051/** Convert any supported type to an ethernet address
3052 *
3053 * Allowed input types are:
3054 * - FR_TYPE_STRING ("00:11:22:33:44:55")
3055 * - FR_TYPE_OCTETS (0x001122334455)
3056 *
3057 *
3058 * @param ctx unused.
3059 * @param dst Where to write result of casting.
3060 * @param dst_type to cast to.
3061 * @param dst_enumv enumeration values.
3062 * @param src Input data.
3063 */
3064static inline int fr_value_box_cast_to_ethernet(TALLOC_CTX *ctx, fr_value_box_t *dst,
3065 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3066 fr_value_box_t const *src)
3067{
3068 fr_assert(dst_type == FR_TYPE_ETHERNET);
3070
3071 switch (src->type) {
3072 case FR_TYPE_STRING:
3073 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3074 src->vb_strvalue, src->vb_length,
3075 NULL);
3076
3077 case FR_TYPE_OCTETS:
3078 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
3079
3080 default:
3081 break;
3082 }
3083
3084 /*
3085 * Pre-initialise box for non-variable types
3086 */
3087 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3088
3089 switch (src->type) {
3090 case FR_TYPE_UINT64: {
3091 uint8_t array[8];
3092
3093 fr_nbo_from_uint64(array, src->vb_uint64);
3094
3095 /*
3096 * For OUIs in the DB.
3097 */
3098 if ((array[0] != 0) || (array[1] != 0)) return -1;
3099
3100 memcpy(dst->vb_ether, &array[2], 6);
3101 break;
3102 }
3103
3104 default:
3105 return fr_value_box_cast_unsupported(dst_type, src->type);
3106 }
3107
3108 return 0;
3109}
3110
3111/** Convert any supported type to a bool
3112 *
3113 * Allowed input types are:
3114 * - FR_TYPE_STRING ("yes", "true", "no", "false")
3115 *
3116 * @param ctx unused.
3117 * @param dst Where to write result of casting.
3118 * @param dst_type to cast to.
3119 * @param dst_enumv enumeration values.
3120 * @param src Input data.
3121 */
3122static inline int fr_value_box_cast_to_bool(TALLOC_CTX *ctx, fr_value_box_t *dst,
3123 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3124 fr_value_box_t const *src)
3125{
3126 fr_assert(dst_type == FR_TYPE_BOOL);
3128
3129 switch (src->type) {
3130 case FR_TYPE_STRING:
3131 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3132 src->vb_strvalue, src->vb_length,
3133 NULL);
3134
3135 case FR_TYPE_OCTETS:
3136 /*
3137 * This is really "bool from network"
3138 */
3139 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
3140
3141 default:
3142 break;
3143 }
3144
3145 /*
3146 * Pre-initialise box for non-variable types
3147 */
3148 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3149
3150 switch (src->type) {
3151 case FR_TYPE_INT8:
3152 dst->vb_bool = (src->vb_int8 != 0);
3153 break;
3154
3155 case FR_TYPE_UINT8:
3156 dst->vb_bool = (src->vb_uint8 != 0);
3157 break;
3158
3159 case FR_TYPE_INT16:
3160 dst->vb_bool = (src->vb_int16 != 0);
3161 break;
3162
3163 case FR_TYPE_UINT16:
3164 dst->vb_bool = (src->vb_uint16 != 0);
3165 break;
3166
3167 case FR_TYPE_INT32:
3168 dst->vb_bool = (src->vb_int32 != 0);
3169 break;
3170
3171 case FR_TYPE_UINT32:
3172 dst->vb_bool = (src->vb_uint32 != 0);
3173 break;
3174
3175 case FR_TYPE_INT64:
3176 dst->vb_bool = (src->vb_int64 != 0);
3177 break;
3178
3179 case FR_TYPE_UINT64:
3180 dst->vb_bool = (src->vb_uint64 != 0);
3181 break;
3182
3183 case FR_TYPE_SIZE:
3184 dst->vb_bool = (src->vb_size != 0);
3185 break;
3186
3187 case FR_TYPE_TIME_DELTA:
3188 dst->vb_bool = (fr_time_delta_unwrap(src->vb_time_delta) != 0);
3189 break;
3190
3191 case FR_TYPE_FLOAT32:
3192 dst->vb_bool = (fpclassify(src->vb_float32) == FP_ZERO);
3193 break;
3194
3195 case FR_TYPE_FLOAT64:
3196 dst->vb_bool = (fpclassify(src->vb_float64) == FP_ZERO);
3197 break;
3198
3199 default:
3200 return fr_value_box_cast_unsupported(dst_type, src->type);
3201 }
3202
3203 return 0;
3204}
3205
3206/** Convert any signed or unsigned integer type to any other signed or unsigned integer type
3207 *
3208 */
3209static inline int fr_value_box_cast_integer_to_integer(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst,
3210 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3211 fr_value_box_t const *src)
3212{
3213 uint64_t tmp = 0;
3214 size_t len = fr_value_box_field_sizes[src->type];
3215 int64_t min;
3216
3218
3219#define SIGN_BIT_HIGH(_int, _len) ((((uint64_t)1) << (((_len) << 3) - 1)) & (_int))
3220#define SIGN_PROMOTE(_int, _len) ((_len) < sizeof(_int) ? \
3221 (_int) | (~((__typeof__(_int))0)) << ((_len) << 3) : (_int))
3222
3223#if !defined(NDEBUG) || defined(STATIC_ANALYZER)
3224 /*
3225 * Helps catch invalid fr_value_box_field_sizes
3226 * entries, and shuts up clang analyzer.
3227 */
3228 if (!fr_cond_assert_msg(len > 0, "Invalid cast from %s to %s. "
3229 "invalid source type len, expected > 0, got %zu",
3230 fr_type_to_str(src->type),
3231 fr_type_to_str(dst_type),
3232 len)) return -1;
3233
3234 if (!fr_cond_assert_msg(len <= sizeof(uint64_t),
3235 "Invalid cast from %s to %s. "
3236 "invalid source type len, expected <= %zu, got %zu",
3237 fr_type_to_str(src->type),
3238 fr_type_to_str(dst_type),
3239 sizeof(uint64_t), len)) return -1;
3240#endif
3241
3242 switch (src->type) {
3243 /*
3244 * Dates are always represented in nanoseconds
3245 * internally, but when we convert to another
3246 * integer type, we scale appropriately.
3247 *
3248 * i.e. if the attribute value resolution is
3249 * seconds, then the integer value is
3250 * nanoseconds -> seconds.
3251 */
3252 case FR_TYPE_DATE:
3253 {
3255 if (src->enumv) res = src->enumv->flags.flag_time_res;
3256
3257 tmp = fr_unix_time_to_integer(src->vb_date, res);
3258 }
3259 break;
3260
3261 /*
3262 * Same deal with time deltas. Note that
3263 * even though we store the value as an
3264 * unsigned integer, it'll be cast to a
3265 * signed integer for comparisons.
3266 */
3267 case FR_TYPE_TIME_DELTA:
3268 {
3270
3271 if (src->enumv) res = src->enumv->flags.flag_time_res;
3272
3273 tmp = (uint64_t)fr_time_delta_to_integer(src->vb_time_delta, res);
3274 }
3275 break;
3276
3277 default:
3278#ifdef WORDS_BIGENDIAN
3279 memcpy(((uint8_t *)&tmp) + (sizeof(tmp) - len),
3280 fr_value_box_raw(src, src->type), len);
3281#else
3282 memcpy(&tmp, fr_value_box_raw(src, src->type), len);
3283#endif
3284 break;
3285 }
3286
3287 min = fr_value_box_integer_min[dst_type];
3288
3289 /*
3290 * Sign promote the input if the source type is
3291 * signed, and the high bit is set.
3292 */
3293 if (fr_value_box_integer_min[src->type] < 0) {
3294 if (SIGN_BIT_HIGH(tmp, len)) tmp = SIGN_PROMOTE(tmp, len);
3295
3296 if ((int64_t)tmp < min) {
3297 fr_strerror_printf("Invalid cast from %s to %s. %"PRId64" "
3298 "outside value range %"PRId64"-%"PRIu64,
3299 fr_type_to_str(src->type),
3300 fr_type_to_str(dst_type),
3301 (int64_t)tmp,
3302 min, fr_value_box_integer_max[dst_type]);
3303 return -1;
3304 }
3305 } else if (tmp > fr_value_box_integer_max[dst_type]) {
3306 fr_strerror_printf("Invalid cast from %s to %s. %"PRIu64" "
3307 "outside value range 0-%"PRIu64,
3308 fr_type_to_str(src->type),
3309 fr_type_to_str(dst_type),
3310 tmp, fr_value_box_integer_max[dst_type]);
3311 return -1;
3312 }
3313
3314 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3315 switch (dst_type) {
3316 case FR_TYPE_DATE:
3317 {
3318 bool overflow;
3320 if (dst->enumv) res = dst->enumv->flags.flag_time_res;
3321
3322 dst->vb_date = fr_unix_time_from_integer(&overflow, tmp, res);
3323 if (overflow) {
3324 fr_strerror_const("Input to date type would overflow");
3325 return -1;
3326 }
3327 }
3328 break;
3329
3330 case FR_TYPE_TIME_DELTA:
3331 {
3332 bool overflow;
3334 if (dst->enumv) res = dst->enumv->flags.flag_time_res;
3335
3336 dst->vb_time_delta = fr_time_delta_from_integer(&overflow, tmp, res);
3337 if (overflow) {
3338 fr_strerror_const("Input to time_delta type would overflow");
3339 return -1;
3340 }
3341 }
3342 break;
3343
3344 default:
3345#ifdef WORDS_BIGENDIAN
3346 memcpy(fr_value_box_raw(dst, dst->type),
3347 ((uint8_t *)&tmp) + (sizeof(tmp) - len), fr_value_box_field_sizes[dst_type]);
3348#else
3349 memcpy(fr_value_box_raw(dst, dst->type),
3350 &tmp, fr_value_box_field_sizes[dst_type]);
3351#endif
3352 break;
3353 }
3354
3355 return 0;
3356}
3357
3358/** Convert any value to a signed or unsigned integer
3359 *
3360 * @param ctx unused.
3361 * @param dst Where to write result of casting.
3362 * @param dst_type to cast to.
3363 * @param dst_enumv enumeration values.
3364 * @param src Input data.
3365 */
3366static inline int fr_value_box_cast_to_integer(TALLOC_CTX *ctx, fr_value_box_t *dst,
3367 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3368 fr_value_box_t const *src)
3369{
3370 switch (src->type) {
3371 case FR_TYPE_STRING:
3372 return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3373 src->vb_strvalue, src->vb_length,
3374 NULL);
3375
3376 case FR_TYPE_OCTETS:
3377 return fr_value_box_fixed_size_from_octets(dst, dst_type, dst_enumv, src);
3378
3379 case FR_TYPE_INTEGER:
3380 fr_value_box_init(dst, dst_type, dst_enumv, false);
3381 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, src);
3382
3383 case FR_TYPE_IPV4_ADDR:
3385 {
3386 fr_value_box_t tmp;
3387
3388 switch (dst_type) {
3389 case FR_TYPE_UINT32:
3390 case FR_TYPE_INT64:
3391 case FR_TYPE_UINT64:
3392 case FR_TYPE_DATE:
3393 case FR_TYPE_TIME_DELTA:
3394 break;
3395
3396 default:
3397 goto bad_cast;
3398 }
3399
3400 fr_value_box_init(&tmp, FR_TYPE_UINT32, src->enumv, src->tainted);
3401 memcpy(&tmp.vb_uint32, &src->vb_ip.addr.v4, sizeof(tmp.vb_uint32));
3402 fr_value_box_hton(&tmp, &tmp);
3403 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, &tmp);
3404 }
3405
3406 case FR_TYPE_ETHERNET:
3407 {
3408 fr_value_box_t tmp;
3409
3410 switch (dst_type) {
3411 case FR_TYPE_INT64:
3412 case FR_TYPE_UINT64:
3413 case FR_TYPE_DATE:
3414 case FR_TYPE_TIME_DELTA:
3415 break;
3416
3417 default:
3418 goto bad_cast;
3419 }
3420
3421 fr_value_box_init(&tmp, FR_TYPE_UINT64, src->enumv, src->tainted);
3422 memcpy(((uint8_t *)&tmp.vb_uint64) + (sizeof(tmp.vb_uint64) - sizeof(src->vb_ether)),
3423 &src->vb_ether, sizeof(src->vb_ether));
3424#ifndef WORDS_BIGENDIAN
3425 /*
3426 * Ethernet addresses are always stored bigendian,
3427 * convert to native on little endian systems
3428 */
3429 fr_value_box_hton(&tmp, &tmp);
3430#endif
3431 return fr_value_box_cast_integer_to_integer(ctx, dst, dst_type, dst_enumv, &tmp);
3432 }
3433
3434 case FR_TYPE_IFID:
3435 {
3436 switch (dst_type) {
3437 case FR_TYPE_UINT64:
3438 break;
3439
3440 default:
3441 goto bad_cast;
3442 }
3443
3444 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3445 dst->vb_uint64 = fr_nbo_to_uint64(&src->vb_ifid[0]);
3446 return 0;
3447 }
3448
3449 case FR_TYPE_FLOAT32:
3450 if (src->vb_float32 < (double) fr_value_box_integer_min[dst_type]) {
3451 underflow:
3452 fr_strerror_const("Source value for cast would underflow destination type");
3453 return -1;
3454 }
3455
3456 if (src->vb_float32 > (double) fr_value_box_integer_max[dst_type]) {
3457 overflow:
3458 fr_strerror_const("Source value for cast would overflow destination type");
3459 return -1;
3460 }
3461
3462 switch (dst_type) {
3463 case FR_TYPE_UINT8:
3464 dst->vb_uint8 = src->vb_float32;
3465 break;
3466
3467 case FR_TYPE_UINT16:
3468 dst->vb_uint16 = src->vb_float32;
3469 break;
3470
3471 case FR_TYPE_UINT32:
3472 dst->vb_uint32 = src->vb_float32;
3473 break;
3474
3475 case FR_TYPE_UINT64:
3476 dst->vb_uint64 = src->vb_float32;
3477 break;
3478
3479 case FR_TYPE_INT8:
3480 dst->vb_int8 = src->vb_float32;
3481 break;
3482
3483 case FR_TYPE_INT16:
3484 dst->vb_int16 = src->vb_float32;
3485 break;
3486
3487 case FR_TYPE_INT32:
3488 dst->vb_int32 = src->vb_float32;
3489 break;
3490
3491 case FR_TYPE_INT64:
3492 dst->vb_int64 = src->vb_float32;
3493 break;
3494
3495 case FR_TYPE_SIZE:
3496 dst->vb_size = src->vb_float32;
3497 break;
3498
3499 case FR_TYPE_DATE: {
3500 int64_t sec, nsec;
3501
3502 sec = src->vb_float32;
3503 sec *= NSEC;
3504 nsec = ((src->vb_float32 * NSEC) - ((float) sec));
3505
3506 dst->vb_date = fr_unix_time_from_nsec(sec + nsec);
3507 }
3508 break;
3509
3510 case FR_TYPE_TIME_DELTA: {
3511 int64_t sec, nsec;
3512 int64_t res = NSEC;
3513 bool fail = false;
3514
3515 if (dst->enumv) res = fr_time_multiplier_by_res[dst->enumv->flags.flag_time_res];
3516
3517 sec = src->vb_float32;
3518 sec *= res;
3519 nsec = ((src->vb_float32 * res) - ((double) sec));
3520
3521 dst->vb_time_delta = fr_time_delta_from_integer(&fail, sec + nsec,
3522 dst->enumv ? dst->enumv->flags.flag_time_res : FR_TIME_RES_NSEC);
3523 if (fail) goto overflow;
3524 }
3525 break;
3526
3527 default:
3528 goto bad_cast;
3529 }
3530 return 0;
3531
3532 case FR_TYPE_FLOAT64:
3533 if (src->vb_float64 < (double) fr_value_box_integer_min[dst_type]) goto underflow;
3534
3535 if (src->vb_float64 > (double) fr_value_box_integer_max[dst_type]) goto overflow;
3536
3537 switch (dst_type) {
3538 case FR_TYPE_UINT8:
3539 dst->vb_uint8 = src->vb_float64;
3540 break;
3541
3542 case FR_TYPE_UINT16:
3543 dst->vb_uint16 = src->vb_float64;
3544 break;
3545
3546 case FR_TYPE_UINT32:
3547 dst->vb_uint32 = src->vb_float64;
3548 break;
3549
3550 case FR_TYPE_UINT64:
3551 dst->vb_uint64 = src->vb_float64;
3552 break;
3553
3554 case FR_TYPE_INT8:
3555 dst->vb_int8 = src->vb_float64;
3556 break;
3557
3558 case FR_TYPE_INT16:
3559 dst->vb_int16 = src->vb_float64;
3560 break;
3561
3562 case FR_TYPE_INT32:
3563 dst->vb_int32 = src->vb_float64;
3564 break;
3565
3566 case FR_TYPE_INT64:
3567 dst->vb_int64 = src->vb_float64;
3568 break;
3569
3570 case FR_TYPE_SIZE:
3571 dst->vb_size = src->vb_float64;
3572 break;
3573
3574 case FR_TYPE_DATE: {
3575 int64_t sec, nsec;
3576
3577 sec = src->vb_float64;
3578 sec *= NSEC;
3579 nsec = ((src->vb_float64 * NSEC) - ((double) sec));
3580
3581 dst->vb_date = fr_unix_time_from_nsec(sec + nsec);
3582 }
3583 break;
3584
3585 case FR_TYPE_TIME_DELTA: {
3586 int64_t sec, nsec;
3587 int64_t res = NSEC;
3588 bool fail = false;
3589
3590 if (dst->enumv) res = fr_time_multiplier_by_res[dst->enumv->flags.flag_time_res];
3591
3592 sec = src->vb_float64;
3593 sec *= res;
3594 nsec = ((src->vb_float64 * res) - ((double) sec));
3595
3596 dst->vb_time_delta = fr_time_delta_from_integer(&fail, sec + nsec,
3597 dst->enumv ? dst->enumv->flags.flag_time_res : FR_TIME_RES_NSEC);
3598 if (fail) goto overflow;
3599 }
3600 break;
3601
3602 default:
3603 goto bad_cast;
3604 }
3605 return 0;
3606
3607 default:
3608 break;
3609 }
3610
3611bad_cast:
3612 return fr_value_box_cast_unsupported(dst_type, src->type);
3613}
3614
3615/** Convert any value to a floating point value
3616 *
3617 * @param ctx unused.
3618 * @param dst Where to write result of casting.
3619 * @param dst_type to cast to.
3620 * @param dst_enumv enumeration values.
3621 * @param src Input data.
3622 */
3623static inline int fr_value_box_cast_to_float(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst,
3624 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3625 fr_value_box_t const *src)
3626{
3627 double num;
3628
3629 switch (src->type) {
3630 case FR_TYPE_FLOAT32:
3631 if (dst_type == FR_TYPE_FLOAT64) {
3632 num = (double) src->vb_float32;
3633 goto good_cast;
3634 }
3635
3636 goto bad_cast;
3637
3638 case FR_TYPE_FLOAT64:
3639 if (dst_type == FR_TYPE_FLOAT32) {
3640 num = src->vb_float64;
3641 goto good_cast;
3642 }
3643
3644 goto bad_cast;
3645
3646 case FR_TYPE_BOOL:
3647 num = src->vb_bool;
3648 goto good_cast;
3649
3650 case FR_TYPE_INT8:
3651 num = src->vb_int8;
3652 goto good_cast;
3653
3654 case FR_TYPE_INT16:
3655 num = src->vb_int16;
3656 goto good_cast;
3657
3658 case FR_TYPE_INT32:
3659 num = src->vb_int32;
3660 goto good_cast;
3661
3662 case FR_TYPE_INT64:
3663 num = src->vb_int64;
3664 goto good_cast;
3665
3666 case FR_TYPE_UINT8:
3667 num = src->vb_uint8;
3668 goto good_cast;
3669
3670 case FR_TYPE_UINT16:
3671 num = src->vb_uint16;
3672 goto good_cast;
3673
3674 case FR_TYPE_UINT32:
3675 num = src->vb_uint32;
3676 goto good_cast;
3677
3678 case FR_TYPE_UINT64:
3679 num = src->vb_uint64;
3680 goto good_cast;
3681
3682 case FR_TYPE_DATE:
3683 /*
3684 * Unix times are in nanoseconds
3685 */
3686 num = fr_unix_time_unwrap(src->vb_date);
3687 num /= NSEC;
3688 goto good_cast;
3689
3690 case FR_TYPE_TIME_DELTA:
3691 /*
3692 * Time deltas are in nanoseconds, but scaled.
3693 */
3694 num = fr_time_delta_unwrap(src->vb_time_delta);
3695 if (src->enumv) {
3696 num /= fr_time_multiplier_by_res[src->enumv->flags.flag_time_res];
3697 } else {
3698 num /= NSEC;
3699 }
3700 goto good_cast;
3701
3702 case FR_TYPE_SIZE:
3703 num = src->vb_size;
3704
3705 good_cast:
3706 fr_value_box_init(dst, dst_type, dst_enumv, src->tainted);
3708
3709 if (dst_type == FR_TYPE_FLOAT32) {
3710 dst->vb_float32 = num;
3711 } else {
3712 dst->vb_float64 = num;
3713 }
3714 return 0;
3715
3716 default:
3717 break;
3718 }
3719
3720bad_cast:
3721 return fr_value_box_cast_unsupported(dst_type, src->type);
3722}
3723
3724
3725/** Convert one type of fr_value_box_t to another
3726 *
3727 * This should be the canonical function used to convert between INTERNAL data formats.
3728 *
3729 * If you want to convert from PRESENTATION format, use #fr_value_box_from_substr.
3730 *
3731 * @note src and dst must not be the same box. We do not support casting in place.
3732 *
3733 * @param ctx to allocate buffers in (usually the same as dst)
3734 * @param dst Where to write result of casting.
3735 * @param dst_type to cast to.
3736 * @param dst_enumv Aliases for values contained within this fr_value_box_t.
3737 * If #fr_value_box_t is passed to #fr_value_box_aprint
3738 * names will be printed instead of actual value.
3739 * @param src Input data.
3740 * @return
3741 * - 0 on success.
3742 * - -1 on failure.
3743 */
3744int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst,
3745 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
3746 fr_value_box_t const *src)
3747{
3748 if (!fr_cond_assert(src != dst)) return -1;
3749
3750 if (fr_type_is_non_leaf(dst_type)) {
3751 fr_strerror_printf("Invalid cast from %s to %s. Can only cast simple data types",
3752 fr_type_to_str(src->type),
3753 fr_type_to_str(dst_type));
3754 return -1;
3755 }
3756
3757 /*
3758 * If it's the same type, copy, but set the enumv
3759 * in the destination box to be the one provided.
3760 *
3761 * The theory here is that the attribute value isn't
3762 * being converted into its presentation format and
3763 * re-parsed, and the enumv names only get applied
3764 * when converting internal values to/from strings,
3765 * so it's OK just to swap out the enumv.
3766 *
3767 * If there's a compelling case in the future we
3768 * might revisit this, but it'd likely mean fixing
3769 * all the casting functions to treat any value
3770 * with an enumv as a string, which seems weird.
3771 */
3772 if (dst_type == src->type) {
3773 int ret;
3774
3775 ret = fr_value_box_copy(ctx, dst, src);
3776 if (ret < 0) return ret;
3777
3778 dst->enumv = dst_enumv;
3779
3780 return ret;
3781 }
3782
3783 /*
3784 * Initialise dst
3785 */
3786 fr_value_box_init(dst, dst_type, NULL, src->tainted);
3787
3788 /*
3789 * Dispatch to specialised cast functions
3790 */
3791 switch (dst_type) {
3792 case FR_TYPE_STRING:
3793 return fr_value_box_cast_to_strvalue(ctx, dst, dst_type, dst_enumv, src);
3794
3795 case FR_TYPE_OCTETS:
3796 return fr_value_box_cast_to_octets(ctx, dst, dst_type, dst_enumv, src);
3797
3798 case FR_TYPE_IPV4_ADDR:
3799 return fr_value_box_cast_to_ipv4addr(ctx, dst, dst_type, dst_enumv, src);
3800
3802 return fr_value_box_cast_to_ipv4prefix(ctx, dst, dst_type, dst_enumv, src);
3803
3804 case FR_TYPE_IPV6_ADDR:
3805 return fr_value_box_cast_to_ipv6addr(ctx, dst, dst_type, dst_enumv, src);
3806
3808 return fr_value_box_cast_to_ipv6prefix(ctx, dst, dst_type, dst_enumv, src);
3809
3812 break;
3813 /*
3814 * Need func
3815 */
3816 case FR_TYPE_IFID:
3817 break;
3818
3819 case FR_TYPE_ETHERNET:
3820 return fr_value_box_cast_to_ethernet(ctx, dst, dst_type, dst_enumv, src);
3821
3822 case FR_TYPE_BOOL:
3823 return fr_value_box_cast_to_bool(ctx, dst, dst_type, dst_enumv, src);
3824
3825 case FR_TYPE_DATE:
3826 if (src->type != FR_TYPE_TIME_DELTA) return fr_value_box_cast_to_integer(ctx, dst, dst_type, dst_enumv, src);
3827
3828 if (fr_time_delta_isneg(src->vb_time_delta)) {
3829 fr_strerror_const("Input to data type would underflow");
3830 return -1;
3831 }
3832
3834 dst->enumv = dst_enumv;
3835 dst->vb_date = fr_unix_time_wrap(fr_time_delta_unwrap(src->vb_time_delta));
3836 return 0;
3837
3838 case FR_TYPE_TIME_DELTA:
3839 /*
3840 * Unix time cast to time_delta is just nanoseconds since the epoch.
3841 *
3842 * Note that we do NOT change time resolution, but we DO change enumv. Both unix time
3843 * and time_delta are tracked internally as nanoseconds, and the only use of precision is
3844 * for printing / parsing.
3845 */
3846 if (src->type == FR_TYPE_DATE) {
3847 uint64_t when;
3848
3849 when = fr_unix_time_unwrap(src->vb_date);
3850 if (when > INT64_MAX) {
3851 fr_strerror_const("Input to data type would overflow");
3852 return -1;
3853 }
3854
3856 dst->enumv = dst_enumv;
3857 dst->vb_time_delta = fr_time_delta_wrap((int64_t) when);
3858 return 0;
3859 }
3861
3862 case FR_TYPE_UINT8:
3863 case FR_TYPE_UINT16:
3864 case FR_TYPE_UINT32:
3865 case FR_TYPE_UINT64:
3866 case FR_TYPE_INT8:
3867 case FR_TYPE_INT16:
3868 case FR_TYPE_INT32:
3869 case FR_TYPE_INT64:
3870 case FR_TYPE_SIZE:
3871 return fr_value_box_cast_to_integer(ctx, dst, dst_type, dst_enumv, src);
3872
3873 case FR_TYPE_FLOAT32:
3874 case FR_TYPE_FLOAT64:
3875 if (fr_type_is_fixed_size(src->type)) {
3876 return fr_value_box_cast_to_float(ctx, dst, dst_type, dst_enumv, src);
3877 }
3878 break; /* use generic string/octets stuff below */
3879
3880#if 0
3881 case FR_TYPE_ATTR:
3882 /*
3883 * Convert it to an integer of the correct length. Then, cast it in place.
3884 */
3885 switch (src->vb_attr->flags.length) {
3886 case 1:
3887 fr_value_box_init(dst, FR_TYPE_UINT8, NULL, false);
3888 dst->vb_uint8 = src->vb_attr->attr;
3889 break;
3890
3891 case 2:
3892 fr_value_box_init(dst, FR_TYPE_UINT16, NULL, false);
3893 dst->vb_uint16 = src->vb_attr->attr;
3894 break;
3895
3896 case 4:
3897 fr_value_box_init(dst, FR_TYPE_UINT32, NULL, false);
3898 dst->vb_uint32 = src->vb_attr->attr;
3899 break;
3900
3901 default:
3902 fr_strerror_printf("Unsupported length '%d' for attribute %s",
3903 src->vb_attr->flags.length, src->vb_attr->name);
3904 return 0;
3905 }
3906
3907 return fr_value_box_cast_in_place(ctx, dst, dst_type, dst_enumv);
3908#else
3909 case FR_TYPE_ATTR:
3910#endif
3911 /*
3912 * Invalid types for casting (were caught earlier)
3913 */
3914 case FR_TYPE_NON_LEAF:
3915 fr_strerror_printf("Invalid cast from %s to %s. Invalid destination type",
3916 fr_type_to_str(src->type),
3917 fr_type_to_str(dst_type));
3918 return -1;
3919 }
3920
3921 /*
3922 * Deserialise a fr_value_box_t
3923 */
3924 if (src->type == FR_TYPE_STRING) return fr_value_box_from_str(ctx, dst, dst_type, dst_enumv,
3925 src->vb_strvalue, src->vb_length,
3926 NULL);
3927
3928 if (src->type == FR_TYPE_OCTETS) {
3929 fr_value_box_t tmp;
3930
3931 if (src->vb_length < network_min_size(dst_type)) {
3932 fr_strerror_printf("Invalid cast from %s to %s. Source is length %zu is smaller than "
3933 "destination type size %zu",
3934 fr_type_to_str(src->type),
3935 fr_type_to_str(dst_type),
3936 src->vb_length,
3937 network_min_size(dst_type));
3938 return -1;
3939 }
3940
3941 if (src->vb_length > network_max_size(dst_type)) {
3942 fr_strerror_printf("Invalid cast from %s to %s. Source length %zu is greater than "
3943 "destination type size %zu",
3944 fr_type_to_str(src->type),
3945 fr_type_to_str(dst_type),
3946 src->vb_length,
3947 network_max_size(dst_type));
3948 return -1;
3949 }
3950
3951 fr_value_box_init(&tmp, dst_type, NULL, false);
3952
3953 /*
3954 * Copy the raw octets into the datum of a value_box
3955 * inverting bytesex for uint32s (if LE).
3956 */
3957 memcpy(&tmp.datum, src->vb_octets, fr_value_box_field_sizes[dst_type]);
3958 tmp.type = dst_type;
3959 dst->enumv = dst_enumv;
3960
3961 fr_value_box_hton(dst, &tmp);
3962 fr_value_box_safety_copy(dst, src);
3963 return 0;
3964 }
3965
3966 memcpy(&dst->datum, &src->datum, fr_value_box_field_sizes[src->type]);
3967
3969 dst->enumv = dst_enumv;
3970
3971 return 0;
3972}
3973
3974/** Convert one type of fr_value_box_t to another in place
3975 *
3976 * This should be the canonical function used to convert between INTERNAL data formats.
3977 *
3978 * If you want to convert from PRESENTATION format, use #fr_value_box_from_substr.
3979 *
3980 * @param ctx to allocate buffers in (usually the same as dst)
3981 * @param vb to cast.
3982 * @param dst_type to cast to.
3983 * @param dst_enumv Aliases for values contained within this fr_value_box_t.
3984 * If #fr_value_box_t is passed to #fr_value_box_aprint
3985 * names will be printed instead of actual value.
3986 * @return
3987 * - 0 on success.
3988 * - -1 on failure.
3989 */
3991 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
3992{
3993 fr_value_box_t tmp;
3994 /*
3995 * Store list pointers to restore later - fr_value_box_cast clears them
3996 */
3997 fr_value_box_entry_t entry = vb->entry;
3998
3999 /*
4000 * Simple case, destination type and current
4001 * type are the same.
4002 */
4003 if (vb->type == dst_type) {
4004 vb->enumv = dst_enumv; /* Update the enumv as this may be different */
4005 return 0;
4006 }
4007
4008 /*
4009 * Copy meta data and any existing buffers to
4010 * a temporary box. We then clear that value
4011 * box after the cast has been completed,
4012 * freeing any old buffers.
4013 */
4014 fr_value_box_copy_shallow(NULL, &tmp, vb);
4015
4016 if (fr_value_box_cast(ctx, vb, dst_type, dst_enumv, &tmp) < 0) {
4017 /*
4018 * On error, make sure the original
4019 * box is left in a consistent state.
4020 */
4021 fr_value_box_copy_shallow(NULL, vb, &tmp);
4022 vb->entry = entry;
4023 return -1;
4024 }
4025 fr_value_box_clear_value(&tmp); /* Clear out any old buffers */
4026
4027 /*
4028 * Restore list pointers
4029 */
4030 vb->entry = entry;
4031
4032 return 0;
4033}
4034
4035/** Assign a #fr_value_box_t value from an #fr_ipaddr_t
4036 *
4037 * Automatically determines the type of the value box from the ipaddr address family
4038 * and the length of the prefix field.
4039 *
4040 * @param[in] dst to assign ipaddr to.
4041 * @param[in] enumv Aliases for values.
4042 * @param[in] ipaddr to copy address from.
4043 * @param[in] tainted Whether the value came from a trusted source.
4044 * @return
4045 * - 0 on success.
4046 * - -1 on failure.
4047 */
4048int fr_value_box_ipaddr(fr_value_box_t *dst, fr_dict_attr_t const *enumv, fr_ipaddr_t const *ipaddr, bool tainted)
4049{
4051
4052 switch (ipaddr->af) {
4053 case AF_INET:
4055 break;
4056
4057 case AF_INET6:
4059 break;
4060
4061 default:
4062 fr_strerror_printf("Invalid address family %i", ipaddr->af);
4063 return -1;
4064 }
4065
4066 fr_value_box_init(dst, type, enumv, tainted);
4067 memcpy(&dst->vb_ip, ipaddr, sizeof(dst->vb_ip));
4068
4069 return 0;
4070}
4071
4072/** Unbox an IP address performing a type check
4073 *
4074 * @param[out] dst Where to copy the IP address to.
4075 * @param[in] src Where to copy the IP address from.
4076 * @return
4077 * - 0 on success.
4078 * - -1 on type mismatch.
4079 */
4081{
4082 if (!fr_type_is_ip(src->type)) {
4083 fr_strerror_printf("Unboxing failed. Needed IPv4/6 addr/prefix, had type %s",
4084 fr_type_to_str(src->type));
4085 return -1;
4086 }
4087
4088 memcpy(dst, &src->vb_ip, sizeof(*dst));
4089
4090 return 0;
4091}
4092
4093/** Clear/free any existing value
4094 *
4095 * @note Do not use on uninitialised memory.
4096 *
4097 * @param[in] data to clear.
4098 */
4100{
4101 switch (data->type) {
4102 case FR_TYPE_OCTETS:
4103 case FR_TYPE_STRING:
4104 if (data->secret) memset_explicit(data->datum.ptr, 0, data->vb_length);
4105 talloc_free(data->datum.ptr);
4106 break;
4107
4108 case FR_TYPE_GROUP:
4109 /*
4110 * Depth first freeing of children
4111 *
4112 * This ensures orderly freeing, regardless
4113 * of talloc hierarchy.
4114 */
4115 {
4116 fr_value_box_t *vb = NULL;
4117
4118 while ((vb = fr_value_box_list_next(&data->vb_group, vb))) {
4120 talloc_free(vb);
4121 }
4122 }
4123 return;
4124
4125 case FR_TYPE_NULL:
4126 return;
4127
4129 talloc_free(data->vb_cursor);
4130 break;
4131
4132 default:
4133 break;
4134 }
4135
4136 memset(&data->datum, 0, sizeof(data->datum));
4137}
4138
4139/** Clear/free any existing value and metadata
4140 *
4141 * @note Do not use on uninitialised memory.
4142 *
4143 * @param[in] data to clear.
4144 */
4150
4151/** Copy value data verbatim duplicating any buffers
4152 *
4153 * @note Will free any exiting buffers associated with the dst #fr_value_box_t.
4154 *
4155 * @param ctx To allocate buffers in.
4156 * @param dst Where to copy value_box to.
4157 * @param src Where to copy value_box from.
4158 * @return
4159 * - 0 on success.
4160 * - -1 on failure.
4161 */
4162int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
4163{
4164 switch (src->type) {
4165 case FR_TYPE_NUMERIC:
4166 case FR_TYPE_IP:
4167 case FR_TYPE_IFID:
4168 case FR_TYPE_ETHERNET:
4169 fr_value_box_memcpy_out(fr_value_box_raw(dst, src->type), src);
4170 fr_value_box_copy_meta(dst, src);
4171 break;
4172
4173 case FR_TYPE_NULL:
4174 fr_value_box_copy_meta(dst, src);
4175 break;
4176
4177 case FR_TYPE_STRING:
4178 {
4179 char *str = NULL;
4180
4181 /*
4182 * Zero length strings still have a one uint8 buffer
4183 */
4184 str = talloc_bstrndup(ctx, src->vb_strvalue, src->vb_length);
4185 if (!str) {
4186 fr_strerror_const("Failed allocating string buffer");
4187 return -1;
4188 }
4189 dst->vb_strvalue = str;
4190 fr_value_box_copy_meta(dst, src);
4191 }
4192 break;
4193
4194 case FR_TYPE_OCTETS:
4195 {
4196 uint8_t *bin;
4197
4198 if (src->vb_length) {
4199 bin = talloc_memdup(ctx, src->vb_octets, src->vb_length);
4200 if (!bin) {
4201 fr_strerror_const("Failed allocating octets buffer");
4202 return -1;
4203 }
4204 talloc_set_type(bin, uint8_t);
4205 } else {
4206 bin = talloc_array(ctx, uint8_t, 0);
4207 }
4208 dst->vb_octets = bin;
4209 fr_value_box_copy_meta(dst, src);
4210 }
4211 break;
4212
4213 case FR_TYPE_GROUP:
4214 {
4215 fr_value_box_t *child = NULL;
4216
4217 fr_value_box_copy_meta(dst, src); /* Initialises group child dlist */
4218
4219 while ((child = fr_value_box_list_next(&src->vb_group, child))) {
4220 fr_value_box_t *new;
4221
4222 /*
4223 * Build out the child
4224 */
4225 new = fr_value_box_alloc_null(ctx);
4226 if (unlikely(!new)) {
4227 group_error:
4228 fr_strerror_const("Failed duplicating group child");
4229 fr_value_box_list_talloc_free(&dst->vb_group);
4230 return -1;
4231 }
4232
4233 /*
4234 * Populate it with the data from the original child.
4235 *
4236 * We do NOT update the dst safety. The individual boxes have safety. A group
4237 * doesn't.
4238 */
4239 if (unlikely(fr_value_box_copy(new, new, child) < 0)) goto group_error;
4240 fr_value_box_list_insert_tail(&dst->vb_group, new);
4241 }
4242 }
4243 break;
4244
4245 case FR_TYPE_ATTR:
4246 fr_value_box_copy_meta(dst, src);
4247
4248 /* raw also sets is_unknown */
4249 if (src->vb_attr->flags.is_unknown) {
4250 dst->vb_attr = fr_dict_attr_unknown_copy(ctx, src->vb_attr);
4251 if (!dst->vb_attr) return -1;
4252 break;
4253 }
4254 dst->vb_attr = src->vb_attr;
4255 break;
4256
4257 case FR_TYPE_TLV:
4258 case FR_TYPE_STRUCT:
4259 case FR_TYPE_VSA:
4260 case FR_TYPE_VENDOR:
4261 case FR_TYPE_UNION:
4262 case FR_TYPE_VOID:
4263 case FR_TYPE_VALUE_BOX:
4266 case FR_TYPE_MAX:
4267 fr_assert(0);
4268 fr_strerror_printf("Cannot copy data type '%s'", fr_type_to_str(src->type));
4269 return -1;
4270 }
4271
4272 return 0;
4273}
4274
4275/** Perform a shallow copy of a value_box
4276 *
4277 * Like #fr_value_box_copy, but does not duplicate the buffers of the src value_box.
4278 *
4279 * For #FR_TYPE_STRING and #FR_TYPE_OCTETS adds a reference from ctx so that the
4280 * buffer cannot be freed until the ctx is freed.
4281 *
4282 * @param[in] ctx to add reference from. If NULL no reference will be added.
4283 * @param[in] dst to copy value to.
4284 * @param[in] src to copy value from.
4285 */
4286void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
4287{
4288 switch (src->type) {
4289 default:
4290 if (unlikely(fr_value_box_copy(NULL, dst, src) < 0)) return;
4291 break;
4292
4293 case FR_TYPE_STRING:
4294 case FR_TYPE_OCTETS:
4295 dst->datum.ptr = ctx ? talloc_reference(ctx, src->datum.ptr) : src->datum.ptr;
4296 fr_value_box_copy_meta(dst, src);
4297 break;
4298
4299 case FR_TYPE_ATTR:
4300 dst->vb_attr = src->vb_attr;
4301 fr_value_box_copy_meta(dst, src);
4302 break;
4303 }
4304}
4305
4306/** Copy value data verbatim moving any buffers to the specified context
4307 *
4308 * @param[in] ctx to allocate any new buffers in.
4309 * @param[in] dst to copy value to.
4310 * @param[in] src to copy value from.
4311 * @return
4312 * - 0 on success.
4313 * - -1 on failure.
4314 */
4315int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
4316{
4317 switch (src->type) {
4318 default:
4319 return fr_value_box_copy(ctx, dst, src);
4320
4321 case FR_TYPE_STRING:
4322 {
4323 char const *str;
4324
4325 str = talloc_steal(ctx, src->vb_strvalue);
4326 if (!str) {
4327 fr_strerror_const("Failed stealing string buffer");
4328 return -1;
4329 }
4330 talloc_set_type(str, char);
4331 dst->vb_strvalue = str;
4332 fr_value_box_copy_meta(dst, src);
4333 memset(&src->datum, 0, sizeof(src->datum));
4334 }
4335 return 0;
4336
4337 case FR_TYPE_OCTETS:
4338 {
4339 uint8_t const *bin;
4340
4341 bin = talloc_steal(ctx, src->vb_octets);
4342 if (!bin) {
4343 fr_strerror_const("Failed stealing octets buffer");
4344 return -1;
4345 }
4346 talloc_set_type(bin, uint8_t);
4347
4348 dst->vb_octets = bin;
4349 fr_value_box_copy_meta(dst, src);
4350 memset(&src->datum, 0, sizeof(src->datum));
4351 }
4352 return 0;
4353
4354 case FR_TYPE_GROUP:
4355 {
4356 fr_value_box_t *child;
4357
4358 while ((child = fr_value_box_list_pop_head(&src->vb_group))) {
4359 child = talloc_steal(ctx, child);
4360 if (unlikely(!child)) {
4361 fr_strerror_const("Failed stealing child");
4362 return -1;
4363 }
4364 fr_value_box_list_insert_tail(&dst->vb_group, child);
4365 }
4366 }
4367 return 0;
4368 }
4369}
4370
4371/** Copy a nul terminated string to a #fr_value_box_t
4372 *
4373 * @param[in] ctx to allocate any new buffers in.
4374 * @param[in] dst to assign new buffer to.
4375 * @param[in] enumv Aliases for values.
4376 * @param[in] src a nul terminated buffer.
4377 * @param[in] tainted Whether the value came from a trusted source.
4378 * @return
4379 * - 0 on success.
4380 * - -1 on failure.
4381 */
4382int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4383 char const *src, bool tainted)
4384{
4385 char const *str;
4386
4387 str = talloc_typed_strdup(ctx, src);
4388 if (!str) {
4389 fr_strerror_const("Failed allocating string buffer");
4390 return -1;
4391 }
4392
4393 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4394 dst->vb_strvalue = str;
4395 dst->vb_length = talloc_array_length(str) - 1;
4396
4397 return 0;
4398}
4399
4400/** Trim the length of the string buffer to match the length of the C string
4401 *
4402 * @param[in] ctx to re-alloc the buffer in.
4403 * @param[in,out] vb to trim.
4404 * @return
4405 * - 0 on success.
4406 * - -1 on failure.
4407 */
4408int fr_value_box_strtrim(TALLOC_CTX *ctx, fr_value_box_t *vb)
4409{
4410 size_t len;
4411 char *str;
4412
4413 if (!fr_cond_assert(vb->type == FR_TYPE_STRING)) return -1;
4414
4415 len = strlen(vb->vb_strvalue);
4416 str = talloc_realloc(ctx, UNCONST(char *, vb->vb_strvalue), char, len + 1);
4417 if (!str) {
4418 fr_strerror_const("Failed re-allocing string buffer");
4419 return -1;
4420 }
4421 vb->vb_length = len;
4422
4423 return 0;
4424}
4425
4426/** Print a formatted string using our internal printf wrapper and assign it to a value box
4427 *
4428 * @param[in] ctx to allocate any new buffers in.
4429 * @param[in] dst to assign new buffer to.
4430 * @param[in] enumv Aliases for values.
4431 * @param[in] fmt The printf format string to process.
4432 * @param[in] tainted Whether the value came from a trusted source.
4433 * @param[in] ap Substitution arguments.
4434 * @return
4435 * - 0 on success.
4436 * - -1 on failure.
4437 */
4438int fr_value_box_vasprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted,
4439 char const *fmt, va_list ap)
4440{
4441 va_list aq;
4442 char *str;
4443
4444 va_copy(aq, ap); /* See vlog_module_failure_msg for why */
4445 str = fr_vasprintf(ctx, fmt, aq);
4446 va_end(aq);
4447
4448 if (!str) return -1;
4449
4450 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4451 dst->vb_strvalue = str;
4452 dst->vb_length = talloc_array_length(str) - 1;
4453
4454 return 0;
4455}
4456
4457/** Print a formatted string using our internal printf wrapper and assign it to a value box
4458 *
4459 * @param[in] ctx to allocate any new buffers in.
4460 * @param[in] dst to assign new buffer to.
4461 * @param[in] enumv Aliases for values.
4462 * @param[in] tainted Whether the value came from a trusted source.
4463 * @param[in] fmt The printf format string to process.
4464 * @param[in] ... Substitution arguments.
4465 * @return
4466 * - 0 on success.
4467 * - -1 on failure.
4468 */
4469int fr_value_box_asprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted,
4470 char const *fmt, ...)
4471{
4472 va_list ap;
4473 int ret;
4474
4475 va_start(ap, fmt);
4476 ret = fr_value_box_vasprintf(ctx, dst, enumv, tainted, fmt, ap);
4477 va_end(ap);
4478
4479 return ret;
4480}
4481
4482/** Assign a buffer containing a nul terminated string to a box, but don't copy it
4483 *
4484 * @note Input string will not be duplicated.
4485 *
4486 * @param[in] dst to assign string to.
4487 * @param[in] enumv Aliases for values.
4488 * @param[in] src to copy string from.
4489 * @param[in] tainted Whether the value came from a trusted source.
4490 */
4492 char const *src, bool tainted)
4493{
4494 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4495 dst->vb_strvalue = src;
4496 dst->vb_length = strlen(src);
4497}
4498
4499/** Free the existing buffer (if talloced) associated with the valuebox, and replace it with a new one
4500 *
4501 * @note Input string will not be duplicated.
4502 *
4503 * @param[in] vb to replace string in.
4504 * @param[in] src to assign string from.
4505 * @param[in] len of src.
4506 */
4508{
4510 vb->vb_strvalue = src;
4511 vb->vb_length = len < 0 ? strlen(src) : (size_t)len;
4512}
4513
4514/** Alloc and assign an empty \0 terminated string to a #fr_value_box_t
4515 *
4516 * @param[in] ctx to allocate any new buffers in.
4517 * @param[out] out if non-null where to write a pointer to the new buffer.
4518 * @param[in] dst to assign new buffer to.
4519 * @param[in] enumv Aliases for values.
4520 * @param[in] len of buffer to allocate.
4521 * @param[in] tainted Whether the value came from a trusted source.
4522 * @return
4523 * - 0 on success.
4524 * - -1 on failure.
4525 */
4526int fr_value_box_bstr_alloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4527 size_t len, bool tainted)
4528{
4529 char *str;
4530
4531 str = talloc_zero_array(ctx, char, len + 1);
4532 if (!str) {
4533 fr_strerror_const("Failed allocating string buffer");
4534 return -1;
4535 }
4536 str[len] = '\0';
4537
4538 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4539 dst->vb_strvalue = str;
4540 dst->vb_length = len;
4541
4542 if (out) *out = str;
4543
4544 return 0;
4545}
4546
4547/** Change the length of a buffer already allocated to a value box
4548 *
4549 * @note Do not use on an uninitialised box.
4550 *
4551 * @param[in] ctx to realloc buffer in.
4552 * @param[out] out if non-null where to write a pointer to the new buffer.
4553 * @param[in] dst to realloc buffer for.
4554 * @param[in] len to realloc to (don't include nul byte).
4555 * @return
4556 * - 0 on success.
4557 * - -1 on failure.
4558 */
4559int fr_value_box_bstr_realloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, size_t len)
4560{
4561 size_t clen;
4562 char *cstr;
4563 char *str;
4564
4565 fr_assert(dst->type == FR_TYPE_STRING);
4566
4567 memcpy(&cstr, &dst->vb_strvalue, sizeof(cstr));
4568
4569 clen = talloc_array_length(dst->vb_strvalue) - 1;
4570 if (clen == len) return 0; /* No change */
4571
4572 str = talloc_realloc(ctx, cstr, char, len + 1);
4573 if (!str) {
4574 fr_strerror_printf("Failed reallocing value box buffer to %zu bytes", len + 1);
4575 return -1;
4576 }
4577
4578 /*
4579 * Zero out the additional bytes
4580 */
4581 if (clen < len) {
4582 memset(str + clen, '\0', (len - clen) + 1);
4583 } else {
4584 cstr[len] = '\0';
4585 }
4586 dst->vb_strvalue = str;
4587 dst->vb_length = len;
4588
4589 if (out) *out = str;
4590
4591 return 0;
4592}
4593
4594/** Copy a string to to a #fr_value_box_t
4595 *
4596 * @param[in] ctx to allocate any new buffers in.
4597 * @param[in] dst to assign buffer to.
4598 * @param[in] enumv Aliases for values.
4599 * @param[in] src a string. May be NULL only if len == 0.
4600 * @param[in] len of src.
4601 * @param[in] tainted Whether the value came from a trusted source.
4602 */
4603int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4604 char const *src, size_t len, bool tainted)
4605{
4606 char const *str;
4607
4608 if (unlikely((len > 0) && !src)) {
4609 fr_strerror_printf("Invalid arguments to %s. Len > 0 (%zu) but src string was NULL",
4610 __FUNCTION__, len);
4611 return -1;
4612 }
4613
4614 str = talloc_bstrndup(ctx, src, len);
4615 if (!str) {
4616 fr_strerror_const("Failed allocating string buffer");
4617 return -1;
4618 }
4619
4620 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4621 dst->vb_strvalue = str;
4622 dst->vb_length = len;
4623
4624 return 0;
4625}
4626
4627int fr_value_box_bstrndup_dbuff(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4628 fr_dbuff_t *dbuff, size_t len, bool tainted)
4629{
4630 char *str;
4631
4632 str = talloc_array(ctx, char, len + 1);
4633 if (!str) {
4634 fr_strerror_printf("Failed allocating string buffer");
4635 return -1;
4636 }
4637
4638 if (fr_dbuff_out_memcpy((uint8_t *)str, dbuff, len) < 0) return -1;
4639 str[len] = '\0';
4640
4641 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4642 dst->vb_strvalue = str;
4643 dst->vb_length = len;
4644
4645 return 0;
4646}
4647
4648/** Copy a nul terminated talloced buffer to a #fr_value_box_t
4649 *
4650 * Copy a talloced nul terminated buffer, setting fields in the dst value box appropriately.
4651 *
4652 * The buffer must be \0 terminated, or an error will be returned.
4653 *
4654 * @param[in] ctx to allocate any new buffers in.
4655 * @param[in] dst to assign new buffer to.
4656 * @param[in] enumv Aliases for values.
4657 * @param[in] src a talloced nul terminated buffer.
4658 * @param[in] tainted Whether the value came from a trusted source.
4659 * @return
4660 * - 0 on success.
4661 * - -1 on failure.
4662 */
4663int fr_value_box_bstrdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4664 char const *src, bool tainted)
4665{
4666 size_t len;
4667
4668 (void)talloc_get_type_abort_const(src, char);
4669
4670 len = talloc_array_length(src);
4671 if ((len == 0) || (src[len - 1] != '\0')) {
4672 fr_strerror_const("Input buffer not \\0 terminated");
4673 return -1;
4674 }
4675
4676 return fr_value_box_bstrndup(ctx, dst, enumv, src, len - 1, tainted);
4677}
4678
4679/** Assign a string to to a #fr_value_box_t
4680 *
4681 * @param[in] dst to assign new buffer to.
4682 * @param[in] enumv Aliases for values.
4683 * @param[in] src a string.
4684 * @param[in] len of src.
4685 * @param[in] tainted Whether the value came from a trusted source.
4686 */
4688 char const *src, size_t len, bool tainted)
4689{
4690 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4691 dst->vb_strvalue = src;
4692 dst->vb_length = len;
4693}
4694
4695/** Assign a talloced buffer containing a nul terminated string to a box, but don't copy it
4696 *
4697 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
4698 *
4699 * @param[in] ctx to add reference from. If NULL no reference will be added.
4700 * @param[in] dst to assign string to.
4701 * @param[in] enumv Aliases for values.
4702 * @param[in] src to copy string from.
4703 * @param[in] tainted Whether the value came from a trusted source.
4704 * @return
4705 * - 0 on success.
4706 * - -1 on failure.
4707 */
4709 char const *src, bool tainted)
4710{
4711 size_t len;
4712
4713 (void) talloc_get_type_abort_const(src, char);
4714
4715 len = talloc_array_length(src);
4716 if ((len == 0) || (src[len - 1] != '\0')) {
4717 fr_strerror_const("Input buffer not \\0 terminated");
4718 return -1;
4719 }
4720
4721 fr_value_box_init(dst, FR_TYPE_STRING, enumv, tainted);
4722 dst->vb_strvalue = ctx ? talloc_reference(ctx, src) : src;
4723 dst->vb_length = len - 1;
4724
4725 return 0;
4726}
4727
4728/** Pre-allocate an octets buffer for filling by the caller
4729 *
4730 * @note Buffer will not be zeroed, as it's assumed the caller will be filling it.
4731 *
4732 * @param[in] ctx to allocate any new buffers in.
4733 * @param[out] out If non-null will be filled with a pointer to the
4734 * new buffer.
4735 * @param[in] dst to assign new buffer to.
4736 * @param[in] enumv Aliases for values.
4737 * @param[in] len of data in the buffer. If 0, a zero length
4738 * talloc buffer will be alloced. dst->vb_octets
4739 * will *NOT* be NULL. You should use the length
4740 * field of the box to determine if any value
4741 * is assigned.
4742 * @param[in] tainted Whether the value came from a trusted source.
4743 * @return
4744 * - 0 on success.
4745 * - -1 on failure.
4746 */
4747int fr_value_box_mem_alloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4748 size_t len, bool tainted)
4749{
4750 uint8_t *bin;
4751
4752 bin = talloc_array(ctx, uint8_t, len);
4753 if (!bin) {
4754 fr_strerror_const("Failed allocating octets buffer");
4755 return -1;
4756 }
4757 talloc_set_type(bin, uint8_t);
4758
4759 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4760 dst->vb_octets = bin;
4761 dst->vb_length = len;
4762
4763 if (out) *out = bin;
4764
4765 return 0;
4766}
4767
4768/** Change the length of a buffer already allocated to a value box
4769 *
4770 * @note Do not use on an uninitialised box.
4771 *
4772 * @param[in] ctx to realloc buffer in.
4773 * @param[out] out if non-null where to write a pointer to the new buffer.
4774 * @param[in] dst to realloc buffer for.
4775 * @param[in] len to realloc to.
4776 * @return
4777 * - 0 on success.
4778 * - -1 on failure.
4779 */
4780int fr_value_box_mem_realloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, size_t len)
4781{
4782 size_t clen;
4783 uint8_t *cbin;
4784 uint8_t *bin;
4785
4786 fr_assert(dst->type == FR_TYPE_OCTETS);
4787
4788 memcpy(&cbin, &dst->vb_octets, sizeof(cbin));
4789
4790 clen = talloc_array_length(dst->vb_octets);
4791 if (clen == len) return 0; /* No change */
4792
4793 /*
4794 * Realloc the buffer. If the new length is 0, we
4795 * need to call talloc_array() instead of talloc_realloc()
4796 * as talloc_realloc() will fail.
4797 */
4798 if (len > 0) {
4799 bin = talloc_realloc(ctx, cbin, uint8_t, len);
4800 } else {
4801 bin = talloc_array(ctx, uint8_t, 0);
4802 }
4803 if (!bin) {
4804 fr_strerror_printf("Failed reallocing value box buffer to %zu bytes", len);
4805 return -1;
4806 }
4807
4808 /*
4809 * Only free the original buffer once we've allocated
4810 * a new empty array.
4811 */
4812 if (len == 0) talloc_free(cbin);
4813
4814 /*
4815 * Zero out the additional bytes
4816 */
4817 if (clen < len) memset(bin + clen, 0x00, len - clen);
4818 dst->vb_octets = bin;
4819 dst->vb_length = len;
4820
4821 if (out) *out = bin;
4822
4823 return 0;
4824}
4825
4826/** Copy a buffer to a fr_value_box_t
4827 *
4828 * Copy a buffer containing binary data, setting fields in the dst value box appropriately.
4829 *
4830 * @param[in] ctx to allocate any new buffers in.
4831 * @param[in] dst to assign new buffer to.
4832 * @param[in] enumv Aliases for values.
4833 * @param[in] src a buffer.
4834 * @param[in] len of data in the buffer. If 0, a zero length
4835 * talloc buffer will be alloced. dst->vb_octets
4836 * will *NOT* be NULL. You should use the length
4837 * field of the box to determine if any value
4838 * is assigned.
4839 * @param[in] tainted Whether the value came from a trusted source.
4840 * @return
4841 * - 0 on success.
4842 * - -1 on failure.
4843 */
4844int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4845 uint8_t const *src, size_t len, bool tainted)
4846{
4847 uint8_t *bin;
4848
4849 if (unlikely((len > 0) && !src)) {
4850 fr_strerror_printf("Invalid arguments to %s. Len > 0 (%zu) but src was NULL",
4851 __FUNCTION__, len);
4852 return -1;
4853 }
4854
4855 bin = talloc_memdup(ctx, src, len);
4856 if (!bin) {
4857 fr_strerror_const("Failed allocating octets buffer");
4858 return -1;
4859 }
4860 talloc_set_type(bin, uint8_t);
4861
4862 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4863 dst->vb_octets = bin;
4864 dst->vb_length = len;
4865
4866 return 0;
4867}
4868
4869int fr_value_box_memdup_dbuff(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4870 fr_dbuff_t *dbuff, size_t len, bool tainted)
4871{
4872 uint8_t *bin;
4873
4874 bin = talloc_size(ctx, len);
4875 if (!bin) {
4876 fr_strerror_printf("Failed allocating octets buffer");
4877 return -1;
4878 }
4879 if (fr_dbuff_out_memcpy(bin, dbuff, len) < (ssize_t) len) return -1;
4880 talloc_set_type(bin, uint8_t);
4881
4882 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4883 dst->vb_octets = bin;
4884 dst->vb_length = len;
4885
4886 return 0;
4887}
4888
4889/** Copy a talloced buffer to a fr_value_box_t
4890 *
4891 * Copy a buffer containing binary data, setting fields in the dst value box appropriately.
4892 *
4893 * @param[in] ctx to allocate any new buffers in.
4894 * @param[in] dst to assign new buffer to.
4895 * @param[in] enumv Aliases for values.
4896 * @param[in] src a buffer.
4897 * @param[in] tainted Whether the value came from a trusted source.
4898 * @return
4899 * - 0 on success.
4900 * - -1 on failure.
4901 */
4902int fr_value_box_memdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv,
4903 uint8_t const *src, bool tainted)
4904{
4906
4907 return fr_value_box_memdup(ctx, dst, enumv, src, talloc_array_length(src), tainted);
4908}
4909
4910/** Assign a buffer to a box, but don't copy it
4911 *
4912 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
4913 *
4914 * Caller should set dst->taint = true, where the value was acquired from an untrusted source.
4915 *
4916 * @note Will free any exiting buffers associated with the value box.
4917 *
4918 * @param[in] dst to assign buffer to.
4919 * @param[in] enumv Aliases for values.
4920 * @param[in] src a talloced buffer.
4921 * @param[in] len of buffer.
4922 * @param[in] tainted Whether the value came from a trusted source.
4923 */
4925 uint8_t const *src, size_t len, bool tainted)
4926{
4927 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4928 dst->vb_octets = src;
4929 dst->vb_length = len;
4930}
4931
4932/** Assign a talloced buffer to a box, but don't copy it
4933 *
4934 * Adds a reference to the src buffer so that it cannot be freed until the ctx is freed.
4935 *
4936 * @param[in] ctx to allocate any new buffers in.
4937 * @param[in] dst to assign buffer to.
4938 * @param[in] enumv Aliases for values.
4939 * @param[in] src a talloced buffer.
4940 * @param[in] tainted Whether the value came from a trusted source.
4941 */
4943 uint8_t const *src, bool tainted)
4944{
4946
4947 fr_value_box_init(dst, FR_TYPE_OCTETS, enumv, tainted);
4948 dst->vb_octets = ctx ? talloc_reference(ctx, src) : src;
4949 dst->vb_length = talloc_array_length(src);
4950}
4951
4952/*
4953 * Assign a cursor to the data type.
4954 */
4955void fr_value_box_set_cursor(fr_value_box_t *dst, fr_type_t type, void *cursor, char const *name)
4956{
4958
4959 fr_value_box_init(dst, type, NULL, false);
4960 dst->vb_cursor = cursor;
4961 dst->vb_cursor_name = name;
4962}
4963
4964/** Increment a boxed value
4965 *
4966 * Implements safe integer overflow.
4967 *
4968 * @param[in] vb to increment.
4969 */
4971{
4972 switch (vb->type) {
4973 case FR_TYPE_UINT8:
4974 vb->vb_uint8 = vb->vb_uint8 == UINT8_MAX ? 0 : vb->vb_uint8 + 1;
4975 return;
4976
4977 case FR_TYPE_UINT16:
4978 vb->vb_uint16 = vb->vb_uint16 == UINT16_MAX ? 0 : vb->vb_uint16 + 1;
4979 return;
4980
4981 case FR_TYPE_UINT32:
4982 vb->vb_uint32 = vb->vb_uint32 == UINT32_MAX ? 0 : vb->vb_uint32 + 1;
4983 return;
4984
4985 case FR_TYPE_UINT64:
4986 vb->vb_uint64 = vb->vb_uint64 == UINT64_MAX ? 0 : vb->vb_uint64 + 1;
4987 return;
4988
4989 case FR_TYPE_INT8:
4990 vb->vb_int8 = vb->vb_int8 == INT8_MAX ? INT8_MIN : vb->vb_int8 + 1;
4991 return;
4992
4993 case FR_TYPE_INT16:
4994 vb->vb_int16 = vb->vb_int16 == INT16_MAX ? INT16_MIN : vb->vb_int16 + 1;
4995 return;
4996
4997 case FR_TYPE_INT32:
4998 vb->vb_int32 = vb->vb_int32 == INT32_MAX ? INT32_MIN : vb->vb_int32 + 1;
4999 return;
5000
5001 case FR_TYPE_INT64:
5002 vb->vb_int64 = vb->vb_int64 == INT64_MAX ? INT64_MIN : vb->vb_int64 + 1;
5003 return;
5004
5005 default:
5006 fr_assert_fail(NULL);
5007 return;
5008 }
5009}
5010
5011/** Convert integer encoded as string to a fr_value_box_t type
5012 *
5013 * @param[out] dst where to write parsed value.
5014 * @param[in] dst_type type of integer to convert string to.
5015 * @param[in] dst_enumv Enumeration values.
5016 * @param[in] in String to convert to integer.
5017 * @param[in] rules for parsing string.
5018 * @param[in] tainted Whether the value came from a trusted source.
5019 * @return
5020 * - >= 0 on success (number of bytes parsed).
5021 * - < 0 on error (where the parse error occurred).
5022 */
5023static inline CC_HINT(always_inline)
5025 fr_dict_attr_t const *dst_enumv,
5026 fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules, bool tainted)
5027{
5028 fr_slen_t slen;
5030
5031 fr_value_box_init(dst, dst_type, dst_enumv, tainted);
5032
5033 switch (dst_type) {
5034 case FR_TYPE_UINT8:
5035 slen = fr_sbuff_out(&err, &dst->vb_uint8, in);
5036 break;
5037
5038 case FR_TYPE_UINT16:
5039 slen = fr_sbuff_out(&err, &dst->vb_uint16, in);
5040 break;
5041
5042 case FR_TYPE_UINT32:
5043 slen = fr_sbuff_out(&err, &dst->vb_uint32, in);
5044 break;
5045
5046 case FR_TYPE_UINT64:
5047 slen = fr_sbuff_out(&err, &dst->vb_uint64, in);
5048 break;
5049
5050 case FR_TYPE_INT8:
5051 slen = fr_sbuff_out(&err, &dst->vb_int8, in);
5052 break;
5053
5054 case FR_TYPE_INT16:
5055 slen = fr_sbuff_out(&err, &dst->vb_int16, in);
5056 break;
5057
5058 case FR_TYPE_INT32:
5059 slen = fr_sbuff_out(&err, &dst->vb_int32, in);
5060 break;
5061
5062 case FR_TYPE_INT64:
5063 slen = fr_sbuff_out(&err, &dst->vb_int64, in);
5064 break;
5065
5066 case FR_TYPE_SIZE:
5067 slen = fr_sbuff_out(&err, &dst->vb_size, in);
5068 break;
5069
5070 case FR_TYPE_FLOAT32:
5071 slen = fr_sbuff_out(&err, &dst->vb_float32, in);
5072 break;
5073
5074 case FR_TYPE_FLOAT64:
5075 slen = fr_sbuff_out(&err, &dst->vb_float64, in);
5076 break;
5077
5078 default:
5079 fr_assert_fail(NULL);
5080 return -1;
5081 }
5082
5083 if (slen < 0) {
5084 /*
5085 * If an enumeration attribute is provided and we
5086 * don't find an integer, assume this is an enumv
5087 * lookup fail, and produce a better error.
5088 */
5089 if (dst_enumv && dst_enumv->flags.has_value && (err == FR_SBUFF_PARSE_ERROR_NOT_FOUND)) {
5090 fr_sbuff_t our_in = FR_SBUFF(in);
5091 fr_sbuff_adv_until(&our_in, SIZE_MAX, rules->terminals,
5092 rules->escapes ? rules->escapes->chr : '\0');
5093
5094 fr_strerror_printf("Invalid enumeration value \"%pV\" for attribute %s",
5096 dst_enumv->name);
5097 return -1;
5098 }
5099
5101 fr_strerror_printf("Failed parsing string as type '%s'",
5102 fr_type_to_str(dst_type));
5103 } else {
5104 fr_sbuff_parse_error_to_strerror(err);
5105 }
5106 }
5107
5108
5109 return slen;
5110}
5111
5112/** Convert string value to a fr_value_box_t type
5113 *
5114 * @param[in] ctx to alloc strings in.
5115 * @param[out] dst where to write parsed value.
5116 * @param[in,out] dst_type of value data to create/dst_type of value created.
5117 * @param[in] dst_enumv fr_dict_attr_t with string names for uint32 values.
5118 * @param[in] in sbuff to read data from.
5119 * @param[in] rules unescape and termination rules.
5120 * @return
5121 * - >0 on success.
5122 * - <= 0 on parse error.
5123 */
5125 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
5126 fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules)
5127{
5128 static fr_sbuff_parse_rules_t default_rules;
5129 fr_sbuff_t *unescaped = NULL;
5130 fr_sbuff_t our_in = FR_SBUFF(in);
5131 fr_ipaddr_t addr;
5132 fr_slen_t slen;
5133 char buffer[256];
5134
5135 if (!rules) rules = &default_rules;
5136
5138
5139 /*
5140 * Lookup any names before continuing
5141 */
5142 if (dst_enumv && dst_enumv->flags.has_value && (dst_type != FR_TYPE_ATTR)) {
5143 size_t name_len;
5144 fr_dict_enum_value_t const *enumv;
5145
5146 /*
5147 * @todo - allow enum names for IPv6 addresses and prefixes. See also
5148 * tmpl_afrom_enum().
5149 */
5150 (void) fr_sbuff_adv_past_str_literal(&our_in, "::");
5151
5152 /*
5153 * If there is no escaping, then we ignore the terminals. The list of allowed characters
5154 * in enum names will ensure that the parsing doesn't go too far. i.e. to '\r', '\n'. '}', etc.
5155 *
5156 * The reason is that the list of terminals may include things like '-', which is also a
5157 * valid character in enum names. We don't want to parse "Framed-User" as "Framed - User".
5158 */
5159 if (!rules->escapes) {
5160 size_t len;
5162
5163 fr_sbuff_marker(&m, &our_in);
5164
5165 len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in),
5167 fr_sbuff_set(&our_in, &m);
5168 fr_sbuff_marker_release(&m);
5169
5170 if (!len) goto parse; /* Zero length name can't match enum */
5171
5172 enumv = fr_dict_enum_by_name(dst_enumv, fr_sbuff_current(&our_in), len);
5173 if (!enumv) {
5174 goto parse; /* No enumeration matches escaped string */
5175 }
5176
5177 (void) fr_sbuff_advance(&our_in, len);
5178 goto cast_enum;
5179 }
5180
5181 /*
5182 * Create a thread-local extensible buffer to
5183 * store unescaped data.
5184 *
5185 * This is created once per-thread (the first time
5186 * this function is called), and freed when the
5187 * thread exits.
5188 */
5189 FR_SBUFF_TALLOC_THREAD_LOCAL(&unescaped, 256, 4096);
5190
5191 /*
5192 * This function only does escaping until a terminal character, such as '-'. So
5193 * Framed-User will get parsed as "Framed - User".
5194 *
5195 * Pretty much no other enum has this problem. For Service-Type, it defines "Framed" ss
5196 * an equivalent name to "Framed-User". The parser sees "Framed-User", stops at the '-',
5197 * and then finds the enum named "Framed". It then returns the trailing "-User" as
5198 * something more to parse.
5199 *
5200 * As a result, when the user passes in "Framed-User", the output is "Framed-User -
5201 * User", which is more than a bit surprising.
5202 */
5203 name_len = fr_sbuff_out_unescape_until(unescaped, &our_in, SIZE_MAX,
5204 rules->terminals, rules->escapes);
5205 if (!name_len) {
5206 fr_sbuff_set_to_start(&our_in);
5207 goto parse; /* Zero length name can't match enum */
5208 }
5209
5210 enumv = fr_dict_enum_by_name(dst_enumv, fr_sbuff_start(unescaped), fr_sbuff_used(unescaped));
5211 if (!enumv) {
5212 fr_sbuff_set_to_start(&our_in);
5213 goto parse; /* No enumeration matches escaped string */
5214 }
5215
5216 cast_enum:
5217 /*
5218 * dst_type may not match enumv type
5219 */
5220 if (fr_value_box_cast(ctx, dst, dst_type, dst_enumv, enumv->value) < 0) return -1;
5221
5222 FR_SBUFF_SET_RETURN(in, &our_in);
5223 }
5224
5225parse:
5226 /*
5227 * It's a variable ret src->dst_type so we just alloc a new buffer
5228 * of size len and copy.
5229 */
5230 switch (dst_type) {
5231 case FR_TYPE_STRING:
5232 /*
5233 * We've not unescaped the string yet, produce an unescaped version
5234 */
5235 if (!dst_enumv || !unescaped) {
5236 char *buff;
5237
5238 if (unlikely(fr_sbuff_out_aunescape_until(ctx, &buff, &our_in, SIZE_MAX,
5239 rules->terminals, rules->escapes) < 0)) {
5240 return -1;
5241 }
5242 fr_value_box_bstrdup_buffer_shallow(NULL, dst, dst_enumv, buff, false);
5243 /*
5244 * We already have an unescaped version, just use that
5245 */
5246 } else {
5247 fr_value_box_bstrndup(ctx, dst, dst_enumv,
5248 fr_sbuff_start(unescaped), fr_sbuff_used(unescaped), false);
5249 }
5250 FR_SBUFF_SET_RETURN(in, &our_in);
5251
5252 /* raw octets: 0x01020304... */
5253 case FR_TYPE_OCTETS:
5254 {
5255 fr_sbuff_marker_t hex_start;
5256 size_t hex_len;
5257 uint8_t *bin_buff;
5258
5259 /*
5260 * If there's escape sequences that need to be processed
5261 * or the string doesn't start with 0x, then assume this
5262 * is literal data, not hex encoded data.
5263 */
5264 if (rules->escapes || !fr_sbuff_adv_past_strcase_literal(&our_in, "0x")) {
5265 if (!dst_enumv || !unescaped) {
5266 char *buff = NULL;
5267 uint8_t *bin;
5268
5269 if (fr_sbuff_extend(&our_in)) {
5270 fr_sbuff_out_aunescape_until(ctx, &buff, &our_in, SIZE_MAX,
5271 rules->terminals, rules->escapes);
5272
5273 if (talloc_array_length(buff) == 1) {
5275 goto zero;
5276 }
5277
5278 bin = talloc_realloc(ctx, buff, uint8_t, talloc_array_length(buff) - 1);
5279 if (unlikely(!bin)) {
5280 fr_strerror_const("Failed trimming string buffer");
5282 return -1;
5283 }
5284 talloc_set_type(bin, uint8_t); /* talloc_realloc doesn't do this */
5285 /*
5286 * Input data is zero
5287 *
5288 * talloc realloc will refuse to realloc to
5289 * a zero length buffer. This is probably
5290 * a bug, because we can create zero length
5291 * arrays normally
5292 */
5293 } else {
5294 zero:
5295 bin = talloc_zero_array(ctx, uint8_t, 0);
5296 }
5297
5298 fr_value_box_memdup_buffer_shallow(NULL, dst, dst_enumv, bin, false);
5299 /*
5300 * We already have an unescaped version, just use that
5301 */
5302 } else {
5303 fr_value_box_memdup(ctx, dst, dst_enumv,
5304 (uint8_t *)fr_sbuff_start(unescaped),
5305 fr_sbuff_used(unescaped), false);
5306 }
5307 FR_SBUFF_SET_RETURN(in, &our_in);
5308 }
5309
5310 fr_sbuff_marker(&hex_start, &our_in); /* Record where the hexits start */
5311
5312 /*
5313 * Find the end of the hex sequence.
5314 *
5315 * We don't technically need to do this, fr_base16_decode
5316 * will find the end on its own.
5317 *
5318 * We do this so we can alloc the correct sized
5319 * output buffer.
5320 */
5321 hex_len = fr_sbuff_adv_past_allowed(&our_in, SIZE_MAX, sbuff_char_class_hex, rules->terminals);
5322 if (hex_len == 0) {
5323 if (fr_value_box_memdup(ctx, dst, dst_enumv, (uint8_t[]){ 0x00 }, 0, false) < 0) return -1;
5324 FR_SBUFF_SET_RETURN(in, &our_in);
5325 }
5326
5327 if ((hex_len & 0x01) != 0) {
5328 fr_strerror_printf("Length of hex string is not even, got %zu bytes", hex_len);
5329 FR_SBUFF_ERROR_RETURN(&our_in);
5330 }
5331
5332 /*
5333 * Pre-allocate the bin buff and initialise the box
5334 */
5335 if (fr_value_box_mem_alloc(ctx, &bin_buff, dst, dst_enumv, (hex_len >> 1), false) < 0) return -1;
5336
5337 /*
5338 * Reset to the start of the hex string
5339 */
5340 fr_sbuff_set(&our_in, &hex_start);
5341
5342 if (unlikely(fr_base16_decode(NULL, &FR_DBUFF_TMP(bin_buff, hex_len), &our_in, false) < 0)) {
5343 talloc_free(bin_buff);
5344 FR_SBUFF_ERROR_RETURN(&our_in);
5345 }
5346
5347 FR_SBUFF_SET_RETURN(in, &our_in);
5348 }
5349
5350 case FR_TYPE_IPV4_ADDR:
5351 {
5352 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5353 if (!name_len) return 0;
5354
5355 if (fr_inet_pton4(&addr, fr_sbuff_current(in), name_len,
5356 fr_hostname_lookups, false, true) < 0) return -1;
5357
5358 /*
5359 * We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
5360 * print them this way.
5361 */
5362 if (addr.prefix != 32) {
5363 fail_ipv4_prefix:
5364 fr_strerror_printf("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted "
5365 "for non-prefix types", addr.prefix);
5366 return -1;
5367 }
5368
5369 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5370 }
5371 goto finish;
5372
5374 {
5375 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5376 if (!name_len) return 0;
5377
5378 if (fr_inet_pton4(&dst->vb_ip, fr_sbuff_current(in), name_len,
5379 fr_hostname_lookups, false, true) < 0) return -1;
5380 }
5381 goto finish;
5382
5383 case FR_TYPE_IPV6_ADDR:
5384 {
5385 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5386 if (!name_len) return 0;
5387
5388 /*
5389 * Parse scope, too.
5390 */
5391 if (fr_sbuff_next_if_char(&our_in, '%')) {
5392 name_len += fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_uint, rules->terminals);
5393 }
5394
5395 if (fr_inet_pton6(&addr, fr_sbuff_current(in), name_len,
5396 fr_hostname_lookups, false, true) < 0) return -1;
5397
5398 /*
5399 * We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
5400 * print them this way.
5401 */
5402 if (addr.prefix != 128) {
5403 fail_ipv6_prefix:
5404 fr_strerror_printf("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted "
5405 "for non-prefix types", addr.prefix);
5406 return -1;
5407 }
5408
5409 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5410 }
5411 goto finish;
5412
5414 {
5415 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5416 if (!name_len) return 0;
5417
5418 if (fr_inet_pton6(&dst->vb_ip, fr_sbuff_current(in), name_len,
5419 fr_hostname_lookups, false, true) < 0) return -1;
5420 }
5421 goto finish;
5422
5424 {
5425 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5426 if (!name_len) return 0;
5427
5428 /*
5429 * Parse scope, too.
5430 */
5431 if (fr_sbuff_next_if_char(&our_in, '%')) {
5432 name_len += fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_uint, rules->terminals);
5433 }
5434
5435 if (fr_inet_pton(&addr, fr_sbuff_current(in), name_len, AF_UNSPEC,
5436 fr_hostname_lookups, true) < 0) return -1;
5437
5438 if ((addr.af == AF_INET) && (addr.prefix != 32)) {
5439 goto fail_ipv4_prefix;
5440 }
5441
5442 if ((addr.af == AF_INET6) && (addr.prefix != 128)) {
5443 goto fail_ipv6_prefix;
5444 }
5445
5446 memcpy(&dst->vb_ip, &addr, sizeof(dst->vb_ip));
5447 }
5448 goto finish;
5449
5451 {
5452 size_t name_len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in), sbuff_char_class_hostname, rules->terminals);
5453 if (!name_len) return 0;
5454
5455 if (fr_inet_pton(&dst->vb_ip, fr_sbuff_current(in), name_len, AF_UNSPEC,
5456 fr_hostname_lookups, true) < 0) return -1;
5457 }
5458 goto finish;
5459
5460 case FR_TYPE_UINT8:
5461 case FR_TYPE_UINT16:
5462 case FR_TYPE_UINT32:
5463 case FR_TYPE_UINT64:
5464 case FR_TYPE_INT8:
5465 case FR_TYPE_INT16:
5466 case FR_TYPE_INT32:
5467 case FR_TYPE_INT64:
5468 case FR_TYPE_FLOAT32:
5469 case FR_TYPE_FLOAT64:
5470 return fr_value_box_from_numeric_substr(dst, dst_type, dst_enumv, in, rules, false);
5471
5472 case FR_TYPE_SIZE:
5473 if (fr_size_from_str(&dst->datum.size, &our_in) < 0) return -1;
5474 goto finish;
5475
5476 case FR_TYPE_BOOL:
5477 fr_value_box_init(dst, dst_type, dst_enumv, false);
5478
5479 /*
5480 * Quoted boolean values are "yes", "no", "true", "false"
5481 */
5482 slen = fr_sbuff_out(NULL, &dst->vb_bool, in);
5483 if (slen >= 0) return slen;
5484
5485 /*
5486 * For barewords we also allow 0 for false and any other
5487 * integer value for true.
5488 */
5489 if (!rules->escapes) {
5490 int64_t stmp;
5491 uint64_t utmp;
5492
5493 slen = fr_sbuff_out(NULL, &stmp, in);
5494 if (slen >= 0) {
5495 dst->vb_bool = (stmp != 0);
5496 return slen;
5497 }
5498
5499 slen = fr_sbuff_out(NULL, &utmp, in);
5500 if (slen >= 0) {
5501 dst->vb_bool = (utmp != 0);
5502 return slen;
5503 }
5504 }
5505
5506 fr_strerror_const("Invalid boolean value. Accepted values are "
5507 "\"yes\", \"no\", \"true\", \"false\" or any unquoted integer");
5508
5509 return slen; /* Just whatever the last error offset was */
5510
5511 case FR_TYPE_ETHERNET:
5512 {
5513 uint64_t num;
5514 fr_ethernet_t ether;
5515 fr_dbuff_t dbuff;
5517
5518 fr_dbuff_init(&dbuff, ether.addr, sizeof(ether.addr));
5519
5520 /*
5521 * Convert things which are obviously integers to Ethernet addresses
5522 *
5523 * We assume the number is the decimal
5524 * representation of the ethernet address.
5525 * i.e. the ethernet address converted to a
5526 * number, and printed.
5527 *
5528 * The string gets converted to a network-order
5529 * 8-byte number, and then the lower bytes of
5530 * that get copied to the ethernet address.
5531 *
5532 * Note: We need to check for a terminal sequence
5533 * after the number, else we may just end up
5534 * parsing the first hexit and returning.
5535 *
5536 * i.e. 1c:00:00:00:00 -> 1
5537 */
5538 if ((fr_sbuff_out(NULL, &num, &our_in) > 0) && fr_sbuff_is_terminal(&our_in, rules->terminals)) {
5539 num = htonll(num);
5540
5541 FR_DBUFF_IN_MEMCPY_RETURN(&dbuff, ((uint8_t *) &num) + 2, sizeof(dst->vb_ether));
5542 fr_value_box_ethernet_addr(dst, dst_enumv, &ether, false);
5543
5544 FR_SBUFF_SET_RETURN(in, &our_in);
5545 }
5546
5547 fr_sbuff_set_to_start(&our_in);
5548
5549 fr_base16_decode(&err, &dbuff, &our_in, true);
5550 if (err != FR_SBUFF_PARSE_OK) {
5551 ether_error:
5552 fr_sbuff_parse_error_to_strerror(err);
5553 FR_SBUFF_ERROR_RETURN(&our_in);
5554 }
5555
5556 if (!fr_sbuff_next_if_char(&our_in, ':')) {
5557 ether_sep_error:
5558 fr_strerror_const("Missing separator, expected ':'");
5559 FR_SBUFF_ERROR_RETURN(&our_in);
5560 }
5561
5562 fr_base16_decode(&err, &dbuff, &our_in, true);
5563 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5564
5565 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5566
5567 fr_base16_decode(&err, &dbuff, &our_in, true);
5568 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5569
5570 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5571
5572 fr_base16_decode(&err, &dbuff, &our_in, true);
5573 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5574
5575 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5576
5577 fr_base16_decode(&err, &dbuff, &our_in, true);
5578 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5579
5580 if (!fr_sbuff_next_if_char(&our_in, ':')) goto ether_sep_error;
5581
5582 fr_base16_decode(&err, &dbuff, &our_in, true);
5583 if (err != FR_SBUFF_PARSE_OK) goto ether_error;
5584
5585 fr_value_box_ethernet_addr(dst, dst_enumv, (fr_ethernet_t * const)fr_dbuff_start(&dbuff), false);
5586
5587 FR_SBUFF_SET_RETURN(in, &our_in);
5588 }
5589
5590 case FR_TYPE_TIME_DELTA:
5591 fr_value_box_init(dst, FR_TYPE_TIME_DELTA, dst_enumv, false);
5592
5593 slen = fr_time_delta_from_substr(&dst->datum.time_delta, &our_in,
5594 dst_enumv ? dst_enumv->flags.flag_time_res : FR_TIME_RES_SEC,
5595 false, rules->terminals);
5596 if (slen < 0) return slen;
5597 FR_SBUFF_SET_RETURN(in, &our_in);
5598
5599 case FR_TYPE_NULL:
5600 if (!rules->escapes && fr_sbuff_adv_past_str_literal(&our_in, "NULL")) {
5601 fr_value_box_init(dst, dst_type, dst_enumv, false);
5602 FR_SBUFF_SET_RETURN(in, &our_in);
5603 }
5604
5605 fr_strerror_const("Unexpected value for data type NULL");
5606 return -1;
5607
5608 case FR_TYPE_ATTR:
5609 if (!dst_enumv) {
5610 fr_strerror_const("No dictionary passed for data type 'attr'");
5611 return -1;
5612 }
5613
5614 /*
5615 * @todo - have attributes of FR_TYPE_ATTR also
5616 * carry a ref to where their values are taken from.
5617 */
5618 if (dst_enumv->type == FR_TYPE_ATTR) {
5619 dst_enumv = fr_dict_root(dst_enumv->dict);
5620
5621 } else if (!dst_enumv->flags.is_root) {
5622 fr_strerror_printf("Can only start from dictionary root for data type 'attr', and not from %s", dst_enumv->name);
5623 return -1;
5624 }
5625
5626 fr_value_box_init(dst, dst_type, dst_enumv, false);
5627
5628 /*
5629 * Allow '@' references in values.
5630 */
5631 if (fr_sbuff_is_char(&our_in, '@')) {
5632 size_t len;
5634
5635 fr_sbuff_marker(&m, &our_in);
5636 fr_sbuff_advance(&our_in, 1); /* '@' is not an allowed character for dictionary names */
5637
5638 len = fr_sbuff_adv_past_allowed(&our_in, fr_sbuff_remaining(&our_in),
5640 fr_sbuff_set(&our_in, &m);
5641 fr_sbuff_marker_release(&m);
5642
5643 len++; /* account for '@' */
5644
5645 /*
5646 * This function needs the '@'.
5647 */
5648 if (fr_dict_protocol_reference(&dst->vb_attr, fr_dict_root(dst_enumv->dict), &FR_SBUFF_IN(fr_sbuff_current(&our_in), len)) < 0) {
5649 return -1;
5650 }
5651
5652 if (!dst->vb_attr) {
5653 fr_strerror_printf("Failed to find attribute reference %.*s", (int) len, fr_sbuff_current(&our_in));
5654 return -1;
5655 }
5656
5657 fr_assert(dst->vb_attr != NULL);
5658
5659 if (dst->vb_attr->dict != dst_enumv->dict) {
5660 fr_strerror_const("Type 'attribute' cannot reference a different protocol");
5661 return -1;
5662 }
5663
5664 fr_sbuff_advance(&our_in, len);
5665 FR_SBUFF_SET_RETURN(in, &our_in);
5666
5667 } else if (fr_sbuff_adv_past_str_literal(&our_in, "::")) {
5668
5669 slen = fr_dict_attr_by_oid_substr(NULL, &dst->vb_attr, dst_enumv, &our_in, rules->terminals);
5670 if (slen > 0) {
5671 fr_assert(dst->vb_attr != NULL);
5672 FR_SBUFF_SET_RETURN(in, &our_in);
5673 }
5674 }
5675
5676 slen = fr_dict_attr_unknown_afrom_oid_substr(ctx, &dst->vb_attr, dst_enumv, &our_in, FR_TYPE_OCTETS);
5677 if (slen <= 0) {
5678 fr_strerror_printf("Failed to find the named attribute in %s", dst_enumv->name);
5679 return -2;
5680 }
5681
5682 fr_assert(dst->vb_attr != NULL);
5683 FR_SBUFF_SET_RETURN(in, &our_in);
5684
5685 /*
5686 * Dealt with below
5687 */
5688 default:
5689 break;
5690 }
5691
5692 /*
5693 * We may have terminals. If so, respect them.
5694 */
5695 if (rules && rules->terminals) {
5696 size_t len;
5697
5698 len = fr_sbuff_out_unescape_until(&FR_SBUFF_OUT(buffer, sizeof(buffer)), &our_in, SIZE_MAX,
5699 rules->terminals, rules->escapes);
5700 if (len >= sizeof(buffer)) goto too_small;
5701
5702 buffer[len] = '\0';
5703
5704 } else {
5705 /*
5706 * It's a fixed size src->dst_type, copy to a temporary buffer and
5707 * \0 terminate.
5708 *
5709 * @todo - note that this brute-force copy means that the input sbuff
5710 * is NOT advanced, and this function will return 0, even though it parsed data!
5711 */
5712 if (fr_sbuff_remaining(in) >= sizeof(buffer)) {
5713 too_small:
5714 fr_strerror_const("Temporary buffer too small");
5715 return -1;
5716 }
5717
5719 buffer[fr_sbuff_remaining(in)] = '\0';
5720 }
5721
5722 switch (dst_type) {
5723 case FR_TYPE_DATE:
5724 {
5725 if (dst_enumv) {
5726 if (fr_unix_time_from_str(&dst->vb_date, buffer, dst_enumv->flags.flag_time_res) < 0) return -1;
5727 } else {
5728 if (fr_unix_time_from_str(&dst->vb_date, buffer, FR_TIME_RES_SEC) < 0) return -1;
5729 }
5730
5731 dst->enumv = dst_enumv;
5732 }
5733 break;
5734
5735 case FR_TYPE_IFID:
5736 if (fr_inet_ifid_pton((void *) dst->vb_ifid, buffer) == NULL) {
5737 fr_strerror_printf("Failed to parse interface-id string \"%s\"", buffer);
5738 return -1;
5739 }
5740 break;
5741
5742 default:
5743 fr_strerror_printf("Cannot parse input as data type %s", fr_type_to_str(dst_type));
5744 return -1;
5745 }
5746
5747finish:
5748 dst->type = dst_type;
5749 dst->tainted = false;
5751
5752 /*
5753 * Fixup enumvs
5754 */
5755 dst->enumv = dst_enumv;
5756 fr_value_box_list_entry_init(dst);
5757
5758 FR_SBUFF_SET_RETURN(in, &our_in);
5759}
5760
5762 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
5763 char const *in, size_t inlen,
5764 fr_sbuff_unescape_rules_t const *erules)
5765{
5766 ssize_t slen;
5767 fr_sbuff_parse_rules_t prules = { .escapes = erules };
5768
5769 slen = fr_value_box_from_substr(ctx, dst, dst_type, dst_enumv, &FR_SBUFF_IN(in, inlen), &prules);
5770 if (slen <= 0) return slen;
5771
5772 if (slen != (ssize_t)inlen) {
5773 fr_strerror_printf("Failed parsing '%s'. %zu bytes of trailing data after string value \"%pV\"",
5774 fr_type_to_str(dst_type),
5775 inlen - slen,
5776 fr_box_strvalue_len(in + slen, inlen - slen));
5777 return (slen - inlen) - 1;
5778 }
5779
5780 return slen;
5781}
5782
5783/** Print one boxed value to a string
5784 *
5785 * This function should primarily be used when a #fr_value_box_t is being
5786 * serialized in some non-standard way, i.e. as a value for a field
5787 * in a database, in all other instances it's better to use
5788 * #fr_value_box_print_quoted.
5789 *
5790 * @note - this function does NOT respect tainting! The escaping rules
5791 * are ONLY for escaping quotation characters, CR, LF, etc.
5792 *
5793 * @param[in] out Where to write the printed string.
5794 * @param[in] data Value box to print.
5795 * @param[in] e_rules To apply to FR_TYPE_STRING types, for escaping quotation characters _only_.
5796 * Is not currently applied to any other box type.
5797 */
5799{
5800 fr_sbuff_t our_out = FR_SBUFF(out);
5801
5802 char buf[1024]; /* Interim buffer to use with poorly behaved printing functions */
5803
5804 if (data->enumv && data->enumv->flags.has_value) {
5805 char const *name;
5806
5808 if (name) {
5809 FR_SBUFF_IN_ESCAPE_BUFFER_RETURN(&our_out, name, NULL);
5810 goto done;
5811 }
5812 }
5813
5814 switch (data->type) {
5815 case FR_TYPE_STRING:
5816 if (data->vb_length) FR_SBUFF_IN_ESCAPE_RETURN(&our_out,
5817 data->vb_strvalue, data->vb_length, e_rules);
5818 break;
5819
5820 case FR_TYPE_OCTETS:
5821 FR_SBUFF_IN_CHAR_RETURN(&our_out, '0', 'x');
5822 if (data->vb_length) FR_SBUFF_RETURN(fr_base16_encode, &our_out,
5823 &FR_DBUFF_TMP(data->vb_octets, data->vb_length));
5824 break;
5825
5826 /*
5827 * We need to use the proper inet_ntop functions for IP
5828 * addresses, else the output might not match output of
5829 * other functions, which makes testing difficult.
5830 *
5831 * An example is tunneled ipv4 in ipv6 addresses.
5832 */
5833 case FR_TYPE_IPV4_ADDR:
5834 case FR_TYPE_IPV6_ADDR:
5836 if (!fr_inet_ntop(buf, sizeof(buf), &data->vb_ip)) return 0;
5837 FR_SBUFF_IN_STRCPY_RETURN(&our_out, buf);
5838 break;
5839
5843 if (!fr_inet_ntop_prefix(buf, sizeof(buf), &data->vb_ip)) return 0;
5844 FR_SBUFF_IN_STRCPY_RETURN(&our_out, buf);
5845 break;
5846
5847 case FR_TYPE_IFID:
5848 if (!fr_inet_ifid_ntop(buf, sizeof(buf), data->vb_ifid)) return 0;
5849 FR_SBUFF_IN_STRCPY_RETURN(&our_out, buf);
5850 break;
5851
5852 case FR_TYPE_ETHERNET:
5853 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%02x:%02x:%02x:%02x:%02x:%02x",
5854 data->vb_ether[0], data->vb_ether[1],
5855 data->vb_ether[2], data->vb_ether[3],
5856 data->vb_ether[4], data->vb_ether[5]);
5857 break;
5858
5859 case FR_TYPE_BOOL:
5860 FR_SBUFF_IN_STRCPY_RETURN(&our_out, data->vb_uint8 ? "yes" : "no");
5861 break;
5862
5863 case FR_TYPE_UINT8:
5864 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", data->vb_uint8);
5865 break;
5866
5867 case FR_TYPE_UINT16:
5868 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", data->vb_uint16);
5869 break;
5870
5871 case FR_TYPE_UINT32:
5872 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", data->vb_uint32);
5873 break;
5874
5875 case FR_TYPE_UINT64:
5876 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%" PRIu64, data->vb_uint64);
5877 break;
5878
5879 case FR_TYPE_INT8:
5880 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%d", data->vb_int8);
5881 break;
5882
5883 case FR_TYPE_INT16:
5884 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%d", data->vb_int16);
5885 break;
5886
5887 case FR_TYPE_INT32:
5888 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%d", data->vb_int32);
5889 break;
5890
5891 case FR_TYPE_INT64:
5892 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%" PRId64, data->vb_int64);
5893 break;
5894
5895 case FR_TYPE_FLOAT32:
5896 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%f", (double) data->vb_float32);
5897 break;
5898
5899 case FR_TYPE_FLOAT64:
5900 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%g", data->vb_float64);
5901 break;
5902
5903 case FR_TYPE_DATE:
5904 {
5906
5907 if (data->enumv) res = data->enumv->flags.flag_time_res;
5908
5909 FR_SBUFF_RETURN(fr_unix_time_to_str, &our_out, data->vb_date, res, true);
5910 break;
5911 }
5912
5913 case FR_TYPE_SIZE:
5914 FR_SBUFF_RETURN(fr_size_to_str, &our_out, data->datum.size);
5915 break;
5916
5917 case FR_TYPE_TIME_DELTA:
5918 {
5920 bool is_unsigned = false;
5921
5922 if (data->enumv) {
5923 res = data->enumv->flags.flag_time_res;
5924 is_unsigned = data->enumv->flags.is_unsigned;
5925 }
5926
5927
5928 FR_SBUFF_RETURN(fr_time_delta_to_str, &our_out, data->vb_time_delta, res, is_unsigned);
5929 }
5930 break;
5931
5932 case FR_TYPE_GROUP:
5933 /*
5934 * If the caller didn't ask to escape binary data
5935 * in 'octets' types, then we force that now.
5936 * Otherwise any 'octets' type which is buried
5937 * inside of a 'group' will get copied verbatim
5938 * from input to output, with no escaping!
5939 */
5940 if (!e_rules || (!e_rules->do_oct && !e_rules->do_hex)) {
5941 e_rules = &fr_value_escape_double;
5942 }
5943
5944 /*
5945 * Represent groups as:
5946 *
5947 * { <value0>, <value1>, { <sub-value0>, <sub-value1>, <sub-valueN> }}
5948 */
5949 FR_SBUFF_IN_CHAR_RETURN(&our_out, '{');
5951 NULL, &our_out, UNCONST(fr_value_box_list_t *, &data->vb_group),
5952 ", ", (sizeof(", ") - 1), e_rules,
5954 FR_SBUFF_IN_CHAR_RETURN(&our_out, '}');
5955 break;
5956
5957 case FR_TYPE_ATTR:
5958 FR_SBUFF_IN_CHAR_RETURN(&our_out, ':', ':');
5959
5960 fr_assert(data->enumv != NULL);
5961
5962 /*
5963 * No escaping, just dump the name as-is.
5964 */
5965 if (!e_rules) {
5966 FR_DICT_ATTR_OID_PRINT_RETURN(&our_out, NULL, data->vb_attr, false);
5967 break;
5968 }
5969
5970 /*
5971 * Escaping, use an intermediate buffer. Because
5972 * we can't pipe sbuffs together.
5973 */
5974 {
5975 fr_sbuff_t *unescaped = NULL;
5976
5977 FR_SBUFF_TALLOC_THREAD_LOCAL(&unescaped, 256, 4096);
5978
5979 FR_DICT_ATTR_OID_PRINT_RETURN(unescaped, NULL, data->vb_attr, false);
5980
5981 FR_SBUFF_IN_ESCAPE_RETURN(&our_out, fr_sbuff_start(unescaped),
5982 fr_sbuff_used(unescaped), e_rules);
5983 }
5984 break;
5985
5986 case FR_TYPE_NULL:
5987 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "NULL");
5988 break;
5989
5990 /*
5991 * Don't add default here
5992 */
5993 case FR_TYPE_TLV: /* Not a box type */
5994 case FR_TYPE_STRUCT: /* Not a box type */
5995 case FR_TYPE_VSA: /* Not a box type */
5996 case FR_TYPE_VENDOR: /* Not a box type */
5997 case FR_TYPE_UNION: /* Not a box type */
5998 case FR_TYPE_VALUE_BOX:
5999 case FR_TYPE_VOID:
6000 case FR_TYPE_MAX:
6001 (void)fr_cond_assert(0);
6002 return 0;
6003
6006 FR_SBUFF_IN_STRCPY_RETURN(&our_out, data->vb_cursor_name);
6007 break;
6008 }
6009
6010done:
6011 FR_SBUFF_SET_RETURN(out, &our_out);
6012}
6013
6014/** Print one boxed value to a string with quotes (where needed)
6015 *
6016 * @param[in] out Where to write the printed string.
6017 * @param[in] data Value box to print.
6018 * @param[in] quote To apply to FR_TYPE_STRING types.
6019 * Is not currently applied to any
6020 * other box type.
6021 */
6023{
6024 fr_sbuff_t our_out = FR_SBUFF(out);
6025
6026 if (quote == T_BARE_WORD) return fr_value_box_print(out, data, NULL);
6027
6028 switch (data->type) {
6029 case FR_TYPE_QUOTED:
6030 FR_SBUFF_IN_CHAR_RETURN(&our_out, fr_token_quote[quote]);
6032 FR_SBUFF_IN_CHAR_RETURN(&our_out, fr_token_quote[quote]);
6033 break;
6034
6035 default:
6036 return fr_value_box_print(out, data, NULL);
6037 }
6038
6039 FR_SBUFF_SET_RETURN(out, &our_out);
6040}
6041
6042/** Concatenate a list of value boxes together
6043 *
6044 * All boxes will be removed from the list.
6045 *
6046 * @param[out] safety if !NULL, the results of tainted / secret / safe_for will be stored here.
6047 * @param[out] sbuff to write the result of the concatenation to.
6048 * @param[in] list to concatenate.
6049 * @param[in] sep Insert a separator between the values.
6050 * @param[in] sep_len Length of the separator.
6051 * @param[in] e_rules To apply to FR_TYPE_STRING types.
6052 * Is not currently applied to any other box type.
6053 * @param[in] proc_action What to do with the boxes in the list once
6054 * they've been processed.
6055 * @param[in] safe_for if value has this safe_for value, don't apply the escape rules.
6056 * for values which are escaped, mash the safe_for value to this.
6057 * @param[in] flatten If true and we encounter a #FR_TYPE_GROUP,
6058 * we concat the contents of its children together.
6059 * If false, the contents will be cast to #FR_TYPE_STRING.
6060 * @return
6061 * - >=0 the number of bytes written to the sbuff.
6062 * - <0 how many additional bytes we would have needed to
6063 * concat the next box.
6064 */
6065ssize_t fr_value_box_list_concat_as_string(fr_value_box_t *safety, fr_sbuff_t *sbuff, fr_value_box_list_t *list,
6066 char const *sep, size_t sep_len, fr_sbuff_escape_rules_t const *e_rules,
6067 fr_value_box_list_action_t proc_action, fr_value_box_safe_for_t safe_for, bool flatten)
6068{
6069 fr_sbuff_t our_sbuff = FR_SBUFF(sbuff);
6070 ssize_t slen;
6071
6072 if (fr_value_box_list_empty(list)) return 0;
6073
6074 fr_value_box_list_foreach(list, vb) {
6075 fr_value_box_safe_for_t box_safe_for = vb->safe_for;
6076
6077 switch (vb->type) {
6078 case FR_TYPE_GROUP:
6079 if (!flatten) goto print;
6080 slen = fr_value_box_list_concat_as_string(safety, &our_sbuff, &vb->vb_group,
6081 sep, sep_len, e_rules,
6082 proc_action, safe_for, flatten);
6083 break;
6084
6085 case FR_TYPE_OCTETS:
6086
6087 /*
6088 * Copy the raw string over, if necessary with escaping.
6089 */
6090 if (e_rules && (!fr_value_box_is_safe_for(vb, safe_for) || e_rules->do_oct || e_rules->do_hex)) {
6091 box_safe_for = safe_for;
6092
6093 slen = fr_sbuff_in_escape(&our_sbuff, (char const *)vb->vb_strvalue, vb->vb_length, e_rules);
6094 } else {
6095 slen = fr_sbuff_in_bstrncpy(&our_sbuff, (char const *)vb->vb_strvalue, vb->vb_length);
6096 }
6097 break;
6098
6099 case FR_TYPE_STRING:
6100 if (!fr_value_box_is_safe_for(vb, safe_for) && e_rules) goto print;
6101
6102 slen = fr_sbuff_in_bstrncpy(&our_sbuff, vb->vb_strvalue, vb->vb_length);
6103 break;
6104
6105 case FR_TYPE_NULL: /* Skip null */
6106 continue;
6107
6108 default:
6109 print:
6110 /*
6111 * If we escaped it, set the output safe_for value.
6112 */
6113 if (e_rules) box_safe_for = safe_for;
6114 slen = fr_value_box_print(&our_sbuff, vb, e_rules);
6115 break;
6116 }
6117 if (slen < 0) return slen;
6118
6119 /*
6120 * Add in the separator
6121 */
6122 if (sep && fr_value_box_list_next(list, vb)) {
6123 slen = fr_sbuff_in_bstrncpy(&our_sbuff, sep, sep_len);
6124 if (slen < 0) return slen;
6125 }
6126
6127 /*
6128 * Merge in the safety rules.
6129 */
6130 if (!safety || (vb->type == FR_TYPE_GROUP)) continue;
6131
6132 /*
6133 * We can't call fr_box_safety_merge(), as we may have escaped the input box.
6134 */
6135 if ((safety->safe_for != FR_VALUE_BOX_SAFE_FOR_NONE) &&
6136 (safety->safe_for != box_safe_for)) {
6137 if (safety->safe_for == FR_VALUE_BOX_SAFE_FOR_ANY) {
6138 safety->safe_for = box_safe_for;
6139 } else {
6140 safety->safe_for = FR_VALUE_BOX_SAFE_FOR_NONE;
6141 }
6142 }
6143
6144 safety->tainted |= vb->tainted;
6145 safety->secret |= vb->secret;
6146 }
6147
6148 /*
6149 * Free the boxes last so if there's
6150 * an issue concatenating them, everything
6151 * is still in a known state.
6152 */
6154 if (vb_should_remove(proc_action)) fr_value_box_list_remove(list, vb);
6155 if (vb_should_free_value(proc_action)) fr_value_box_clear_value(vb);
6156 if (vb_should_free(proc_action)) talloc_free(vb);
6157 }}
6158
6159 FR_SBUFF_SET_RETURN(sbuff, &our_sbuff);
6160}
6161
6162/** Concatenate a list of value boxes together
6163 *
6164 * All boxes will be removed from the list.
6165 *
6166 * @param[out] safety if !NULL, the results of tainted / secret / safe_for will be stored here.
6167 * @param[out] dbuff to write the result of the concatenation to.
6168 * @param[in] list to concatenate.
6169 * @param[in] sep Insert a separator between the values.
6170 * @param[in] sep_len Length of the separator.
6171 * @param[in] proc_action What to do with the boxes in the list once
6172 * they've been processed.
6173 * @param[in] flatten If true and we encounter a #FR_TYPE_GROUP,
6174 * we concat the contents of its children together.
6175 * If false, the contents will be cast to #FR_TYPE_OCTETS.
6176 * @return
6177 * - >=0 the number of bytes written to the sbuff.
6178 * - <0 how many additional bytes we would have needed to
6179 * concat the next box.
6180 */
6181ssize_t fr_value_box_list_concat_as_octets(fr_value_box_t *safety, fr_dbuff_t *dbuff, fr_value_box_list_t *list,
6182 uint8_t const *sep, size_t sep_len,
6183 fr_value_box_list_action_t proc_action, bool flatten)
6184{
6185 fr_dbuff_t our_dbuff = FR_DBUFF(dbuff);
6186 TALLOC_CTX *tmp_ctx = NULL;
6187 ssize_t slen;
6188
6189 if (fr_value_box_list_empty(list)) return 0;
6190
6191 fr_value_box_list_foreach(list, vb) {
6192 switch (vb->type) {
6193 case FR_TYPE_GROUP:
6194 if (!flatten) goto cast;
6195 slen = fr_value_box_list_concat_as_octets(safety, &our_dbuff, &vb->vb_group,
6196 sep, sep_len,
6197 proc_action, flatten);
6198 break;
6199
6200 case FR_TYPE_OCTETS:
6201 slen = fr_dbuff_in_memcpy(&our_dbuff, vb->vb_octets, vb->vb_length);
6202 break;
6203
6204 case FR_TYPE_STRING:
6205 slen = fr_dbuff_in_memcpy(&our_dbuff, (uint8_t const *)vb->vb_strvalue, vb->vb_length);
6206 break;
6207
6208 case FR_TYPE_NULL: /* Skip null */
6209 continue;
6210
6211 default:
6212 cast:
6213 {
6214 fr_value_box_t tmp_vb;
6215
6216 if (!tmp_ctx) tmp_ctx = talloc_pool(NULL, 1024);
6217
6218 /*
6219 * Not equivalent to fr_value_box_to_network
6220 */
6221 if (fr_value_box_cast_to_octets(tmp_ctx, &tmp_vb, FR_TYPE_OCTETS, NULL, vb) < 0) {
6222 slen = -1;
6223 goto error;
6224 }
6225
6226 slen = fr_dbuff_in_memcpy(&our_dbuff, tmp_vb.vb_octets, tmp_vb.vb_length);
6227 fr_value_box_clear_value(&tmp_vb);
6228 break;
6229 }
6230 }
6231
6232 if (slen < 0) {
6233 error:
6234 talloc_free(tmp_ctx);
6235 return slen;
6236 }
6237
6238 if (sep && fr_value_box_list_next(list, vb)) {
6239 slen = fr_dbuff_in_memcpy(&our_dbuff, sep, sep_len);
6240 if (slen < 0) goto error;
6241 }
6242
6243 fr_value_box_safety_merge(safety, vb);
6244 }
6245
6246 talloc_free(tmp_ctx);
6247
6248 /*
6249 * Free the boxes last so if there's
6250 * an issue concatenating them, everything
6251 * is still in a known state.
6252 */
6254 if (vb_should_remove(proc_action)) fr_value_box_list_remove(list, vb);
6255 if (vb_should_free_value(proc_action)) fr_value_box_clear_value(vb);
6256 if (vb_should_free(proc_action)) talloc_free(vb);
6257 }}
6258
6259 return fr_dbuff_set(dbuff, &our_dbuff);
6260}
6261
6262/** Concatenate a list of value boxes
6263 *
6264 * @note Will automatically cast all #fr_value_box_t to type specified.
6265 *
6266 * @param[in] ctx to allocate new value buffer in.
6267 * @param[out] out Where to write the resulting box.
6268 * @param[in] list to concatenate together.
6269 * @param[in] type May be #FR_TYPE_STRING or #FR_TYPE_OCTETS, no other types are
6270 * supported.
6271 * @param[in] proc_action What to do with the boxes in the list once
6272 * they've been processed.
6273 * @param[in] flatten If true and we encounter a #FR_TYPE_GROUP,
6274 * we concat the contents of its children together.
6275 * If false, the contents will be cast to the given type.
6276 * @param[in] max_size of the value.
6277 * @return
6278 * - 0 on success.
6279 * - -1 on failure.
6280 */
6282 fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type,
6283 fr_value_box_list_action_t proc_action, bool flatten,
6284 size_t max_size)
6285{
6286 fr_dbuff_t dbuff; /* FR_TYPE_OCTETS */
6287 fr_dbuff_uctx_talloc_t dbuff_tctx;
6288
6289 fr_sbuff_t sbuff; /* FR_TYPE_STRING */
6290 fr_sbuff_uctx_talloc_t sbuff_tctx;
6291
6292 fr_value_box_t *head_vb = fr_value_box_list_head(list);
6293
6294 fr_value_box_entry_t entry;
6295
6296 if (fr_value_box_list_empty(list)) {
6297 fr_strerror_const("Invalid arguments. List contains no elements");
6298 return -1;
6299 }
6300
6301 /*
6302 * Exit quickly if the list is only one box of the correct type and
6303 * out points at that box.
6304 */
6305 if ((fr_value_box_list_num_elements(list) == 1) && (head_vb == out) && (head_vb->type == type)) return 0;
6306
6307 switch (type) {
6308 case FR_TYPE_STRING:
6309 if (unlikely(!fr_sbuff_init_talloc(ctx, &sbuff, &sbuff_tctx, 256, max_size))) return -1;
6310 break;
6311
6312 case FR_TYPE_OCTETS:
6313 if (unlikely(!fr_dbuff_init_talloc(ctx, &dbuff, &dbuff_tctx, 256, max_size))) return -1;
6314 break;
6315
6316 default:
6317 fr_strerror_printf("Invalid argument. Can't concatenate boxes to type %s",
6319 return -1;
6320 }
6321
6322 /*
6323 * Merge all siblings into list head.
6324 *
6325 * This is where the first element in the
6326 * list is the output box.
6327 *
6328 * i.e. we want to merge all its siblings
6329 * into it.
6330 */
6331 if (out == head_vb) {
6332 switch (type) {
6333 case FR_TYPE_STRING:
6334 /*
6335 * Head gets dealt with specially as we don't
6336 * want to free it, and we don't want to free
6337 * the buffer associated with it (just yet).
6338 *
6339 * Note that we don't convert 'octets' to a printable string
6340 * here. Doing so breaks the keyword tests.
6341 */
6342 if (fr_value_box_list_concat_as_string(out, &sbuff, list,
6343 NULL, 0, NULL,
6345 fr_strerror_printf("Concatenation exceeded max_size (%zu)", max_size);
6346 error:
6347 switch (type) {
6348 case FR_TYPE_STRING:
6349 talloc_free(fr_sbuff_buff(&sbuff));
6350 break;
6351
6352 case FR_TYPE_OCTETS:
6353 talloc_free(fr_dbuff_buff(&dbuff));
6354 break;
6355
6356 default:
6357 break;
6358 }
6359 return -1;
6360 }
6361
6362 /*
6363 * Concat the rest of the children...
6364 */
6365 if (fr_value_box_list_concat_as_string(out, &sbuff, list,
6366 NULL, 0, NULL,
6367 proc_action, FR_VALUE_BOX_SAFE_FOR_ANY, flatten) < 0) {
6368 fr_value_box_list_insert_head(list, head_vb);
6369 goto error;
6370 }
6371 (void)fr_sbuff_trim_talloc(&sbuff, SIZE_MAX);
6373 if (fr_value_box_bstrndup(ctx, out, NULL, fr_sbuff_buff(&sbuff), fr_sbuff_used(&sbuff), out->tainted) < 0) goto error;
6374 break;
6375
6376 case FR_TYPE_OCTETS:
6377 if (fr_value_box_list_concat_as_octets(out, &dbuff, list,
6378 NULL, 0,
6379 FR_VALUE_BOX_LIST_REMOVE, flatten) < 0) goto error;
6380
6381 if (fr_value_box_list_concat_as_octets(out, &dbuff, list,
6382 NULL, 0,
6383 proc_action, flatten) < 0) {
6384 fr_value_box_list_insert_head(list, head_vb);
6385 goto error;
6386 }
6387 (void)fr_dbuff_trim_talloc(&dbuff, SIZE_MAX);
6389 if (fr_value_box_memdup(ctx, out, NULL, fr_dbuff_buff(&dbuff), fr_dbuff_used(&dbuff), out->tainted) < 0) goto error;
6390 break;
6391
6392 default:
6393 break;
6394 }
6395
6396 fr_value_box_list_insert_head(list, out);
6397
6398 /*
6399 * Merge all the boxes in the list into
6400 * a single contiguous buffer.
6401 *
6402 * This deals with an unrelated out and list
6403 * and also where list is the children of
6404 * out.
6405 */
6406 } else {
6407 switch (type) {
6408 case FR_TYPE_STRING:
6409 if (fr_value_box_list_concat_as_string(out, &sbuff, list,
6410 NULL, 0, NULL,
6411 proc_action, FR_VALUE_BOX_SAFE_FOR_ANY, flatten) < 0) goto error;
6412 (void)fr_sbuff_trim_talloc(&sbuff, SIZE_MAX);
6413
6414 entry = out->entry;
6415 if (fr_value_box_bstrndup(ctx, out, NULL, fr_sbuff_buff(&sbuff), fr_sbuff_used(&sbuff), out->tainted) < 0) goto error;
6416 out->entry = entry;
6417 break;
6418
6419 case FR_TYPE_OCTETS:
6420 if (fr_value_box_list_concat_as_octets(out, &dbuff, list,
6421 NULL, 0,
6422 proc_action, flatten) < 0) goto error;
6423 (void)fr_dbuff_trim_talloc(&dbuff, SIZE_MAX);
6424
6425 entry = out->entry;
6426 if (fr_value_box_memdup(ctx, out, NULL, fr_dbuff_buff(&dbuff), fr_dbuff_used(&dbuff), out->tainted) < 0) goto error;
6427 out->entry = entry;
6428 break;
6429
6430 default:
6431 break;
6432 }
6433 }
6434
6435 return 0;
6436}
6437
6438/** Escape a single value box in place
6439 *
6440 * @note Applies recursively to the children of group boxes.
6441 *
6442 * @param[in] vb to escape.
6443 * @param[in] escape escape definition to apply to the value box.
6444 * @param[in] uctx user context to pass to the escape function.
6445 * @return
6446 * - 0 on success.
6447 * - -1 on failure.
6448 */
6450{
6451 int ret;
6452
6453 switch (vb->type) {
6454 case FR_TYPE_GROUP:
6455 return fr_value_box_list_escape_in_place(&vb->vb_group, escape, uctx);
6456
6457 case FR_TYPE_NULL:
6458 case FR_TYPE_TLV:
6459 case FR_TYPE_STRUCT:
6460 case FR_TYPE_VSA:
6461 case FR_TYPE_VENDOR:
6462 case FR_TYPE_INTERNAL:
6463 fr_strerror_printf("Cannot escape data type '%s'", fr_type_to_str(vb->type));
6464 return -1;
6465
6466 case FR_TYPE_ATTR:
6467 fr_assert(0); /* @todo - print to string, and then escape? */
6468 fr_strerror_printf("Cannot escape data type '%s'", fr_type_to_str(vb->type));
6469 return -1;
6470
6471 default:
6472 break;
6473 }
6474
6475 /*
6476 * Don't do double escaping.
6477 */
6478 if (!escape->always_escape && fr_value_box_is_safe_for(vb, escape->safe_for)) return 0;
6479
6480 ret = escape->func(vb, uctx);
6481 if (unlikely(ret < 0)) return ret;
6482
6483 /*
6484 * '1' means that the function mashed the safe_for value, so we don't need to.
6485 */
6486 if (!ret) vb->safe_for = escape->safe_for;
6487 vb->tainted = false;
6488
6489 return 0;
6490}
6491
6492/** Escape a list of value boxes in place
6493 *
6494 * @note Applies recursively to the children of group boxes.
6495 *
6496 * @note on error, the list may be left in an inconsistent/partially escaped state.
6497 *
6498 * @param[in] list to escape.
6499 * @param[in] escape escape definition to apply to the value box.
6500 * @param[in] uctx user context to pass to the escape function.
6501 * @return
6502 * - 0 on success.
6503 * - -1 on failure.
6504 */
6505int fr_value_box_list_escape_in_place(fr_value_box_list_t *list, fr_value_box_escape_t const *escape, void *uctx)
6506{
6507 int ret = 0;
6508
6509 fr_value_box_list_foreach(list, vb) {
6510 ret = fr_value_box_escape_in_place(vb, escape, uctx);
6511 if (unlikely(ret < 0)) return ret;
6512 }
6513
6514 return ret;
6515}
6516
6517/** Removes a single layer of nesting, moving all children into the parent list
6518 *
6519 * @param[in] ctx to reparent children in if steal is true.
6520 * @param[in] list to flatten.
6521 * @param[in] steal whether to change the talloc ctx of children.
6522 * @param[in] free whether to free any group boxes which have had
6523 * their children removed.
6524 */
6525void fr_value_box_flatten(TALLOC_CTX *ctx, fr_value_box_list_t *list, bool steal, bool free)
6526{
6527 fr_value_box_list_foreach_safe(list, child) {
6528 if (!fr_type_is_structural(child->type)) continue;
6529
6530 fr_value_box_list_foreach_safe(&child->vb_group, grandchild) {
6531 fr_value_box_list_remove(&child->vb_group, grandchild);
6532 if (steal) talloc_steal(ctx, grandchild);
6533 fr_value_box_list_insert_before(list, child, grandchild);
6534 }}
6535
6536 if (free) talloc_free(child);
6537 }}
6538}
6539
6540/** Concatenate the string representations of a list of value boxes together
6541 *
6542 * @param[in] ctx to allocate the buffer in.
6543 * @param[in] list of value boxes.
6544 * @param[in] delim to insert between value box values.
6545 * @param[in] e_rules to control escaping of the concatenated elements.
6546 * @return
6547 * - NULL on error.
6548 * - The concatenation of the string values of the value box list on success.
6549 */
6550char *fr_value_box_list_aprint(TALLOC_CTX *ctx, fr_value_box_list_t const *list, char const *delim,
6551 fr_sbuff_escape_rules_t const *e_rules)
6552{
6553 fr_value_box_t const *vb = fr_value_box_list_head(list);
6554 char *aggr, *td = NULL;
6555 TALLOC_CTX *pool = NULL;
6556
6557 if (!vb) return NULL;
6558
6559 fr_value_box_aprint(ctx, &aggr, vb, e_rules);
6560 if (!aggr) return NULL;
6561 if (!fr_value_box_list_next(list, vb)) return aggr;
6562
6563 /*
6564 * If we're aggregating more values,
6565 * allocate a temporary pool.
6566 */
6567 pool = talloc_pool(NULL, 255);
6568 if (delim) td = talloc_typed_strdup(pool, delim);
6569
6570 while ((vb = fr_value_box_list_next(list, vb))) {
6571 char *str, *new_aggr;
6572
6573 fr_value_box_aprint(pool, &str, vb, e_rules);
6574 if (!str) continue;
6575
6576 new_aggr = talloc_buffer_append_variadic_buffer(ctx, aggr, 2, td, str);
6577 if (unlikely(!new_aggr)) {
6578 talloc_free(aggr);
6579 talloc_free(pool);
6580 return NULL;
6581 }
6582 aggr = new_aggr;
6583 talloc_free(str);
6584 }
6585 talloc_free(pool);
6586
6587 return aggr;
6588}
6589
6590/** Concatenate the string representations of a list of value boxes together hiding "secret" values
6591 *
6592 * @param[in] ctx to allocate the buffer in.
6593 * @param[in] list of value boxes.
6594 * @param[in] delim to insert between value box values.
6595 * @param[in] e_rules to control escaping of the concatenated elements.
6596 * @return
6597 * - NULL on error.
6598 * - The concatenation of the string values of the value box list on success.
6599 */
6600char *fr_value_box_list_aprint_secure(TALLOC_CTX *ctx, fr_value_box_list_t const *list, char const *delim,
6601 fr_sbuff_escape_rules_t const *e_rules)
6602{
6603 fr_value_box_t const *vb = fr_value_box_list_head(list);
6604 char *aggr, *td = NULL;
6605 TALLOC_CTX *pool = NULL;
6606
6607 if (!vb) return NULL;
6608
6610 aggr = talloc_typed_strdup(ctx, "<<< secret >>>");
6611 } else {
6612 fr_value_box_aprint(ctx, &aggr, vb, e_rules);
6613 }
6614 if (!aggr) return NULL;
6615 if (!fr_value_box_list_next(list, vb)) return aggr;
6616
6617 /*
6618 * If we're aggregating more values,
6619 * allocate a temporary pool.
6620 */
6621 pool = talloc_pool(NULL, 255);
6622 if (delim) td = talloc_typed_strdup(pool, delim);
6623
6624 while ((vb = fr_value_box_list_next(list, vb))) {
6625 char *str, *new_aggr;
6626
6628 str = talloc_typed_strdup(pool, "<<< secret >>>");
6629 } else {
6630 fr_value_box_aprint(pool, &str, vb, e_rules);
6631 }
6632 if (!str) continue;
6633
6634 new_aggr = talloc_buffer_append_variadic_buffer(ctx, aggr, 2, td, str);
6635 if (unlikely(!new_aggr)) {
6636 talloc_free(aggr);
6637 talloc_free(pool);
6638 return NULL;
6639 }
6640 aggr = new_aggr;
6641 talloc_free(str);
6642 }
6643 talloc_free(pool);
6644
6645 return aggr;
6646}
6647
6648/** Hash the contents of a value box
6649 *
6650 */
6652{
6653 switch (vb->type) {
6654 case FR_TYPE_FIXED_SIZE:
6655 return fr_hash(fr_value_box_raw(vb, vb->type),
6656 fr_value_box_field_sizes[vb->type]);
6657
6658 case FR_TYPE_STRING:
6659 return fr_hash(vb->vb_strvalue, vb->vb_length);
6660
6661 case FR_TYPE_OCTETS:
6662 return fr_hash(vb->vb_octets, vb->vb_length);
6663
6664 case FR_TYPE_ATTR:
6665 return fr_hash(&vb->vb_attr, sizeof(vb->vb_attr));
6666
6667 case FR_TYPE_STRUCTURAL:
6668 case FR_TYPE_INTERNAL:
6671 case FR_TYPE_NULL:
6672 fr_assert(0);
6673 break;
6674 }
6675
6676 return 0;
6677}
6678
6679/** Do a full copy of a list of value boxes
6680 *
6681 * @param[in] ctx to allocate boxes in.
6682 * @param[out] out Where to write the head of the new list.
6683 * @param[in] in boxes to copy.
6684 * @return
6685 * - A duplicate list of value boxes, allocated in the context of 'ctx'
6686 * - NULL on error, or empty input list.
6687 */
6688int fr_value_box_list_acopy(TALLOC_CTX *ctx, fr_value_box_list_t *out, fr_value_box_list_t const *in)
6689{
6690 fr_value_box_t const *in_p = NULL;
6691
6692 while ((in_p = fr_value_box_list_next(in, in_p))) {
6693 fr_value_box_t *n = NULL;
6694
6696 if (!n) {
6697 error:
6698 fr_value_box_list_talloc_free(out);
6699 return -1;
6700 }
6701
6702 if (fr_value_box_copy(n, n, in_p) < 0) goto error;
6703 fr_dlist_insert_tail(fr_value_box_list_dlist_head(out), n);
6704 }
6705
6706 return 0;
6707}
6708
6709/** Check to see if any list members (or their children) are tainted
6710 *
6711 * @param[in] head of list to check.
6712 * @return
6713 * - true if a list member is tainted.
6714 * - false if no list members are tainted.
6715 */
6716bool fr_value_box_list_tainted(fr_value_box_list_t const *head)
6717{
6718 fr_value_box_t *vb = NULL;
6719
6720 while ((vb = fr_value_box_list_next(head, vb))) {
6721 if (fr_type_is_group(vb->type) && fr_value_box_list_tainted(&vb->vb_group)) return true;
6722 if (vb->tainted) return true;
6723 }
6724
6725 return false;
6726}
6727
6728/** Taint every list member (and their children)
6729 *
6730 * @param[in] head of list.
6731 */
6732void fr_value_box_list_taint(fr_value_box_list_t *head)
6733{
6734 fr_value_box_t *vb = NULL;
6735
6736 while ((vb = fr_value_box_list_next(head, vb))) {
6737 if (fr_type_is_group(vb->type)) fr_value_box_list_taint(&vb->vb_group);
6739 vb->tainted = true;
6740 }
6741}
6742
6743/** Untaint every list member (and their children)
6744 *
6745 * @param[in] head of list.
6746 */
6747void fr_value_box_list_untaint(fr_value_box_list_t *head)
6748{
6749 fr_value_box_t *vb = NULL;
6750
6751 while ((vb = fr_value_box_list_next(head, vb))) {
6752 if (fr_type_is_group(vb->type)) fr_value_box_list_untaint(&vb->vb_group);
6753 vb->tainted = false;
6754 }
6755}
6756
6757/** Validation function to check that a fr_value_box_t is correctly initialised
6758 *
6759 */
6760void fr_value_box_verify(char const *file, int line, fr_value_box_t const *vb)
6761{
6762DIAG_OFF(nonnull-compare)
6763 /*
6764 * nonnull only does something if we're building
6765 * with ubsan... We still want to assert event
6766 * if we're building without sanitizers.
6767 */
6768 fr_fatal_assert_msg(vb, "CONSISTENCY CHECK FAILED %s[%i]: fr_value_box_t pointer was NULL", file, line);
6769DIAG_ON(nonnull-compare)
6770
6771 if (vb->talloced) vb = talloc_get_type_abort_const(vb, fr_value_box_t);
6772
6773#ifndef NDEBUG
6774 fr_fatal_assert_msg(vb->magic == FR_VALUE_BOX_MAGIC, "CONSISTENCY CHECK FAILED %s[%i]: fr_value_box_t magic "
6775 "incorrect, expected %" PRIx64 ", got %" PRIx64, file, line, FR_VALUE_BOX_MAGIC, vb->magic);
6776#endif
6777 switch (vb->type) {
6778 case FR_TYPE_STRING:
6779 fr_fatal_assert_msg(vb->vb_strvalue, "CONSISTENCY CHECK FAILED %s[%d]: fr_value_box_t strvalue field "
6780 "was NULL", file, line);
6781 fr_fatal_assert_msg(vb->vb_strvalue[vb->vb_length] == '\0',
6782 "CONSISTENCY CHECK FAILED %s[%i]: fr_value_box_t strvalue field "
6783 "not null terminated", file, line);
6784 if (vb->talloced) {
6785 size_t len = talloc_array_length(vb->vb_strvalue);
6786
6787 /* We always \0 terminate to be safe, even though most things should use the len field */
6788 if (len <= vb->vb_length) {
6789 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: Expected fr_value_box_t->vb_strvalue talloc buffer "
6790 "len >= %zu, got %zu",
6791 file, line, vb->vb_length + 1, len);
6792 }
6793 }
6794 break;
6795
6796 case FR_TYPE_OCTETS:
6797 fr_fatal_assert_msg(vb->vb_octets, "CONSISTENCY CHECK FAILED %s[%d]: fr_value_box_t octets field "
6798 "was NULL", file, line);
6799 break;
6800
6801 case FR_TYPE_VOID:
6802 fr_fatal_assert_msg(vb->vb_void, "CONSISTENCY CHECK FAILED %s[%d]: fr_value_box_t ptr field "
6803 "was NULL", file, line);
6804 break;
6805
6806 case FR_TYPE_GROUP:
6807 fr_value_box_list_verify(file, line, &vb->vb_group);
6808 break;
6809
6810 case FR_TYPE_ATTR:
6811 if (vb->vb_attr) break;
6812
6813 fr_fatal_assert_msg(vb->vb_void, "CONSISTENCY CHECK FAILED %s[%d]: fr_value_box_t vb_attr field "
6814 "was NULL", file, line);
6815 break;
6816
6817 default:
6818 break;
6819 }
6820}
6821
6822void fr_value_box_list_verify(char const *file, int line, fr_value_box_list_t const *list)
6823{
6825}
6826
6827/** Mark a value-box as "safe", of a particular type.
6828 *
6829 */
6831{
6832 /*
6833 * Don't over-ride value-boxes which are already safe, unless we want to mark them as being
6834 * completely unsafe.
6835 */
6836 if ((vb->safe_for == FR_VALUE_BOX_SAFE_FOR_ANY) &&
6837 (safe_for != FR_VALUE_BOX_SAFE_FOR_NONE)) {
6838 fr_assert(!vb->tainted);
6839 return;
6840 }
6841
6842 vb->safe_for = safe_for;
6843}
6844
6845/** Mark a value-box as "unsafe"
6846 *
6847 * This always succeeds, and there are no side effects.
6848 */
6850{
6851 vb->safe_for = FR_VALUE_BOX_SAFE_FOR_NONE;
6852}
6853
6854/** Set the escaped flag for all value boxes in a list
6855 *
6856 * @note Only operates on a single level.
6857 *
6858 * @param[in] list to operate on.
6859 * @param[in] safe_for value to set.
6860 */
6861void fr_value_box_list_mark_safe_for(fr_value_box_list_t *list, fr_value_box_safe_for_t safe_for)
6862{
6863 fr_value_box_list_foreach(list, vb) {
6864 /*
6865 * Don't over-ride value-boxes which are already safe.
6866 */
6867 if (vb->safe_for == FR_VALUE_BOX_SAFE_FOR_ANY) {
6868 fr_assert(!vb->tainted);
6869
6870 } else {
6871 vb->safe_for = safe_for;
6872 }
6873 }
6874}
6875
6876/** Copy the safety values from one box to another.
6877 *
6878 */
6880{
6881 if (out == in) return;
6882
6883 out->safe_for = in->safe_for;
6884 out->tainted = in->tainted;
6885 out->secret = in->secret;
6886}
6887
6888/** Copy the safety values from one box to another.
6889 *
6890 * But note that we have changed the output format, so we reset the "safe_for" value to NONE.
6891 */
6893{
6894 out->safe_for = FR_VALUE_BOX_SAFE_FOR_NONE;
6895 out->tainted = in->tainted;
6896 out->secret = in->secret;
6897}
6898
6899/** Merge safety results.
6900 */
6902{
6903 if (out == in) return;
6904
6905 /*
6906 * If we're already at no safety, then we don't need to do anything.
6907 *
6908 * Otherwise we update the safety only if we need to change it.
6909 */
6910 if ((out->safe_for != FR_VALUE_BOX_SAFE_FOR_NONE) &&
6911 (out->safe_for != in->safe_for)) {
6912 /*
6913 * If the output is anything, then the input is more restrictive, so we switch to that.
6914 *
6915 * Otherwise the values are different. Either it's X/Y, or NONE/X, or X/NONE. In which
6916 * case the answer is always NONE.
6917 */
6918 if (out->safe_for == FR_VALUE_BOX_SAFE_FOR_ANY) {
6919 out->safe_for = in->safe_for;
6920
6921 } else {
6922 out->safe_for = FR_VALUE_BOX_SAFE_FOR_NONE;
6923 }
6924 }
6925
6926 out->tainted |= in->tainted;
6927 out->secret |= in->secret;
6928}
6929
6930
6931/** Check truthiness of values.
6932 *
6933 * The casting rules for expressions / conditions are slightly
6934 * different than fr_value_box_cast(). Largely because that
6935 * function is used to parse configuration files, and parses "yes
6936 * / no" and "true / false" strings, even if there's no
6937 * fr_dict_attr_t passed to it.
6938 */
6940{
6941 fr_value_box_t box;
6942
6943 switch (in->type) {
6944 case FR_TYPE_NULL:
6948 case FR_TYPE_ATTR:
6949 case FR_TYPE_INTERNAL:
6950 break;
6951
6952 case FR_TYPE_GROUP:
6953 return (fr_value_box_list_num_elements(&in->vb_group) > 0);
6954
6955 case FR_TYPE_BOOL:
6956 return in->vb_bool;
6957
6958 case FR_TYPE_STRING:
6959 case FR_TYPE_OCTETS:
6960 return (in->vb_length > 0);
6961
6962 case FR_TYPE_IPV4_ADDR:
6963 case FR_TYPE_IPV6_ADDR:
6964 return !fr_ipaddr_is_inaddr_any(&in->vb_ip);
6965
6968 return !((in->vb_ip.prefix == 0) && fr_ipaddr_is_inaddr_any(&in->vb_ip));
6969
6971 case FR_TYPE_FLOAT32:
6972 case FR_TYPE_FLOAT64:
6973 case FR_TYPE_IFID:
6974 case FR_TYPE_ETHERNET:
6976 if (fr_value_box_cast(NULL, &box, FR_TYPE_BOOL, NULL, in) < 0) return false;
6977 return box.vb_bool;
6978 }
6979
6980 return false;
6981}
6982
6983#define INFO_INDENT(_fmt, ...) fprintf(fp, "%*s" _fmt "\n", depth * 2, " ", ## __VA_ARGS__)
6984
6985static void _fr_value_box_debug(FILE *fp, fr_value_box_t const *vb, int depth, int idx);
6986static void _fr_value_box_list_debug(FILE *fp, fr_value_box_list_t const *head, int depth)
6987{
6988 int i = 0;
6989
6990 INFO_INDENT("{");
6992 INFO_INDENT("}");
6993}
6994
6995/** Print a list of value boxes as info messages
6996 *
6997 * @note Call directly from the debugger
6998 */
6999void fr_value_box_list_debug(FILE *fp, fr_value_box_list_t const *head)
7000{
7002}
7003
7004static void _fr_value_box_debug(FILE *fp, fr_value_box_t const *vb, int depth, int idx)
7005{
7006 char *value;
7007 char buffer[64];
7008
7009 if (fr_type_is_structural(vb->type)) {
7010 _fr_value_box_list_debug(fp, &vb->vb_group, depth + 1);
7011 return;
7012 }
7013
7014 buffer[0] = '\0';
7015 if (vb->type == FR_TYPE_TIME_DELTA) {
7016 if (!vb->enumv) {
7017 snprintf(buffer, sizeof(buffer), " (sec!) %" PRId64, fr_time_delta_unwrap(vb->vb_time_delta));
7018 } else {
7019 snprintf(buffer, sizeof(buffer), " (%s) %" PRId64,
7020 fr_table_str_by_value(fr_time_precision_table, vb->enumv->flags.flag_time_res, "?"),
7021 fr_time_delta_unwrap(vb->vb_time_delta));
7022 }
7023 }
7024
7025 fr_value_box_aprint(NULL, &value, vb, NULL);
7026 if (idx >= 0) {
7027 INFO_INDENT("[%d] (%s) %s", idx, fr_type_to_str(vb->type), value);
7028 INFO_INDENT(" %s %s %lx%s",
7029 vb->secret ? "s" : "-",
7030 vb->tainted ? "t" : "-",
7031 vb->safe_for, buffer);
7032 } else {
7033 INFO_INDENT("(%s) %s", fr_type_to_str(vb->type), value);
7034 INFO_INDENT(" %s %s %lx%s",
7035 vb->secret ? "s" : "-",
7036 vb->tainted ? "t" : "-",
7037 vb->safe_for, buffer);
7038 }
7040}
7041
7042/** Print the value of a box as info messages
7043 *
7044 * @note Call directly from the debugger
7045 */
7046void fr_value_box_debug(FILE *fp, fr_value_box_t const *vb)
7047{
7048 _fr_value_box_debug(fp, vb, 0, -1);
7049}
static int const char char buffer[256]
Definition acutest.h:576
int const char * file
Definition acutest.h:702
va_end(args)
int n
Definition acutest.h:577
static int const char * fmt
Definition acutest.h:573
int const char int line
Definition acutest.h:702
va_start(args, fmt)
#define fr_base16_encode(_out, _in)
Definition base16.h:57
#define fr_base16_decode(_err, _out, _in, _no_trailing)
Definition base16.h:95
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define DIAG_ON(_x)
Definition build.h:460
#define SIZEOF_MEMBER(_t, _m)
Definition build.h:338
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:112
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define DIAG_OFF(_x)
Definition build.h:459
static fr_atomic_queue_t * aq
static size_t min(size_t x, size_t y)
Definition dbuff.c:66
int fr_dbuff_trim_talloc(fr_dbuff_t *dbuff, size_t len)
Trim a talloced dbuff to the minimum length required to represent the contained string.
Definition dbuff.c:297
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h:767
#define FR_DBUFF_OUT_UINT64V_RETURN(_num, _dbuff_or_marker, _len)
Read bytes from a dbuff or marker and interpret them as a network order unsigned integer.
Definition dbuff.h:1858
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
Definition dbuff.h:1004
#define fr_dbuff_init(_out, _start, _len_or_end)
Initialise an dbuff for encoding or decoding.
Definition dbuff.h:354
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:898
#define FR_DBUFF_OUT_INT64V_RETURN(_num, _dbuff_or_marker, _len)
Read bytes from a dbuff or marker and interpret them as a network order unsigned integer.
Definition dbuff.h:1898
#define fr_dbuff_buff(_dbuff_or_marker)
Return the underlying buffer in a dbuff or one of marker.
Definition dbuff.h:882
#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen)
Copy exactly _outlen bytes from the dbuff.
Definition dbuff.h:1732
#define FR_DBUFF_MEMSET_RETURN(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c returning if there is insufficient space.
Definition dbuff.h:1508
#define FR_DBUFF_OUT_MEMCPY_RETURN(_out, _dbuff_or_marker, _outlen)
Copy outlen bytes from the dbuff returning if there's insufficient data in the dbuff.
Definition dbuff.h:1752
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1382
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
Definition dbuff.h:1350
#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff returning if there is insufficient space.
Definition dbuff.h:1585
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:222
#define FR_DBUFF_OUT_RETURN(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type returning if there is insufficient data.
Definition dbuff.h:1818
static fr_dbuff_t * fr_dbuff_init_talloc(TALLOC_CTX *ctx, fr_dbuff_t *dbuff, fr_dbuff_uctx_talloc_t *tctx, size_t init, size_t max)
Initialise a special dbuff which automatically extends as additional data is written.
Definition dbuff.h:411
#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1472
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:514
#define fr_fatal_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h: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
static fr_slen_t err
Definition dict.h:849
static fr_dict_attr_t * fr_dict_attr_unknown_copy(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Definition dict.h:566
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:2416
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:593
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:2492
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:238
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:3515
#define da_is_length_field(_da)
Definition dict.h:161
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:717
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:3420
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:3528
static fr_slen_t in
Definition dict.h:849
@ FLAG_LENGTH_UINT8
string / octets type is prefixed by uint8 of length
Definition dict.h:155
@ FLAG_LENGTH_UINT16
string / octets type is prefixed by uint16 of length
Definition dict.h:156
static int8_t fr_dict_attr_cmp(fr_dict_attr_t const *a, fr_dict_attr_t const *b)
Definition dict.h:621
Value of an enumerated attribute.
Definition dict.h:234
Test enumeration values.
Definition dict_test.h:92
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition dlist.h:378
uint32_t fr_hash(void const *data, size_t size)
Definition hash.c:812
free(array)
int fr_ipaddr_is_prefix(fr_ipaddr_t const *ipaddr)
Determine if an address is a prefix.
Definition inet.c: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:118
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:851
#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:204
#define FR_SBUFF_IN_ESCAPE_BUFFER_RETURN(...)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition sbuff.h:192
char const * name
Name for rule set to aid we debugging.
Definition sbuff.h:202
#define FR_SBUFF_IN_STRCPY_LITERAL_RETURN(_sbuff, _str)
#define fr_sbuff_extend(_sbuff_or_marker)
#define fr_sbuff_buff(_sbuff_or_marker)
#define FR_SBUFF_RETURN(_func, _sbuff,...)
#define fr_sbuff_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:180
#define FR_SBUFF_IN_STRCPY_RETURN(...)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Talloc sbuff extension structure.
Definition sbuff.h:139
Set of parsing rules for *unescape_until functions.
fr_slen_t fr_size_from_str(size_t *out, fr_sbuff_t *in)
Parse a size string with optional unit.
Definition size.c:40
fr_slen_t fr_size_to_str(fr_sbuff_t *out, size_t in)
Print a size string with unit.
Definition size.c:155
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
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:287
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:4627
void fr_value_box_list_verify(char const *file, int line, fr_value_box_list_t const *list)
Definition value.c:6822
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:4942
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:4438
static void _fr_value_box_list_debug(FILE *fp, fr_value_box_list_t const *head, int depth)
Definition value.c:6986
#define INFO_INDENT(_fmt,...)
Definition value.c:6983
void fr_value_box_mark_unsafe(fr_value_box_t *vb)
Mark a value-box as "unsafe".
Definition value.c:6849
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:6065
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:4408
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
Definition value.c:6651
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:5798
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:5024
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:2422
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:6600
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:1919
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:4747
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:4902
#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:4663
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:3744
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:4469
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:6550
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:4780
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:3623
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:7004
#define CAST_IP_FIX_COMBO
Definition value.c:2582
void fr_value_box_list_untaint(fr_value_box_list_t *head)
Untaint every list member (and their children)
Definition value.c:6747
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:2623
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:4162
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:6505
fr_sbuff_unescape_rules_t fr_value_unescape_solidus
Definition value.c:302
bool fr_value_box_is_truthy(fr_value_box_t const *in)
Check truthiness of values.
Definition value.c:6939
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:3990
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:2408
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:4924
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:4286
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:5761
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:6181
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:2473
void fr_value_box_increment(fr_value_box_t *vb)
Increment a boxed value.
Definition value.c:4970
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:6830
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:4099
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:6760
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:4382
#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:4507
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:6022
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:3366
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:2966
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:6892
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:4048
void fr_value_box_list_taint(fr_value_box_list_t *head)
Taint every list member (and their children)
Definition value.c:6732
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:6861
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:2360
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:3122
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:4080
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:6901
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:4491
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:6999
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:2737
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:3064
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:6879
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:4526
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:4955
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:4315
static int fr_value_box_cast_unsupported(fr_type_t dst, fr_type_t src)
Definition value.c:2599
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:2297
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:6525
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:6688
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:4145
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:6716
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:1518
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:4559
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:4603
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:4869
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:7046
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:4708
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:5124
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:6449
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:4687
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:2852
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:4844
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:3209
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:6281
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:1291
static bool fr_value_box_contains_secret(fr_value_box_t const *box)
Definition value.h:1097
#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:1081
#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