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