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