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