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