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