The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
cbor.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/** CBPR encoding and decoding
18 *
19 * @file src/lib/util/cbor.c
20 *
21 * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
22 */
23RCSID("$Id: dcc46727e33a94dc38ce507e3ede136e0875c260 $")
24
25#include <freeradius-devel/util/cbor.h>
26
27#define CBOR_INTEGER (0)
28#define CBOR_NEGATIVE (1)
29#define CBOR_OCTETS (2)
30#define CBOR_STRING (3)
31#define CBOR_ARRAY (4)
32#define CBOR_MAP (5)
33#define CBOR_TAG (6)
34#define CBOR_FLOAT (7)
35
36#define CBOR_1_BYTE ((uint8_t) 24)
37#define CBOR_2_BYTE ((uint8_t) 25)
38#define CBOR_4_BYTE ((uint8_t) 26)
39#define CBOR_8_BYTE ((uint8_t) 27)
40
41static const char *cbor_type_to_str[8] = {
42 "integer", "negative", "octets", "string",
43 "array", "map", "tag", "float"
44};
45
46/*
47 * Some of our data types need tags.
48 *
49 * We don't have a tag to data type array. When decoding, we should usually have the enclosing pair
50 * number, which includes our data type. If the tag type doesn't match the value here, then something is
51 * wrong.
52 */
53static const uint64_t cbor_type_to_tag[FR_TYPE_MAX + 1] = {
54 [FR_TYPE_DATE] = 1,
55 [FR_TYPE_ETHERNET] = 48,
56 [FR_TYPE_IPV4_ADDR] = 52,
58 [FR_TYPE_IPV6_ADDR] = 54,
60 [FR_TYPE_TIME_DELTA] = 1002,
61};
62
63static fr_type_t cbor_guess_type(fr_dbuff_t *dbuff, bool pair);
64
66{
67 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
68 uint8_t value[8];
69
70 fr_assert(type < 8);
71 type <<= 5;
72
73 if (data < 24) {
74 data |= type;
75
76 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) (data & 0xff));
77 goto done;
78 }
79
80 if (data < (((uint64_t) 1) << 8)) {
81 value[0] = data;
82
84 FR_DBUFF_IN_RETURN(&work_dbuff, value[0]);
85 goto done;
86 }
87
88 if (data < (((uint64_t) 1) << 16)) {
90
92 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value, 2);
93 goto done;
94 }
95
96 if (data < (((uint64_t) 1) << 32)) {
98
100 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value, 4);
101 goto done;
102 }
103
105
106 /*
107 * Has to be 8 bytes.
108 */
110 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value, 8);
111
112done:
113 return fr_dbuff_set(dbuff, &work_dbuff);
114}
115
116#define cbor_encode_array(_dbuff, _size) cbor_encode_integer(_dbuff, CBOR_ARRAY, _size)
117
118#define cbor_encode_tag(_dbuff, _tag) cbor_encode_integer(_dbuff, CBOR_TAG, _tag)
119
120/*
121 * Make many things easier
122 */
123#define return_slen return FR_DBUFF_ERROR_OFFSET(slen, fr_dbuff_used(&work_dbuff))
124
125/*
126 * Octets is length + data
127 */
128static ssize_t cbor_encode_octets(fr_dbuff_t *dbuff, uint8_t const *data, size_t data_len)
129{
130 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
131 ssize_t slen;
132
133 slen = cbor_encode_integer(&work_dbuff, CBOR_OCTETS, data_len);
134 if (slen <= 0) return_slen;
135
136 if (data_len > 0) FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, data, data_len);
137
138 return fr_dbuff_set(dbuff, &work_dbuff);
139}
140
141static ssize_t cbor_encode_int64(fr_dbuff_t *dbuff, int64_t neg)
142{
143 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
144 ssize_t slen;
145
146 if (neg >= 0) {
147 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, neg);
148 } else {
149 uint64_t data;
150
151 neg++;
152 data = -neg;
153 slen = cbor_encode_integer(&work_dbuff, CBOR_NEGATIVE, data);
154 }
155 if (slen <= 0) return_slen;
156
157 return fr_dbuff_set(dbuff, &work_dbuff);
158}
159
160#define cbor_encode_key cbor_encode_int64
161
162/** Encode CBOR
163 *
164 * Values 0..23 can be encoded in place. Other values can be encoded using the closest smallest integer
165 */
167{
168 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
170 uint64_t data;
171 int64_t neg;
172 ssize_t slen;
173 uint8_t const *p, *end;
174
175 switch (vb->type) {
176 case FR_TYPE_BOOL:
177 /*
178 * One byte of FLOAT (i.e. special value), and the boolean as a "simple value".
179 */
180 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | (20 + vb->vb_bool)));
181 break;
182
183 case FR_TYPE_UINT8:
184 data = vb->vb_uint8;
185 goto encode_int;
186
187 case FR_TYPE_UINT16:
188 data = vb->vb_uint16;
189 goto encode_int;
190
191 case FR_TYPE_UINT32:
192 data = vb->vb_uint32;
193 goto encode_int;
194
195 case FR_TYPE_UINT64:
196 data = vb->vb_uint64;
197 goto encode_int;
198
199 /*
200 * Negative numbers.
201 */
202 case FR_TYPE_INT8:
203 neg = vb->vb_int8;
204 goto encode_neg;
205
206 case FR_TYPE_INT16:
207 neg = vb->vb_int16;
208 goto encode_neg;
209
210 case FR_TYPE_INT32:
211 neg = vb->vb_int32;
212 goto encode_neg;
213
214 case FR_TYPE_INT64:
215 neg = vb->vb_int64;
216 encode_neg:
217 if (neg >= 0) {
219 data = neg;
220 goto encode_int;
221 }
222
223 /*
224 * convert -1..-2^63 to 0..-(2^63-1)
225 * and then it fits into a positive integer.
226 */
227 neg++;
228 data = -neg;
229
230 encode_int:
231 return cbor_encode_integer(dbuff, type, data);
232
233 case FR_TYPE_OCTETS:
234 return cbor_encode_octets(dbuff, vb->vb_octets, vb->vb_length);
235
236 case FR_TYPE_STRING:
237 slen = cbor_encode_integer(&work_dbuff, CBOR_STRING, vb->vb_length);
238 if (slen <= 0) return_slen;
239
240 if (vb->vb_length) FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vb->vb_strvalue, vb->vb_length);
241 break;
242
243 /*
244 * More complex data types are represented by type "tag", followed by a tag number. The
245 * actual data is then encoded as the next item after the tag.
246 */
247 case FR_TYPE_ETHERNET:
248 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
249 if (slen <= 0) return_slen;
250
251 slen = cbor_encode_octets(&work_dbuff, vb->vb_ether, sizeof(vb->vb_ether));
252 if (slen <= 0) return_slen;
253 break;
254
255 /*
256 * Tag 1, with integer seconds since epoch.
257 *
258 * @todo - if the input has time resolution, then save it in that format.
259 *
260 * RFC 9581 Section 3.
261 *
262 * A tag with key 1001, and then: a map with required key 1 (integer epoch seconds) and
263 * optional key -3 (milliseconds), -6 (microseconds), or -9 (integer nanoseconds).
264 *
265 * For the encoder, there are a ton of different formats for dates, and we shouldn't
266 * bother to parse them all. :(
267 */
268 case FR_TYPE_DATE:
269 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
270 if (slen <= 0) return_slen;
271
272 neg = fr_unix_time_to_sec(vb->vb_date);
273 slen = cbor_encode_int64(&work_dbuff, neg);
274 if (slen <= 0) return_slen;
275 break;
276
277 /*
278 * RFC 9581 Section 4.
279 *
280 * A tag with key 1002, and then: a map with required key 1 (integer seconds) and
281 * optional key -3 (milliseconds), -6 (microseconds), or -9 (integer nanoseconds).
282 */
284 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
285 if (slen <= 0) return_slen;
286
287 neg = fr_time_delta_unwrap(vb->vb_time_delta) % NSEC;
288
289 slen = cbor_encode_integer(&work_dbuff, CBOR_MAP, 1 + (neg != 0));
290 if (slen <= 0) return_slen;
291
292 /*
293 * 1: seconds
294 */
295 slen = cbor_encode_key(&work_dbuff, 1);
296 if (slen <= 0) return_slen;
297
298 slen = cbor_encode_int64(&work_dbuff, fr_time_delta_to_sec(vb->vb_time_delta));
299 if (slen <= 0) return_slen;
300
301 /*
302 * -9: nanoseconds
303 */
304 if (neg) {
305 slen = cbor_encode_key(&work_dbuff, -9);
306 if (slen <= 0) return_slen;
307
308 slen = cbor_encode_int64(&work_dbuff, neg);
309 if (slen <= 0) return_slen;
310 }
311 break;
312
313 /*
314 * RFC 9164, Section 3.3
315 *
316 *
317 * tag=IPv4 + address + optional (prefix + scope)
318 */
320 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
321 if (slen <= 0) return_slen;
322
323 if (vb->vb_ip.scope_id != 0) {
324 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 3));
325
326 }
327
328 slen = cbor_encode_octets(&work_dbuff, (uint8_t const *) &vb->vb_ipv4addr, 4);
329 if (slen <= 0) return_slen;
330
331 if (vb->vb_ip.scope_id == 0) break;
332
333 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, (uint8_t) 32);
334 if (slen <= 0) return_slen;
335
336 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.scope_id);
337 if (slen <= 0) return_slen;
338 break;
339
340 /*
341 * RFC 9164, Section 3.2
342 *
343 * tag=IPv6 + address + optional (prefix + scope)
344 */
346 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
347 if (slen <= 0) return_slen;
348
349 if (vb->vb_ip.scope_id != 0) {
350 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 3));
351 }
352
353 slen = cbor_encode_octets(&work_dbuff, (uint8_t const *) &vb->vb_ipv6addr, 16);
354 if (slen <= 0) return_slen;
355
356 if (vb->vb_ip.scope_id == 0) break;
357
358 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, (uint8_t) 128);
359 if (slen <= 0) return_slen;
360
361 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.scope_id);
362 if (slen <= 0) return_slen;
363 break;
364
365 /*
366 * RFC 9164, Section 3.3
367 *
368 * tag=IPv4 + array(prefix-length, address)
369 */
371 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
372 if (slen <= 0) return_slen;
373
374 slen = cbor_encode_array(&work_dbuff, 2);
375 if (slen <= 0) return_slen;
376
377 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.prefix);
378 if (slen <= 0) return_slen;
379
380 p = (uint8_t const *) &vb->vb_ipv4addr;
381 end = p + 3;
382
383 /*
384 * RFC 9164 Section 4.2 - Drop lower octets which are all zero.
385 *
386 * If this results in a zero-length string, so be it.
387 *
388 * Note also that "There is no relationship between the number of bytes omitted and the
389 * prefix length."
390 */
391 do {
392 if (*end != 0) break;
393
394 end--;
395 } while (end != p);
396
397 slen = cbor_encode_octets(&work_dbuff, p, (end - p) + (*end != 0));
398 if (slen <= 0) return_slen;
399 break;
400
401 /*
402 * RFC 9164, Section 3.2
403 *
404 * tag=IPv6 + array(prefix-length, address)
405 */
407 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
408 if (slen <= 0) return_slen;
409
410 slen = cbor_encode_array(&work_dbuff, 2);
411 if (slen <= 0) return_slen;
412
413 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.prefix);
414 if (slen <= 0) return_slen;
415
416 p = (uint8_t const *) &vb->vb_ipv6addr;
417 end = p + 15;
418
419 /*
420 * RFC 9164 Section 4.2 - Drop lower octets which are all zero.
421 *
422 * If this results in a zero-length string, so be it.
423 *
424 * Note also that "There is no relationship between the number of bytes omitted and the
425 * prefix length."
426 */
427 do {
428 if (*end != 0) break;
429
430 end--;
431 } while (end != p);
432
433 slen = cbor_encode_octets(&work_dbuff, p, (end - p) + (*end != 0));
434 if (slen <= 0) return_slen;
435
436 break;
437
438 case FR_TYPE_FLOAT32:
439 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | CBOR_4_BYTE));
440 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *) &vb->vb_float32, sizeof(vb->vb_float32));
441 break;
442
443 case FR_TYPE_FLOAT64:
444 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | CBOR_8_BYTE));
445 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *) &vb->vb_float64, sizeof(vb->vb_float64));
446 break;
447
448 case FR_TYPE_GROUP:
449 /*
450 * Zero-length array.
451 */
452 if (fr_value_box_list_num_elements(&vb->vb_group) == 0) {
453 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 0));
454 break;
455 }
456
457 /*
458 * The value is array(children)
459 */
460 slen = cbor_encode_integer(&work_dbuff, CBOR_ARRAY,
461 fr_value_box_list_num_elements(&vb->vb_group));
462 if (slen <= 0) return_slen;
463
464
465 fr_value_box_list_foreach(&vb->vb_group, child) {
466 slen = fr_cbor_encode_value_box(&work_dbuff, child);
467 if (slen <= 0) return_slen;
468 }
469 break;
470
471
472 default:
473 fr_strerror_printf("Invalid data type %s for cbor encoding", fr_type_to_str(vb->type));
474 return -1;
475 }
476
477 return fr_dbuff_set(dbuff, &work_dbuff);
478}
479
480
481static ssize_t cbor_decode_integer(uint64_t *out, uint8_t info, fr_dbuff_t *dbuff)
482{
483 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
484
485 if (info < 24) {
486 *out = info;
487 return 0;
488 }
489
490 if (info == CBOR_1_BYTE) {
492
493 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
494 *out = value;
495 goto done;
496 }
497
498 if (info == CBOR_2_BYTE) {
500
501 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
502 *out = value;
503 goto done;
504 }
505
506 if (info == CBOR_4_BYTE) {
508
509 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
510 *out = value;
511 goto done;
512 }
513
514 if (info == CBOR_8_BYTE) {
515 uint64_t value;
516
517 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
518 *out = value;
519 goto done;
520 }
521
522 /*
523 * 28 and greater are invalid according to the RFCs.
524 */
525 if (info > CBOR_8_BYTE) return -1;
526
527done:
528 return fr_dbuff_set(dbuff, &work_dbuff);
529}
530
531static ssize_t cbor_decode_count(uint64_t *out, int expected, fr_dbuff_t *dbuff)
532{
533 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
534 uint8_t major, info;
535 ssize_t slen;
536
537 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
538
539 info = major & 0x1f;
540 major >>= 5;
541
542 if (major != expected) {
543 fr_strerror_printf("Expected cbor type '%s', got unexpected type %d ",
544 cbor_type_to_str[expected], major);
545 return -1;
546 }
547
548 slen = cbor_decode_integer(out, info, &work_dbuff);
549 if (slen < 0) return_slen;
550
551 return fr_dbuff_set(dbuff, &work_dbuff);
552}
553
554typedef ssize_t (*cbor_decode_type_t)(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff);
555
556static ssize_t cbor_decode_octets_memcpy(uint8_t *dst, size_t dst_min, size_t dst_max, fr_dbuff_t *dbuff)
557{
558 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
559 ssize_t slen;
560 uint64_t value = 0;
561
562 slen = cbor_decode_count(&value, CBOR_OCTETS, &work_dbuff);
563 if (slen < 0) return_slen;
564
565 if (value < dst_min) {
566 fr_strerror_printf("Invalid length for data - expected at least %zu got %" PRIu64, dst_min, value);
567 return -1;
568 }
569
570 if (value > dst_max) {
571 fr_strerror_printf("Invalid length for data - expected no more than %zu got %" PRIu64, dst_max, value);
572 return -1;
573 }
574
575 FR_DBUFF_OUT_MEMCPY_RETURN(dst, &work_dbuff, value);
576
577 return fr_dbuff_set(dbuff, &work_dbuff);
578}
579
580#if 0
581static ssize_t *cbor_decode_octets_memdup(TALLOC_CTX *ctx, uint8_t **out, fr_dbuff_t *dbuff)
582{
583 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
584 ssize_t slen;
585 uint64_t value;
586 uint8_t *ptr;
587
588 slen = cbor_decode_count(&value, CBOR_OCTETS, &work_dbuff);
589 if (slen < 0) return_slen;
590
591 if (value > (1 << 20)) {
592 fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
593 return -1;
594 }
595
596 ptr = talloc_array(ctx, uint8_t, value);
597 if (!ptr) {
598 fr_strerror_const("Out of memory");
599 return -1;
600 }
601
602 FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
603 *out = ptr;
604
605 return fr_dbuff_set(dbuff, &work_dbuff);
606}
607#endif
608
609static ssize_t cbor_decode_ethernet(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
610{
611 return cbor_decode_octets_memcpy(vb->vb_ether, sizeof(vb->vb_ether), sizeof(vb->vb_ether), dbuff);
612}
613
615{
616 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
617 ssize_t slen;
618 uint8_t header;
619 size_t count = 0;
620 uint64_t value = 0;
621
622 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
623
624 header = *fr_dbuff_current(&work_dbuff);
625 if ((header >> 5) == CBOR_ARRAY) {
626 count = header & 0x1f;
627
628 if ((count != 2) && (count != 3)) {
629 fr_strerror_printf("Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
630 header);
631 return -1;
632 }
633
634 fr_dbuff_advance(&work_dbuff, 1);
635 }
636
637 vb->vb_ip.prefix = 32;
638
639 /*
640 * Get the IP address.
641 */
642 slen = cbor_decode_octets_memcpy((uint8_t *) &vb->vb_ipv4addr,
643 sizeof(vb->vb_ipv4addr),
644 sizeof(vb->vb_ipv4addr), &work_dbuff);
645 if (slen <= 0) return_slen;
646
647 if (!count) return fr_dbuff_set(dbuff, &work_dbuff);
648
649 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
650 if (slen <= 0) return_slen;
651
652 if (value != 32) {
653 fr_strerror_printf("Invalid IPv4 address - expected prefix = 32 got %" PRIu64, value);
654 return -fr_dbuff_used(&work_dbuff);
655 }
656
657 if (count == 2) return fr_dbuff_set(dbuff, &work_dbuff);
658
659 /*
660 * Get the scope ID
661 */
662 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
663 if (slen <= 0) return_slen;
664
665 if (value > UINT32_MAX) {
666 fr_strerror_printf("Invalid IPv4 address - scope ID %" PRIu64 " is larger than 32 bits", value);
667 return -fr_dbuff_used(&work_dbuff);
668 }
669
670 vb->vb_ip.scope_id = (uint32_t) value;
671
672 return fr_dbuff_set(dbuff, &work_dbuff);
673}
674
676{
677 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
678 ssize_t slen;
679 uint8_t header;
680 size_t count = 0;
681 uint64_t value = 0;
682
683 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
684
685 header = *fr_dbuff_current(&work_dbuff);
686 if ((header >> 5) == CBOR_ARRAY) {
687 count = header & 0x1f;
688
689 if ((count != 2) && (count != 3)) {
690 fr_strerror_printf("Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
691 header);
692 return -1;
693 }
694
695 fr_dbuff_advance(&work_dbuff, 1);
696 }
697
698 vb->vb_ip.prefix = 128;
699
700 /*
701 * Get the IP address.
702 */
703 slen = cbor_decode_octets_memcpy((uint8_t *) &vb->vb_ipv6addr,
704 sizeof(vb->vb_ipv6addr),
705 sizeof(vb->vb_ipv6addr), &work_dbuff);
706
707 if (slen <= 0) return_slen;
708
709 if (!count) return fr_dbuff_set(dbuff, &work_dbuff);
710
711 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
712 if (slen <= 0) return_slen;
713
714 if (value != 128) {
715 fr_strerror_printf("Invalid IPv6 address - expected prefix = 128 got %" PRIu64, value);
716 return -fr_dbuff_used(&work_dbuff);
717 }
718
719 vb->vb_ip.prefix = value;
720
721 if (count == 2) return fr_dbuff_set(dbuff, &work_dbuff);
722
723 /*
724 * Get the scope ID
725 */
726 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
727 if (slen <= 0) return_slen;
728
729 if (value > UINT32_MAX) {
730 fr_strerror_printf("Invalid IPv6 address - scope ID %" PRIu64 " is larger than 32 bits", value);
731 return -fr_dbuff_used(&work_dbuff);
732 }
733
734 vb->vb_ip.scope_id = (uint32_t) value;
735
736 return fr_dbuff_set(dbuff, &work_dbuff);
737}
738
740{
741 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
742 ssize_t slen;
743 uint8_t header;
744 uint64_t value = 0;
745 uint8_t buffer[sizeof(vb->vb_ipv4addr)];
746
747 FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
748
749 if (header != ((CBOR_ARRAY << 5) | 2)) {
750 fr_strerror_printf("Invalid IPv4 prefix - expected array of 2 elements, got %02x",
751 header);
752 return -1;
753 }
754
755 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
756 if (slen <= 0) return_slen;
757
758 if (value > 32) {
759 fr_strerror_printf("Invalid IPv4 prefix - expected prefix < 32, got %" PRIu64, value);
760 return -1;
761 }
762
763 /*
764 * RFC 9164 Section 4.3 - Trailing bytes of zero are omitted, so we
765 * first copy the data to a fixed-sized buffer which was
766 * zeroed out, and then (@todo) also check that unused bits in
767 * the last byte are all zero.
768 */
769 memset(buffer, 0, sizeof(buffer));
770
771 slen = cbor_decode_octets_memcpy(buffer, 0, sizeof(buffer), &work_dbuff);
772 if (slen <= 0) return_slen;
773
774 memcpy((uint8_t *) &vb->vb_ipv4addr, buffer, sizeof(vb->vb_ipv4addr));
775 vb->vb_ip.prefix = value;
776
777 return fr_dbuff_set(dbuff, &work_dbuff);
778}
779
781{
782 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
783 ssize_t slen;
784 uint8_t header;
785 uint64_t value = 0;
786 uint8_t buffer[sizeof(vb->vb_ipv6addr)];
787
788 FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
789
790 if (header != ((CBOR_ARRAY << 5) | 2)) {
791 fr_strerror_printf("Invalid IPv6 prefix - expected array of 2 elements, got %02x",
792 header);
793 return -1;
794 }
795
796 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
797 if (slen <= 0) return_slen;
798
799 if (value > 128) {
800 fr_strerror_printf("Invalid IPv6 prefix - expected prefix < 128, got %" PRIu64, value);
801 return -1;
802 }
803
804 /*
805 * RFC 9164 Section 4.3 - Trailing bytes of zero are omitted, so we
806 * first copy the data to a fixed-sized buffer which was
807 * zeroed out, and then (@todo) also check that unused bits in
808 * the last byte are all zero.
809 */
810 memset(buffer, 0, sizeof(buffer));
811
812 slen = cbor_decode_octets_memcpy(buffer, 0, sizeof(buffer), &work_dbuff);
813 if (slen <= 0) return_slen;
814
815 memcpy((uint8_t *) &vb->vb_ipv6addr, buffer, sizeof(vb->vb_ipv6addr));
816 vb->vb_ip.prefix = value;
817
818 return fr_dbuff_set(dbuff, &work_dbuff);
819}
820
822{
823 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
824 ssize_t slen;
825 uint8_t major, info;
826 uint64_t value = 0;
827 int64_t neg;
828
829 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
830
831 info = major & 0x1f;
832 major >>= 5;
833
834 switch (major) {
835 case CBOR_INTEGER:
836 slen = cbor_decode_integer(&value, info, &work_dbuff);
837 if (slen < 0) return_slen;
838
839 if (value >= ((uint64_t) 1) << 63) { /* equal! */
840 invalid:
841 fr_strerror_printf("cbor value is too large for output data type %s",
843 return -1;
844 }
845
846 *out = value;
847 break;
848
849 case CBOR_NEGATIVE:
850 slen = cbor_decode_integer(&value, info, &work_dbuff);
851 if (slen < 0) return_slen;
852
853 if (value >= ((uint64_t) 1) << 63) goto invalid; /* greater than! */
854
855 /*
856 * Convert 0..(2^63-1) into -0..-(2^63-1)
857 * then conver to -1..-(2^63)
858 */
859 neg = -value;
860 neg--;
861
862 *out = neg;
863 break;
864
865 default:
866 fr_strerror_printf("cbor data contains invalid content %d for expected data type %s",
867 major, fr_type_to_str(type));
868 return -1;
869 }
870
871 return fr_dbuff_set(dbuff, &work_dbuff);
872
873}
874
875static ssize_t cbor_decode_date(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
876{
877 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
878 ssize_t slen;
879 int64_t neg;
880
881 slen = cbor_decode_int64(&neg, &work_dbuff, FR_TYPE_DATE);
882 if (slen <= 0) return_slen;
883
884 vb->vb_date = fr_unix_time_from_sec(neg);
885
886 return fr_dbuff_set(dbuff, &work_dbuff);
887}
888
889/*
890 * Tag 1002, followed by map of at least 2 elements
891 * key 1: seconds
892 * key -9: nanoseconds
893 */
895{
896 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
897 uint64_t count;
898 ssize_t slen;
899 int64_t key, seconds, fraction, scale;
900
901 slen = cbor_decode_count(&count, CBOR_MAP, &work_dbuff);
902 if (slen < 0) return_slen;
903
904 if (!count || (count > 2)) {
905 fr_strerror_printf("Unexpected count %" PRIu64" for time_delta, expected map of 1-2 elements", count);
906 return -1;
907 }
908
909 key = seconds = fraction = 0;
910
911 /*
912 * Expect key 1:seconds
913 */
914 slen = cbor_decode_int64(&key, &work_dbuff, FR_TYPE_TIME_DELTA);
915 if (slen < 0) return_slen;
916
917 if (key != 1) {
918 fr_strerror_printf("Unexpected key %" PRIi64 " for time_delta, expected key 1", key);
919 return -1;
920 }
921
922 slen = cbor_decode_int64(&seconds, &work_dbuff, FR_TYPE_TIME_DELTA);
923 if (slen < 0) return_slen;
924
925 if (count > 1) {
926 slen = cbor_decode_int64(&key, &work_dbuff, FR_TYPE_TIME_DELTA);
927 if (slen < 0) return_slen;
928
929 switch (key) {
930 case -3:
931 scale = MSEC;
932 break;
933
934 case -6:
935 scale = USEC;
936 break;
937
938 case -9:
939 scale = NSEC;
940 break;
941
942 default:
943 fr_strerror_printf("Unsupported time_delta key %" PRIi64, key);
944 return -fr_dbuff_used(&work_dbuff); /* point to actual key? */
945
946 }
947
948 slen = cbor_decode_int64(&fraction, &work_dbuff, FR_TYPE_TIME_DELTA);
949 if (slen < 0) return_slen;
950
951 if ((fraction < 0) || (fraction > scale)) fraction = 0;
952 } else {
953 scale = NSEC;
954 fraction = 0;
955 }
956
957 if (seconds > (INT64_MAX / scale)) {
958 vb->vb_time_delta = fr_time_delta_max();
959
960 } else if (seconds < (INT64_MIN / scale)) {
961 vb->vb_time_delta = fr_time_delta_min();
962
963 } else {
964 seconds *= scale;
965
966 if (seconds < 0) {
967 seconds -= fraction;
968 } else {
969 seconds += fraction;
970 }
971
972 vb->vb_time_delta = fr_time_delta_wrap(seconds);
973 }
974
975 return fr_dbuff_set(dbuff, &work_dbuff);
976}
977
978
991
992/*
993 * @todo - fr_cbor_encode_pair_list(). And then if we have da->flags.array, we encode the _value_ as an
994 * array of indeterminate length. This is a little bit of a special case, but not terrible.
995 */
997 fr_type_t type, fr_dict_attr_t const *enumv, bool tainted)
998{
999 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1000 bool indefinite;
1001 uint8_t major, info;
1002 ssize_t slen;
1003 int64_t neg;
1004 uint64_t value;
1005 uint8_t *ptr;
1006
1007 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1008
1009 if (type == FR_TYPE_NULL) {
1010 type = cbor_guess_type(&work_dbuff, false);
1011 if (type == FR_TYPE_NULL) {
1012 fr_strerror_const("Unable to determine data type from cbor");
1013 return -1;
1014 }
1015 }
1016
1017 fr_value_box_init(vb, type, enumv, tainted);
1018
1019 info = major & 0x1f;
1020 major >>= 5;
1021
1022 /*
1023 * Invalid combinations.
1024 */
1025 if (((info >= 28) && (info <= 30)) ||
1026 ((info == 31) && ((major == 0) || (major == 1) || (major == 6)))) {
1027 fr_strerror_const("Invalid cbor data - input is not 'well formed'");
1028 return -1;
1029 }
1030
1031 switch (major) {
1032 case CBOR_STRING:
1033 if (type != FR_TYPE_STRING) {
1034 mismatch:
1035 fr_strerror_printf("cbor data contains invalid content %d for expected data type %s",
1036 major, fr_type_to_str(type));
1037 return -1;
1038 }
1039
1040 if (info == 31) {
1041 no_chunks:
1042 fr_strerror_const("Chunked strings are not supported");
1043 return -1;
1044 }
1045
1046
1047 /*
1048 * @todo - undefinite length strings. Which are really "chunked" strings.
1049 */
1050 slen = cbor_decode_integer(&value, info, &work_dbuff);
1051 if (slen < 0) return_slen;
1052
1053 /*
1054 * A little bit of sanity check.
1055 */
1056 if (value > (1 << 20)) {
1057 fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
1058 return -1;
1059 }
1060
1061 ptr = talloc_array(ctx, uint8_t, value + 1);
1062 if (!ptr) {
1063 fr_strerror_const("Out of memory");
1064 return -1;
1065 }
1066 talloc_set_type(ptr, char);
1067 if (value) FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
1068 ptr[value] = '\0';
1069
1070 fr_value_box_strdup_shallow(vb, NULL, (char const *) ptr, tainted);
1071
1072 break;
1073
1074 case CBOR_OCTETS:
1075 if (type != FR_TYPE_OCTETS) goto mismatch;
1076
1077 if (info == 31) goto no_chunks;
1078
1079 /*
1080 * @todo - indefinite length octet strings. Which are really "chunked" octet strings.
1081 */
1082 slen = cbor_decode_integer(&value, info, &work_dbuff);
1083 if (slen < 0) return_slen;
1084
1085 /*
1086 * A little bit of sanity check.
1087 */
1088 if (value > (1 << 20)) {
1089 fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
1090 return -1;
1091 }
1092
1093 ptr = talloc_array(ctx, uint8_t, value);
1094 if (!ptr) {
1095 fr_strerror_const("Out of memory");
1096 return -1;
1097 }
1098
1099 fr_value_box_memdup_shallow(vb, NULL, (uint8_t const *) ptr, value, false); /* tainted? */
1100
1101 if (value) FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
1102 break;
1103
1104 case CBOR_INTEGER:
1105 slen = cbor_decode_integer(&value, info, &work_dbuff);
1106 if (slen < 0) return_slen;
1107
1108 switch (type) {
1109 case FR_TYPE_BOOL:
1110 if (value > 1) goto invalid_bool;
1111 vb->vb_bool = value;
1112 break;
1113
1114 case FR_TYPE_UINT8:
1115 if (value > UINT8_MAX) {
1116 invalid:
1117 fr_strerror_printf("cbor value is too large for output data type %s",
1119 return -1;
1120 }
1121 vb->vb_uint8 = value;
1122 break;
1123
1124 case FR_TYPE_UINT16:
1125 if (value > UINT16_MAX) goto invalid;
1126 vb->vb_uint16 = value;
1127 break;
1128
1129 case FR_TYPE_UINT32:
1130 if (value > UINT32_MAX) goto invalid;
1131 vb->vb_uint32 = (uint32_t) value;
1132 break;
1133
1134 case FR_TYPE_UINT64:
1135 vb->vb_uint64 = value;
1136 break;
1137
1138 case FR_TYPE_INT8:
1139 if (value > INT8_MAX) goto invalid;
1140 vb->vb_int8 = value;
1141 break;
1142
1143 case FR_TYPE_INT16:
1144 if (value > INT16_MAX) goto invalid;
1145 vb->vb_int16 = value;
1146 break;
1147
1148 case FR_TYPE_INT32:
1149 if (value > INT32_MAX) goto invalid;
1150 vb->vb_int32 = (int32_t) value;
1151 break;
1152
1153 case FR_TYPE_INT64:
1154 if (value > INT64_MAX) goto invalid;
1155 vb->vb_int64 = value;
1156 break;
1157
1158 default:
1159 integer_type_mismatch:
1160 fr_strerror_printf("Unexpected cbor type 'integer' when decoding data type %s",
1162 return -1;
1163 }
1164 break;
1165
1166 case CBOR_NEGATIVE:
1167 slen = cbor_decode_integer(&value, info, &work_dbuff);
1168 if (slen < 0) return_slen;
1169
1170 /*
1171 * Signed numbers only go down to -2^63
1172 * so value must be less than 2^63
1173 */
1174 if (value >= ((uint64_t) 1) << 63) goto invalid;
1175
1176 /*
1177 * Convert 0..(2^63-1) into -0..-(2^63-1)
1178 * then conver to -1..-(2^63)
1179 */
1180 neg = -value;
1181 neg--;
1182
1183 switch (type) {
1184 case FR_TYPE_INT8:
1185 if (neg < INT8_MIN) goto invalid;
1186 vb->vb_int8 = neg;
1187 break;
1188
1189 case FR_TYPE_INT16:
1190 if (neg < INT16_MIN) goto invalid;
1191 vb->vb_int16 = neg;
1192 break;
1193
1194 case FR_TYPE_INT32:
1195 if (neg < INT32_MIN) goto invalid;
1196 vb->vb_int32 = (int32_t) neg;
1197 break;
1198
1199 case FR_TYPE_INT64:
1200 vb->vb_int64 = neg;
1201 break;
1202
1203 default:
1204 goto integer_type_mismatch;
1205 }
1206 break;
1207
1208 case CBOR_FLOAT:
1209 /*
1210 * Simple values. See RFC 8489 Section 3.3.
1211 *
1212 * 20 - false
1213 * 21 - true
1214 * 22 - NULL
1215 */
1216 if (info < 24) {
1217 switch (type) {
1218 case FR_TYPE_BOOL:
1219 if (info == 20) {
1220 vb->vb_bool = false;
1221 break;
1222 }
1223
1224 if (info == 21) {
1225 vb->vb_bool = true;
1226 break;
1227 }
1228
1229 invalid_bool:
1230 fr_strerror_printf("Invalid cbor - boolean is not encoded as 'true' or 'false'");
1231 return -fr_dbuff_used(&work_dbuff);
1232
1233 case FR_TYPE_OCTETS:
1234 case FR_TYPE_STRING:
1235 case FR_TYPE_TLV:
1236 case FR_TYPE_VENDOR:
1237 case FR_TYPE_GROUP:
1238 case FR_TYPE_STRUCT:
1239 /*
1240 * Be a little forgiving. 22 is NULL, so we treat that as "nothing".
1241 *
1242 * i.e. empty string, empty set, etc.
1243 */
1244 if (info == 22) break;
1245
1247
1248 default:
1249 fr_strerror_printf("Invalid cbor - unexpected 'simple value' %u", info);
1250 return -fr_dbuff_used(&work_dbuff);
1251 }
1252 break;
1253 }
1254
1255 /*
1256 * Or as one-byte integers.
1257 */
1258 if (info == CBOR_1_BYTE) {
1259 uint8_t data;
1260
1261 FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1262
1263 switch (type) {
1264 case FR_TYPE_FLOAT32:
1265 vb->vb_float32 = data;
1266 break;
1267
1268 case FR_TYPE_FLOAT64:
1269 vb->vb_float64 = data;
1270 break;
1271
1272 default:
1273 float_type_mismatch:
1274 fr_strerror_printf("Unexpected cbor type 'float' when decoding data type %s",
1276 return -1;
1277 }
1278
1279 break;
1280 }
1281
1282 /*
1283 * We don't support float16
1284 */
1285
1286 if (info == CBOR_4_BYTE) {
1287 float data;
1288
1289 FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1290
1291 switch (type) {
1292 case FR_TYPE_FLOAT32:
1293 vb->vb_float32 = data;
1294 break;
1295
1296 case FR_TYPE_FLOAT64:
1297 vb->vb_float64 = (double) data;
1298 break;
1299
1300 default:
1301 goto float_type_mismatch;
1302 }
1303
1304 break;
1305 }
1306
1307 if (info == CBOR_8_BYTE) {
1308 double data;
1309
1310 FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1311
1312 switch (type) {
1313 case FR_TYPE_FLOAT32:
1314 vb->vb_float32 = data; /* maybe loses precision? */
1315 break;
1316
1317 case FR_TYPE_FLOAT64:
1318 vb->vb_float64 = data;
1319 break;
1320
1321 default:
1322 goto float_type_mismatch;
1323 }
1324
1325 break;
1326 }
1327
1328 /*
1329 * 24 is FLOAT16, which we don't support.
1330 * 31 is BREAK, which the caller should have checked for.
1331 */
1332 goto float_type_mismatch;
1333
1334 case CBOR_TAG:
1335 /*
1336 * We only support a limited number of tags.
1337 */
1338 slen = cbor_decode_integer(&value, info, &work_dbuff);
1339 if (slen < 0) return_slen;
1340
1341 /*
1342 * No tag defined for this data type, that's on us.
1343 */
1344 if (!cbor_type_to_tag[type]) {
1345 fr_strerror_printf("Unknown cbor tag %" PRIu64 " for expected data type %s",
1347 return -fr_dbuff_used(&work_dbuff);
1348 }
1349
1350 /*
1351 * Wrong tag for this data type, that's on them.
1352 */
1353 if (cbor_type_to_tag[type] != value) {
1354 fr_strerror_printf("Invalid cbor tag %" PRIu64 " for expected data type %s",
1356 return -fr_dbuff_used(&work_dbuff);
1357 }
1358
1359 fr_value_box_init(vb, type, enumv, tainted);
1360
1361 slen = cbor_decode_type[type](ctx, vb, &work_dbuff);
1362 if (slen < 0) return_slen;
1363 break;
1364
1365 case CBOR_ARRAY:
1366 if (type != FR_TYPE_GROUP) goto invalid_type;
1367
1368 /*
1369 * Loop until done.
1370 */
1371 if (info == 31) {
1372 value = ~0;
1373 indefinite = true;
1374
1375 } else {
1376 slen = cbor_decode_integer(&value, info, &work_dbuff);
1377 if (slen < 0) return_slen;
1378
1379 indefinite = false;
1380 }
1381
1382#ifdef STATIC_ANALYZER
1383 if (value > fr_dbuff_remaining(&work_dbuff)) return -1;
1384#endif
1385
1386 /*
1387 * Loop until we decode everything. For simplicity, we handle indefinite and definite
1388 * length arrays in the same loop.
1389 */
1390 for (/* nothing */; value > 0; value--) {
1391 uint8_t header;
1392 fr_value_box_t *child;
1393
1394 /*
1395 * Require at least one byte in the buffer.
1396 */
1397 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
1398
1399 /*
1400 * Peek ahead for a break.
1401 */
1402 header = *fr_dbuff_current(&work_dbuff);
1403 if (header == 0xff) {
1404 if (!indefinite) {
1405 fr_strerror_const("Unexpected 'break' found in cbor data");
1406 return -fr_dbuff_used(&work_dbuff);
1407 }
1408
1409 /*
1410 * Done!
1411 */
1412 fr_dbuff_advance(&work_dbuff, 1);
1413 break;
1414 }
1415
1416 child = fr_value_box_alloc(ctx, FR_TYPE_NULL, NULL);
1417 if (!child) {
1418 fr_strerror_const("Out of memory");
1419 return -fr_dbuff_used(&work_dbuff);
1420 }
1421
1422 /*
1423 * We have to decode at least one value.
1424 */
1425 slen = fr_cbor_decode_value_box(child, child, &work_dbuff, FR_TYPE_NULL, NULL, tainted);
1426 if (slen <= 0) {
1427 talloc_free(child);
1429 }
1430
1431 fr_value_box_list_insert_tail(&vb->vb_group, child);
1432 }
1433 break;
1434
1435 /*
1436 * These are not value-box types.
1437 */
1438 case CBOR_MAP:
1440 fr_strerror_printf("Invalid data type %s for cbor to value-box", fr_type_to_str(type));
1441 return -1;
1442 }
1443
1444 return fr_dbuff_set(dbuff, &work_dbuff);
1445}
1446
1447/** Encode a pair
1448 *
1449 */
1451{
1452 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1453 ssize_t slen;
1454 fr_dict_attr_t const *parent;
1455 size_t count;
1456
1457 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_MAP << 5) | 1)); /* map of 1 item */
1458
1459 /*
1460 * Key is the attribute number.
1461 */
1462 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vp->da->attr);
1463 if (slen <= 0) return_slen;
1464
1465 /*
1466 * Value is the actual value of the leaf, or the array of children.
1467 */
1468 switch (vp->vp_type) {
1469 case FR_TYPE_LEAF:
1470 slen = fr_cbor_encode_value_box(&work_dbuff, &vp->data);
1471 if (slen <= 0) return_slen;
1472 break;
1473
1474 /*
1475 * Groups reparent to the ref.
1476 */
1477 case FR_TYPE_GROUP:
1479 fr_assert(parent != NULL);
1480 goto encode_children;
1481
1482 /*
1483 * The only difference between TLV and VSA is that the children of VSA are all VENDORs.
1484 */
1485 case FR_TYPE_VENDOR:
1486 case FR_TYPE_VSA:
1487 case FR_TYPE_TLV:
1488 parent = vp->da;
1489
1490 /*
1491 * The value is array(children)
1492 */
1493encode_children:
1494 if (fr_pair_list_num_elements(&vp->vp_group) == 0) {
1495 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | 22)); /* NULL */
1496 break;
1497 }
1498
1499 /*
1500 * The groups, etc. may contain internal attributes. We don't yet deal with those.
1501 */
1502 count = 0;
1503 fr_pair_list_foreach(&vp->vp_group, child) {
1504 if (child->da->parent != parent) continue;
1505 count++;
1506 }
1507
1508 slen = cbor_encode_integer(&work_dbuff, CBOR_ARRAY, count);
1509 if (slen <= 0) return_slen;
1510
1511 fr_pair_list_foreach(&vp->vp_group, child) {
1512 /*
1513 * We don't allow changing dictionaries here.
1514 */
1515 if (child->da->parent != parent) continue;
1516
1517 slen = fr_cbor_encode_pair(&work_dbuff, child);
1518 if (slen <= 0) return_slen;
1519 }
1520 break;
1521
1522 /*
1523 * @todo - struct, except if we hit the end of the struct, check if the next child is the child
1524 * of the key? That makes it all more annoying :(
1525 */
1526
1527 default:
1528 fr_strerror_printf("Invalid data type %s for cbor encoding", fr_type_to_str(vp->vp_type));
1529 return -1;
1530 }
1531
1532 return fr_dbuff_set(dbuff, &work_dbuff);
1533}
1534
1535/** Guess the data type of the CBOR data.
1536 *
1537 * We've parsed the attribute number, and found that we don't have a dictionary entry for it. But rather
1538 * than create an attribute of type octets, we try to guess the data type.
1539 */
1540static fr_type_t cbor_guess_type(fr_dbuff_t *dbuff, bool pair)
1541{
1542 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1543 ssize_t slen;
1544 uint8_t major, info;
1545 uint64_t value;
1546
1547 /*
1548 * get the next byte, which is a CBOR header.
1549 */
1550 slen = fr_dbuff_out(&major, &work_dbuff);
1551 if (slen <= 0) {
1552 no_data:
1553 fr_strerror_const("Invalid cbor - insufficient data");
1554 return FR_TYPE_NULL;
1555 }
1556
1557 info = major & 0x1f;
1558 major >>= 5;
1559
1560 switch (major) {
1561 case CBOR_INTEGER:
1562 return FR_TYPE_UINT64;
1563
1564 case CBOR_NEGATIVE:
1565 return FR_TYPE_INT64;
1566
1567 case CBOR_STRING:
1568 return FR_TYPE_STRING;
1569
1570 case CBOR_OCTETS:
1571 return FR_TYPE_OCTETS;
1572
1573 case CBOR_ARRAY:
1574 if (!pair) return FR_TYPE_GROUP;
1575 break;
1576
1577 case CBOR_MAP:
1578 return FR_TYPE_TLV;
1579
1580 /*
1581 * Look at the tag to determine what it is
1582 */
1583 case CBOR_TAG:
1584 slen = cbor_decode_integer(&value, info, &work_dbuff);
1585 if (slen < 0) break;
1586
1587 switch (value) {
1588 case 1:
1589 case 1001:
1590 return FR_TYPE_DATE;
1591
1592 case 1002:
1593 return FR_TYPE_TIME_DELTA;
1594
1595 case 48:
1596 return FR_TYPE_ETHERNET;
1597
1598 case 52:
1599 slen = fr_dbuff_out(&major, &work_dbuff);
1600 if (slen <= 0) goto no_data;
1601
1602 major >>= 5;
1603
1604 if (major == CBOR_ARRAY) {
1605 return FR_TYPE_IPV4_PREFIX;
1606 }
1607 return FR_TYPE_IPV4_ADDR;
1608
1609 case 54:
1610 slen = fr_dbuff_out(&major, &work_dbuff);
1611 if (slen <= 0) goto no_data;
1612
1613 major >>= 5;
1614
1615 if (major == CBOR_ARRAY) {
1616 return FR_TYPE_IPV6_PREFIX;
1617 }
1618 return FR_TYPE_IPV6_ADDR;
1619
1620 default:
1621 break;
1622 }
1623
1624 break;
1625
1626 case CBOR_FLOAT:
1627 /*
1628 * In-place values are special. false / true / NULL
1629 */
1630 if (info < 24) {
1631 if ((info == 20) || (info == 21)) return FR_TYPE_BOOL;
1632
1633 return FR_TYPE_NULL;
1634 }
1635
1636 return FR_TYPE_FLOAT64;
1637 }
1638
1639
1640 /*
1641 * No idea. :(
1642 *
1643 * @todo - also check the cbor data, and return the length of cbor data which needs to be
1644 * converted to data type 'octets'. This work involves mostly parsing the cbor data, which isn't
1645 * trivial.
1646 */
1647 fr_strerror_const("Invalid cbor - unable to determine data type");
1648 return FR_TYPE_NULL;
1649}
1650
1651static ssize_t cbor_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dbuff_t *dbuff,
1652 fr_dict_attr_t const *parent, bool tainted, int depth)
1653{
1654 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1655 uint8_t header, major, info;
1656 bool indefinite;
1657 ssize_t slen;
1658 fr_pair_t *vp;
1659 uint64_t value = 0;
1660 fr_dict_attr_t const *da;
1661
1662 FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
1663
1664 /*
1665 * We require a 2-element array(attribute number, value)
1666 */
1667 if (header != (((CBOR_MAP) << 5) | 1)) {
1668 fr_strerror_printf("Invalid cbor header - expected map of 1 elements, got %02x", header);
1669 return -1;
1670 }
1671
1672 /*
1673 * This should be a CBOR_INTEGER.
1674 */
1675 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1676
1677 info = major & 0x1f;
1678 major >>= 5;
1679
1680 if (major != CBOR_INTEGER) {
1681 fr_strerror_printf("Invalid cbor - expected 'integer', got major type %d",
1682 major);
1683 return -1;
1684 }
1685
1686 slen = cbor_decode_integer(&value, info, &work_dbuff);
1687 if (slen < 0) {
1689 }
1690
1691 if (value > UINT32_MAX) {
1692 fr_strerror_printf("Invalid cbor - attribute number %" PRIu64 " is larger than 32 bits", value);
1693 return -fr_dbuff_used(&work_dbuff);
1694 }
1695
1696 /*
1697 * If the nesting is too deep, decode as raw octets. We have to do this manually in CBOR,
1698 * because the other protocols create a da_stack which limits the depth.
1699 */
1700 if (depth >= FR_DICT_MAX_TLV_STACK) goto raw;
1701
1702 da = fr_dict_attr_child_by_num(parent, (unsigned int) value);
1703 if (!da) {
1705
1706 type = cbor_guess_type(&work_dbuff, true);
1707 if (type == FR_TYPE_NULL) return -fr_dbuff_used(&work_dbuff);
1708
1710 raw:
1712 }
1713
1714 /*
1715 * @todo - the value here isn't a cbor octets type, but is instead cbor data. Since cbor
1716 * is typed, we _could_ perhaps instead discover the type from the cbor data, and then
1717 * use that instead. This would involve creating a function which maps cbor types to our
1718 * data types.
1719 */
1720 da = fr_dict_attr_unknown_typed_afrom_num(ctx, parent, (unsigned int) value, type);
1721 if (!da) return -fr_dbuff_used(&work_dbuff);
1722 }
1723
1724 vp = fr_pair_afrom_da(ctx, da);
1725 if (!vp) {
1726 fr_strerror_const("Out of memory");
1727 return -fr_dbuff_used(&work_dbuff);
1728 }
1729
1730 /*
1731 * Leaf values are easy.
1732 */
1733 if (fr_type_is_leaf(da->type)) {
1734 slen = fr_cbor_decode_value_box(vp, &vp->data, &work_dbuff, da->type, da, tainted);
1735 if (slen < 0) {
1736 talloc_free(vp);
1738 }
1739
1740 goto done;
1741 }
1742
1744
1745 switch (da->type) {
1746 /*
1747 * All of these are essentially the same.
1748 */
1749 case FR_TYPE_VENDOR:
1750 case FR_TYPE_VSA:
1751 case FR_TYPE_TLV:
1752 parent = vp->da;
1753 break;
1754
1755 /*
1756 * Groups reparent to the ref.
1757 */
1758 case FR_TYPE_GROUP:
1760 fr_assert(parent != NULL);
1761 break;
1762
1763 default:
1764 fr_strerror_printf("Invalid data type %s for child %s of %s",
1765 fr_type_to_str(da->type), vp->da->name, parent->name);
1766 talloc_free(vp);
1767 return -1;
1768 }
1769
1770 /*
1771 * This should be a CBOR_ARRAY.
1772 */
1773 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1774
1775 info = major & 0x1f;
1776 major >>= 5;
1777
1778 if (major != CBOR_ARRAY) {
1779 /*
1780 * Allow NULL as a synonym for "no children".
1781 */
1782 if ((major == CBOR_FLOAT) && (info == 22)) goto done;
1783
1784 talloc_free(vp);
1785 fr_strerror_printf("Invalid cbor - expected 'array', got major type %d",
1786 major);
1787 return -1;
1788 }
1789
1790 if (info == 31) {
1791 value = ~0;
1792 indefinite = true;
1793
1794 } else {
1795 slen = cbor_decode_integer(&value, info, &work_dbuff);
1796 if (slen < 0) {
1797 talloc_free(vp);
1799 }
1800
1801 indefinite = false;
1802 }
1803
1804#ifdef STATIC_ANALYZER
1805 if (value > fr_dbuff_remaining(&work_dbuff)) return -1;
1806#endif
1807
1808 /*
1809 * Loop until we decode everything. For simplicity, we handle indefinite and definite
1810 * length arrays in the same loop.
1811 */
1812 for (/* nothing */; value > 0; value--) {
1813 /*
1814 * Require at least one byte in the buffer.
1815 */
1816 if (fr_dbuff_extend_lowat(NULL, &work_dbuff, 1) == 0) {
1817 talloc_free(vp);
1818 return -fr_dbuff_used(&work_dbuff);
1819 }
1820
1821 /*
1822 * Peek ahead for a break.
1823 */
1824 header = *fr_dbuff_current(&work_dbuff);
1825 if (header == 0xff) {
1826 if (!indefinite) {
1827 talloc_free(vp);
1828 fr_strerror_const("Unexpected 'break' found in cbor data");
1829 return -fr_dbuff_used(&work_dbuff);
1830 }
1831
1832 /*
1833 * Done!
1834 */
1835 fr_dbuff_advance(&work_dbuff, 1);
1836 break;
1837 }
1838
1839 slen = cbor_decode_pair(vp, &vp->vp_group, &work_dbuff, parent, tainted, depth + 1);
1840 if (slen <= 0) {
1841 talloc_free(vp);
1843 }
1844 }
1845
1846done:
1848 return fr_dbuff_set(dbuff, &work_dbuff);
1849}
1850
1852 fr_dict_attr_t const *parent, bool tainted)
1853{
1854 return cbor_decode_pair(ctx, out, dbuff, parent, tainted, 0);
1855}
1856
1857/*
1858 * @todo - cbor_print
1859 * [] for array
1860 * [_...] for indefinite array
1861 * {a:b} for map
1862 * digits for integer
1863 * 'string' for string
1864 * h'HHHH' for octets
1865 *
1866 * https://datatracker.ietf.org/doc/html/draft-ietf-cbor-edn-literals
1867 */
static int const char char buffer[256]
Definition acutest.h:641
#define RCSID(id)
Definition build.h:603
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:422
#define UNUSED
Definition build.h:415
static int invalid_type(fr_type_t type)
Definition calc.c:699
ssize_t fr_cbor_encode_value_box(fr_dbuff_t *dbuff, fr_value_box_t *vb)
Encode CBOR.
Definition cbor.c:166
static ssize_t cbor_decode_ipv4_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:614
static ssize_t cbor_decode_int64(int64_t *out, fr_dbuff_t *dbuff, fr_type_t type)
Definition cbor.c:821
#define CBOR_2_BYTE
Definition cbor.c:37
static ssize_t cbor_decode_ipv6_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:675
#define CBOR_TAG
Definition cbor.c:33
static ssize_t cbor_decode_octets_memcpy(uint8_t *dst, size_t dst_min, size_t dst_max, fr_dbuff_t *dbuff)
Definition cbor.c:556
#define cbor_encode_tag(_dbuff, _tag)
Definition cbor.c:118
static ssize_t cbor_encode_octets(fr_dbuff_t *dbuff, uint8_t const *data, size_t data_len)
Definition cbor.c:128
ssize_t fr_cbor_encode_pair(fr_dbuff_t *dbuff, fr_pair_t *vp)
Encode a pair.
Definition cbor.c:1450
static const uint64_t cbor_type_to_tag[FR_TYPE_MAX+1]
Definition cbor.c:53
#define CBOR_INTEGER
Definition cbor.c:27
#define CBOR_1_BYTE
Definition cbor.c:36
#define CBOR_OCTETS
Definition cbor.c:29
static ssize_t cbor_decode_date(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:875
#define return_slen
Definition cbor.c:123
#define CBOR_FLOAT
Definition cbor.c:34
static cbor_decode_type_t cbor_decode_type[FR_TYPE_MAX]
Definition cbor.c:979
static ssize_t cbor_decode_time_delta(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:894
static ssize_t cbor_decode_ipv4_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:739
#define CBOR_NEGATIVE
Definition cbor.c:28
#define CBOR_4_BYTE
Definition cbor.c:38
static fr_type_t cbor_guess_type(fr_dbuff_t *dbuff, bool pair)
Guess the data type of the CBOR data.
Definition cbor.c:1540
static ssize_t cbor_encode_integer(fr_dbuff_t *dbuff, uint8_t type, uint64_t data)
Definition cbor.c:65
static ssize_t cbor_decode_integer(uint64_t *out, uint8_t info, fr_dbuff_t *dbuff)
Definition cbor.c:481
static ssize_t cbor_decode_ethernet(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:609
ssize_t fr_cbor_decode_value_box(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff, fr_type_t type, fr_dict_attr_t const *enumv, bool tainted)
Definition cbor.c:996
static ssize_t cbor_encode_int64(fr_dbuff_t *dbuff, int64_t neg)
Definition cbor.c:141
static ssize_t cbor_decode_ipv6_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:780
#define cbor_encode_array(_dbuff, _size)
Definition cbor.c:116
ssize_t fr_cbor_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dbuff_t *dbuff, fr_dict_attr_t const *parent, bool tainted)
Definition cbor.c:1851
#define CBOR_8_BYTE
Definition cbor.c:39
#define cbor_encode_key
Definition cbor.c:160
#define CBOR_MAP
Definition cbor.c:32
#define CBOR_ARRAY
Definition cbor.c:31
static ssize_t cbor_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dbuff_t *dbuff, fr_dict_attr_t const *parent, bool tainted, int depth)
Definition cbor.c:1651
static const char * cbor_type_to_str[8]
Definition cbor.c:41
ssize_t(* cbor_decode_type_t)(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:554
static ssize_t cbor_decode_count(uint64_t *out, int expected, fr_dbuff_t *dbuff)
Definition cbor.c:531
#define CBOR_STRING
Definition cbor.c:30
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
Definition dbuff.h:1121
#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:819
#define FR_DBUFF_EXTEND_LOWAT_OR_RETURN(_dbuff_or_marker, _lowat)
Extend if we're below _lowat and return if we can't extend above _lowat.
Definition dbuff.h:725
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:963
#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:1056
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
Definition dbuff.h:712
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
Definition dbuff.h:795
#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:1805
#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:1435
#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:1638
#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:1871
#define fr_dbuff_out(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type.
Definition dbuff.h:1852
#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:1525
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition dict.h:541
static fr_dict_attr_t * fr_dict_attr_unknown_typed_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num, fr_type_t type)
Definition dict.h:620
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:3667
static fr_dict_attr_t const * fr_dict_attr_ref(fr_dict_attr_t const *da)
Return the reference associated with a group type attribute.
Definition dict_ext.h:149
Test enumeration values.
Definition dict_test.h:92
talloc_free(hp)
unsigned short uint16_t
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_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_BOOL
A truth value.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
@ FR_TYPE_FLOAT64
Double precision floating point.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
#define UINT8_MAX
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
static void fr_nbo_from_uint16(uint8_t out[static sizeof(uint16_t)], uint16_t num)
Write out an unsigned 16bit integer in wire format (big endian)
Definition nbo.h:38
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
static void fr_nbo_from_uint32(uint8_t out[static sizeof(uint32_t)], uint32_t num)
Write out an unsigned 32bit integer in wire format (big endian)
Definition nbo.h:61
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:284
#define fr_assert(_expr)
Definition rad_assert.h:37
static bool done
Definition radclient.c:80
return count
Definition module.c:155
fr_aka_sim_id_type_t type
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
#define MSEC
Definition time.h:381
#define fr_time_delta_min()
Definition time.h:151
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
static int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
Definition time.h:506
#define fr_time_delta_wrap(_time)
Definition time.h:152
static int64_t fr_time_delta_to_sec(fr_time_delta_t delta)
Definition time.h:656
static fr_unix_time_t fr_unix_time_from_sec(int64_t sec)
Definition time.h:449
#define NSEC
Definition time.h:379
#define USEC
Definition time.h:380
#define fr_time_delta_max()
Definition time.h:150
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition pair.h:285
#define FR_PAIR_APPEND
Definition pair.h:218
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
static fr_slen_t parent
Definition pair.h:864
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_type_is_structural(_x)
Definition types.h:392
#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_LEAF
Definition types.h:317
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:5339
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:4873
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:668
static fr_slen_t data
Definition value.h:1366
static fr_sbuff_err_t char ** out
Definition value.h:1061
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:634
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:253