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