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