The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
23 RCSID("$Id: 2ae42f051d45500ccd7105538d69d3dacb3c6def $")
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 
41 static 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  */
53 static 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,
57  [FR_TYPE_IPV4_PREFIX] = 52,
58  [FR_TYPE_IPV6_ADDR] = 54,
59  [FR_TYPE_IPV6_PREFIX] = 54,
60  [FR_TYPE_TIME_DELTA] = 1002,
61 };
62 
63 static 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  */
109  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, type | CBOR_8_BYTE);
110  FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value, 8);
111 
112 done:
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 slen - fr_dbuff_used(&work_dbuff)
124 
125 /*
126  * Octets is length + data
127  */
128 static 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 
141 static 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_uint64;
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_int64;
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  */
283  case FR_TYPE_TIME_DELTA:
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  */
319  case FR_TYPE_IPV4_ADDR:
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_ip.addr.v4.s_addr, 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  */
345  case FR_TYPE_IPV6_ADDR:
346  if (vb->vb_ip.scope_id != 0) {
347  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 3));
348 
349  }
350 
351  slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
352  if (slen <= 0) return_slen;
353 
354  slen = cbor_encode_octets(&work_dbuff, (uint8_t const *) &vb->vb_ip.addr.v6.s6_addr, 16);
355  if (slen <= 0) return_slen;
356 
357  if (vb->vb_ip.scope_id == 0) break;
358 
359  slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, (uint8_t) 32);
360  if (slen <= 0) return_slen;
361 
362  slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.scope_id);
363  if (slen <= 0) return_slen;
364  break;
365 
366  /*
367  * RFC 9164, Section 3.3
368  *
369  * tag=IPv4 + array(prefix-length, address)
370  */
371  case FR_TYPE_IPV4_PREFIX:
372  slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
373  if (slen <= 0) return_slen;
374 
375  slen = cbor_encode_array(&work_dbuff, 2);
376  if (slen <= 0) return_slen;
377 
378  slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.prefix);
379  if (slen <= 0) return_slen;
380 
381  p = (uint8_t const *) &vb->vb_ip.addr.v4.s_addr;
382  end = p + 3;
383 
384  /*
385  * RFC 9164 Section 4.2 - Drop lower octets which are all zero.
386  *
387  * If this results in a zero-length string, so be it.
388  *
389  * Note also that "There is no relationship between the number of bytes omitted and the
390  * prefix length."
391  */
392  do {
393  if (*end != 0) break;
394 
395  end--;
396  } while (end != p);
397 
398  slen = cbor_encode_octets(&work_dbuff, p, (end - p) + (*end != 0));
399  if (slen <= 0) return_slen;
400  break;
401 
402  /*
403  * RFC 9164, Section 3.2
404  *
405  * tag=IPv6 + array(prefix-length, address)
406  */
407  case FR_TYPE_IPV6_PREFIX:
408  slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
409  if (slen <= 0) return_slen;
410 
411  slen = cbor_encode_array(&work_dbuff, 2);
412  if (slen <= 0) return_slen;
413 
414  slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.prefix);
415  if (slen <= 0) return_slen;
416 
417  p = (uint8_t const *) &vb->vb_ip.addr.v6.s6_addr;
418  end = p + 15;
419 
420  /*
421  * RFC 9164 Section 4.2 - Drop lower octets which are all zero.
422  *
423  * If this results in a zero-length string, so be it.
424  *
425  * Note also that "There is no relationship between the number of bytes omitted and the
426  * prefix length."
427  */
428  do {
429  if (*end != 0) break;
430 
431  end--;
432  } while (end != p);
433 
434  slen = cbor_encode_octets(&work_dbuff, p, (end - p) + (*end != 0));
435  if (slen <= 0) return_slen;
436 
437  break;
438 
439  case FR_TYPE_FLOAT32:
440  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | CBOR_4_BYTE));
441 
442  slen = cbor_encode_octets(&work_dbuff, (uint8_t const *) &vb->vb_float32, 4);
443  if (slen <= 0) return_slen;
444  break;
445 
446  case FR_TYPE_FLOAT64:
447  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | CBOR_8_BYTE));
448 
449  slen = cbor_encode_octets(&work_dbuff, (uint8_t const *) &vb->vb_float64, 8);
450  if (slen <= 0) return_slen;
451  break;
452 
453  case FR_TYPE_GROUP:
454  /*
455  * Zero-length array.
456  */
457  if (fr_value_box_list_num_elements(&vb->vb_group) == 0) {
458  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 0));
459  break;
460  }
461 
462  /*
463  * The value is array(children)
464  */
465  slen = cbor_encode_integer(&work_dbuff, CBOR_ARRAY,
466  fr_value_box_list_num_elements(&vb->vb_group));
467  if (slen <= 0) return_slen;
468 
469 
470  fr_value_box_list_foreach(&vb->vb_group, child) {
471  slen = fr_cbor_encode_value_box(&work_dbuff, child);
472  if (slen <= 0) return_slen;
473  }
474  break;
475 
476 
477  default:
478  fr_strerror_printf("Invalid data type %s for cbor encoding", fr_type_to_str(vb->type));
479  return -1;
480  }
481 
482  return fr_dbuff_set(dbuff, &work_dbuff);
483 }
484 
485 
486 static ssize_t cbor_decode_integer(uint64_t *out, uint8_t info, fr_dbuff_t *dbuff)
487 {
488  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
489 
490  if (info < 24) {
491  *out = info;
492  return 0;
493  }
494 
495  if (info == CBOR_1_BYTE) {
496  uint8_t value;
497 
498  FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
499  *out = value;
500  goto done;
501  }
502 
503  if (info == CBOR_2_BYTE) {
504  uint16_t value;
505 
506  FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
507  *out = value;
508  goto done;
509  }
510 
511  if (info == CBOR_4_BYTE) {
512  uint32_t value;
513 
514  FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
515  *out = value;
516  goto done;
517  }
518 
519  if (info == CBOR_8_BYTE) {
520  uint64_t value;
521 
522  FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
523  *out = value;
524  goto done;
525  }
526 
527  /*
528  * 28 and greater are invalid according to the RFCs.
529  */
530 
531 done:
532  return fr_dbuff_set(dbuff, &work_dbuff);
533 }
534 
535 static ssize_t cbor_decode_count(uint64_t *out, int expected, fr_dbuff_t *dbuff)
536 {
537  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
538  uint8_t major, info;
539  ssize_t slen;
540 
541  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
542 
543  info = major & 0x1f;
544  major >>= 5;
545 
546  if (major != expected) {
547  fr_strerror_printf("Expected cbor type '%s', got unexpected type %d ",
548  cbor_type_to_str[expected], major);
549  return -1;
550  }
551 
552  slen = cbor_decode_integer(out, info, &work_dbuff);
553  if (slen < 0) return_slen;
554 
555  return fr_dbuff_set(dbuff, &work_dbuff);
556 }
557 
558 typedef ssize_t (*cbor_decode_type_t)(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff);
559 
560 static ssize_t cbor_decode_octets_memcpy(uint8_t *dst, size_t dst_min, size_t dst_max, fr_dbuff_t *dbuff)
561 {
562  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
563  ssize_t slen;
564  uint64_t value = 0;
565 
566  slen = cbor_decode_count(&value, CBOR_OCTETS, &work_dbuff);
567  if (slen < 0) return_slen;
568 
569  if (value < dst_min) {
570  fr_strerror_printf("Invalid length for data - expected at least %zu got %" PRIu64, dst_min, value);
571  return -1;
572  }
573 
574  if (value > dst_max) {
575  fr_strerror_printf("Invalid length for data - expected no more than %zu got %" PRIu64, dst_max, value);
576  return -1;
577  }
578 
579  FR_DBUFF_OUT_MEMCPY_RETURN(dst, &work_dbuff, value);
580 
581  return fr_dbuff_set(dbuff, &work_dbuff);
582 }
583 
584 #if 0
585 static ssize_t *cbor_decode_octets_memdup(TALLOC_CTX *ctx, uint8_t **out, fr_dbuff_t *dbuff)
586 {
587  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
588  ssize_t slen;
589  uint64_t value;
590  uint8_t *ptr;
591 
592  slen = cbor_decode_count(&value, CBOR_OCTETS, &work_dbuff);
593  if (slen < 0) return_slen;
594 
595  if (value > (1 << 20)) {
596  fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
597  return -1;
598  }
599 
600  ptr = talloc_array(ctx, uint8_t, value);
601  if (!ptr) {
602  fr_strerror_const("Out of memory");
603  return -1;
604  }
605 
606  FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
607  *out = ptr;
608 
609  return fr_dbuff_set(dbuff, &work_dbuff);
610 }
611 #endif
612 
613 static ssize_t cbor_decode_ethernet(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
614 {
615  return cbor_decode_octets_memcpy(vb->vb_ether, sizeof(vb->vb_ether), sizeof(vb->vb_ether), dbuff);
616 }
617 
618 static ssize_t cbor_decode_ipv4_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
619 {
620  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
621  ssize_t slen;
622  uint8_t header;
623  size_t count = 0;
624  uint64_t value = 0;
625 
626  FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
627 
628  header = *fr_dbuff_current(&work_dbuff);
629  if ((header >> 5) == CBOR_ARRAY) {
630  count = header & 0x1f;
631 
632  if ((count != 2) && (count != 3)) {
633  fr_strerror_printf("Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
634  header);
635  return -1;
636  }
637 
638  fr_dbuff_advance(&work_dbuff, 1);
639  }
640 
641  vb->vb_ip.prefix = 32;
642 
643  /*
644  * Get the IP address.
645  */
646  slen = cbor_decode_octets_memcpy((uint8_t *) &vb->vb_ip.addr.v4.s_addr,
647  sizeof(vb->vb_ip.addr.v4.s_addr),
648  sizeof(vb->vb_ip.addr.v4.s_addr), &work_dbuff);
649  if (slen <= 0) return_slen;
650 
651  if (!count) return fr_dbuff_set(dbuff, &work_dbuff);
652 
653  slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
654  if (slen <= 0) return_slen;
655 
656  if (value > 32) {
657  fr_strerror_printf("Invalid IPv4 interface - expected prefix <= 32 got %" PRIu64, value);
658  return -fr_dbuff_used(&work_dbuff);
659  }
660 
661  vb->vb_ip.prefix = value;
662 
663  if (count == 2) return fr_dbuff_set(dbuff, &work_dbuff);
664 
665  /*
666  * Get the scope ID
667  */
668  slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
669  if (slen <= 0) return_slen;
670 
671  vb->vb_ip.scope_id = value;
672 
673  return fr_dbuff_set(dbuff, &work_dbuff);
674 }
675 
676 static ssize_t cbor_decode_ipv6_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
677 {
678  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
679  ssize_t slen;
680  uint8_t header;
681  size_t count = 0;
682  uint64_t value = 0;
683 
684  FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
685 
686  header = *fr_dbuff_current(&work_dbuff);
687  if ((header >> 5) == CBOR_ARRAY) {
688  count = header & 0x1f;
689 
690  if ((count != 2) && (count != 3)) {
691  fr_strerror_printf("Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
692  header);
693  return -1;
694  }
695 
696  fr_dbuff_advance(&work_dbuff, 1);
697  }
698 
699  vb->vb_ip.prefix = 128;
700 
701  /*
702  * Get the IP address.
703  */
704  slen = cbor_decode_octets_memcpy((uint8_t *) &vb->vb_ip.addr.v6.s6_addr,
705  sizeof(vb->vb_ip.addr.v6.s6_addr),
706  sizeof(vb->vb_ip.addr.v6.s6_addr), dbuff);
707 
708  if (slen <= 0) return_slen;
709 
710  if (!count) return fr_dbuff_set(dbuff, &work_dbuff);
711 
712  slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
713  if (slen <= 0) return_slen;
714 
715  if (value > 128) {
716  fr_strerror_printf("Invalid IPv6 interface - expected prefix <= 128 got %" PRIu64, value);
717  return -fr_dbuff_used(&work_dbuff);
718  }
719 
720  vb->vb_ip.prefix = value;
721 
722  if (count == 2) return fr_dbuff_set(dbuff, &work_dbuff);
723 
724  /*
725  * Get the scope ID
726  */
727  slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
728  if (slen <= 0) return_slen;
729 
730  vb->vb_ip.scope_id = value;
731 
732  return fr_dbuff_set(dbuff, &work_dbuff);
733 }
734 
735 static ssize_t cbor_decode_ipv4_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
736 {
737  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
738  ssize_t slen;
739  uint8_t header;
740  uint64_t value = 0;
741  uint8_t buffer[sizeof(vb->vb_ip.addr.v4.s_addr)];
742 
743  FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
744 
745  if (header != ((CBOR_ARRAY << 5) | 2)) {
746  fr_strerror_printf("Invalid IPv4 prefix - expected array of 2 elements, got %02x",
747  header);
748  return -1;
749  }
750 
751  slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
752  if (slen <= 0) return_slen;
753 
754  if (value > 32) {
755  fr_strerror_printf("Invalid IPv4 prefix - expected prefix < 32, got %" PRIu64, value);
756  return -1;
757  }
758 
759  /*
760  * RFC 9164 Section 4.3 - Trailing bytes of zero are omitted, so we
761  * first copy the data to a fixed-sized buffer which was
762  * zeroed out, and then (@todo) also check that unused bits in
763  * the last byte are all zero.
764  */
765  memset(buffer, 0, sizeof(buffer));
766 
767  slen = cbor_decode_octets_memcpy(buffer, 0, sizeof(buffer), &work_dbuff);
768  if (slen <= 0) return_slen;
769 
770  memcpy((uint8_t *) &vb->vb_ip.addr.v4.s_addr, buffer, sizeof(vb->vb_ip.addr.v4.s_addr));
771  vb->vb_ip.prefix = value;
772 
773  return fr_dbuff_set(dbuff, &work_dbuff);
774 }
775 
776 static ssize_t cbor_decode_ipv6_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
777 {
778  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
779  ssize_t slen;
780  uint8_t header;
781  uint64_t value = 0;
782  uint8_t buffer[sizeof(vb->vb_ip.addr.v6.s6_addr)];
783 
784  FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
785 
786  if (header != ((CBOR_ARRAY << 5) | 2)) {
787  fr_strerror_printf("Invalid IPv6 prefix - expected array of 2 elements, got %02x",
788  header);
789  return -1;
790  }
791 
792  slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
793  if (slen <= 0) return_slen;
794 
795  if (value > 128) {
796  fr_strerror_printf("Invalid IPv6 prefix - expected prefix < 128, got %" PRIu64, value);
797  return -1;
798  }
799 
800  /*
801  * RFC 9164 Section 4.3 - Trailing bytes of zero are omitted, so we
802  * first copy the data to a fixed-sized buffer which was
803  * zeroed out, and then (@todo) also check that unused bits in
804  * the last byte are all zero.
805  */
806  memset(buffer, 0, sizeof(buffer));
807 
808  slen = cbor_decode_octets_memcpy(buffer, 0, sizeof(buffer), &work_dbuff);
809  if (slen <= 0) return_slen;
810 
811  memcpy((uint8_t *) &vb->vb_ip.addr.v6.s6_addr, buffer, sizeof(vb->vb_ip.addr.v6.s6_addr));
812  vb->vb_ip.prefix = value;
813 
814  return fr_dbuff_set(dbuff, &work_dbuff);
815 }
816 
818 {
819  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
820  ssize_t slen;
821  uint8_t major, info;
822  uint64_t value = 0;
823  int64_t neg;
824 
825  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
826 
827  info = major & 0x1f;
828  major >>= 5;
829 
830  switch (major) {
831  case CBOR_INTEGER:
832  slen = cbor_decode_integer(&value, info, &work_dbuff);
833  if (slen < 0) return_slen;
834 
835  if (value >= ((uint64_t) 1) << 63) { /* equal! */
836  invalid:
837  fr_strerror_printf("cbor value is too large for output data type %s",
839  return -1;
840  }
841 
842  *out = value;
843  break;
844 
845  case CBOR_NEGATIVE:
846  slen = cbor_decode_integer(&value, info, &work_dbuff);
847  if (slen < 0) return_slen;
848 
849  if (value > ((uint64_t) 1) << 63) goto invalid; /* greater than! */
850 
851  /*
852  * Convert 0..(2^63-1) into -0..-(2^63-1)
853  * then conver to -1..-(2^63)
854  */
855  neg = -value;
856  neg--;
857 
858  *out = neg;
859  break;
860 
861  default:
862  fr_strerror_printf("cbor data contains invalid content %d for expected data type %s",
863  major, fr_type_to_str(type));
864  return -1;
865  }
866 
867  return fr_dbuff_set(dbuff, &work_dbuff);
868 
869 }
870 
871 static ssize_t cbor_decode_date(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
872 {
873  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
874  ssize_t slen;
875  int64_t neg;
876 
877  slen = cbor_decode_int64(&neg, dbuff, FR_TYPE_DATE);
878  if (slen <= 0) return_slen;
879 
880  vb->vb_date = fr_unix_time_from_sec(neg);
881 
882  return fr_dbuff_set(dbuff, &work_dbuff);
883 }
884 
885 /*
886  * Tag 1002, followed by map of at least 2 elements
887  * key 1: seconds
888  * key -9: nanoseconds
889  */
890 static ssize_t cbor_decode_time_delta(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
891 {
892  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
893  uint64_t count;
894  ssize_t slen;
895  int64_t key, seconds, fraction, scale;
896 
897  slen = cbor_decode_count(&count, CBOR_MAP, &work_dbuff);
898  if (slen < 0) return_slen;
899 
900  if (!count || (count > 2)) {
901  fr_strerror_printf("Unexpected count %" PRIu64" for time_delta, expected map of 1-2 elements", count);
902  return -1;
903  }
904 
905  key = seconds = fraction = 0;
906 
907  /*
908  * Expect key 1:seconds
909  */
910  slen = cbor_decode_int64(&key, &work_dbuff, FR_TYPE_TIME_DELTA);
911  if (slen < 0) return_slen;
912 
913  if (key != 1) {
914  fr_strerror_printf("Unexpected key %" PRIi64 " for time_delta, expected key 1", key);
915  return -1;
916  }
917 
918  slen = cbor_decode_int64(&seconds, &work_dbuff, FR_TYPE_TIME_DELTA);
919  if (slen < 0) return_slen;
920 
921  if (count > 1) {
922  slen = cbor_decode_int64(&key, &work_dbuff, FR_TYPE_TIME_DELTA);
923  if (slen < 0) return_slen;
924 
925  switch (key) {
926  case -3:
927  scale = MSEC;
928  break;
929 
930  case -6:
931  scale = USEC;
932  break;
933 
934  case -9:
935  scale = NSEC;
936  break;
937 
938  default:
939  fr_strerror_printf("Unsupported time_delta key %" PRIi64, key);
940  return -fr_dbuff_used(&work_dbuff); /* point to actual key? */
941 
942  }
943 
944  slen = cbor_decode_int64(&fraction, &work_dbuff, FR_TYPE_TIME_DELTA);
945  if (slen < 0) return_slen;
946 
947  } else {
948  scale = NSEC;
949  fraction = 0;
950  }
951 
952  if (seconds > (INT64_MAX / scale)) {
953  vb->vb_time_delta = fr_time_delta_max();
954 
955  } else if (seconds < (INT64_MIN / scale)) {
956  vb->vb_time_delta = fr_time_delta_min();
957 
958  } else {
959  /*
960  * We don't worry too much about positive seconds and negative nanoseconds.
961  *
962  * We also don't worry too much about overflow / underflow here.
963  */
964  fraction += seconds * scale;
965  vb->vb_time_delta = fr_time_delta_wrap(fraction);
966  }
967 
968  return fr_dbuff_set(dbuff, &work_dbuff);
969 }
970 
971 
974 
977 
980 
983 };
984 
985 /*
986  * @todo - fr_cbor_encode_pair_list(). And then if we have da->flags.array, we encode the _value_ as an
987  * array of indeterminate length. This is a little bit of a special case, but not terrible.
988  */
990  fr_type_t type, fr_dict_attr_t const *enumv, bool tainted)
991 {
992  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
993  bool indefinite;
994  uint8_t major, info;
995  ssize_t slen;
996  int64_t neg;
997  uint64_t value;
998  uint8_t *ptr;
999 
1000  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1001 
1002  if (type == FR_TYPE_NULL) {
1003  type = cbor_guess_type(&work_dbuff, false);
1004  if (type == FR_TYPE_NULL) {
1005  fr_strerror_printf("Invalid cbor - unable to determine data type");
1006  return 0;
1007  }
1008  }
1009 
1010  fr_value_box_init(vb, type, enumv, tainted);
1011 
1012  info = major & 0x1f;
1013  major >>= 5;
1014 
1015  /*
1016  * Invalid combinations.
1017  */
1018  if (((info >= 28) && (info <= 30)) ||
1019  ((info == 31) && ((major == 0) || (major == 1) || (major == 6)))) {
1020  fr_strerror_const("Invalid cbor data - input is not 'well formed'");
1021  return 0;
1022  }
1023 
1024  switch (major) {
1025  case CBOR_STRING:
1026  if (type != FR_TYPE_STRING) {
1027  mismatch:
1028  fr_strerror_printf("cbor data contains invalid content %d for expected data type %s",
1029  major, fr_type_to_str(type));
1030  return -1;
1031  }
1032 
1033  fr_assert(info != 31);
1034 
1035  /*
1036  * @todo - undefinite length strings. Which are really "chunked" strings.
1037  */
1038  slen = cbor_decode_integer(&value, info, &work_dbuff);
1039  if (slen < 0) return_slen;
1040 
1041  /*
1042  * A little bit of sanity check.
1043  */
1044  if (value > (1 << 20)) {
1045  fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
1046  return -1;
1047  }
1048 
1049  ptr = talloc_array(ctx, uint8_t, value + 1);
1050  if (!ptr) {
1051  fr_strerror_const("Out of memory");
1052  return -1;
1053  }
1054  talloc_set_type(ptr, char);
1055  if (value) FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
1056  ptr[value] = '\0';
1057 
1058  fr_value_box_strdup_shallow(vb, NULL, (char const *) ptr, tainted);
1059 
1060  break;
1061 
1062  case CBOR_OCTETS:
1063  if (type != FR_TYPE_OCTETS) goto mismatch;
1064 
1065  fr_assert(info != 31);
1066 
1067  /*
1068  * @todo - undefinite length octet strings. Which are really "chunked" octet strings.
1069  */
1070  slen = cbor_decode_integer(&value, info, &work_dbuff);
1071  if (slen < 0) return_slen;
1072 
1073  /*
1074  * A little bit of sanity check.
1075  */
1076  if (value > (1 << 20)) {
1077  fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
1078  return -1;
1079  }
1080 
1081  ptr = talloc_array(ctx, uint8_t, value);
1082  if (!ptr) {
1083  fr_strerror_const("Out of memory");
1084  return -1;
1085  }
1086 
1087  fr_value_box_memdup_shallow(vb, NULL, (uint8_t const *) ptr, value, false); /* tainted? */
1088 
1089  if (value) FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
1090  break;
1091 
1092  case CBOR_INTEGER:
1093  slen = cbor_decode_integer(&value, info, &work_dbuff);
1094  if (slen < 0) return_slen;
1095 
1096  switch (type) {
1097  case FR_TYPE_BOOL:
1098  if (value > 1) goto invalid_bool;
1099  vb->vb_bool = value;
1100  break;
1101 
1102  case FR_TYPE_UINT8:
1103  if (value > UINT8_MAX) {
1104  invalid:
1105  fr_strerror_printf("cbor value is too large for output data type %s",
1106  fr_type_to_str(type));
1107  return -1;
1108  }
1109  vb->vb_uint8 = value;
1110  break;
1111 
1112  case FR_TYPE_UINT16:
1113  if (value > UINT16_MAX) goto invalid;
1114  vb->vb_uint16 = value;
1115  break;
1116 
1117  case FR_TYPE_UINT32:
1118  if (value > UINT32_MAX) goto invalid;
1119  vb->vb_uint32 = value;
1120  break;
1121 
1122  case FR_TYPE_UINT64:
1123  vb->vb_uint64 = value;
1124  break;
1125 
1126  case FR_TYPE_INT8:
1127  if (value > INT8_MAX) goto invalid;
1128  vb->vb_int8 = value;
1129  break;
1130 
1131  case FR_TYPE_INT16:
1132  if (value > INT16_MAX) goto invalid;
1133  vb->vb_int16 = value;
1134  break;
1135 
1136  case FR_TYPE_INT32:
1137  if (value > INT32_MAX) goto invalid;
1138  vb->vb_int32 = value;
1139  break;
1140 
1141  case FR_TYPE_INT64:
1142  if (value > INT64_MAX) goto invalid;
1143  vb->vb_int64 = value;
1144  break;
1145 
1146  default:
1147  integer_type_mismatch:
1148  fr_strerror_printf("Unexpected cbor type 'integer' when decoding data type %s",
1149  fr_type_to_str(type));
1150  return -1;
1151  }
1152  break;
1153 
1154  case CBOR_NEGATIVE:
1155  slen = cbor_decode_integer(&value, info, &work_dbuff);
1156  if (slen < 0) return_slen;
1157 
1158  /*
1159  * Signed numbers only go down to -2^63
1160  */
1161  if (value > ((uint64_t) 1) << 63) goto invalid;
1162 
1163  /*
1164  * Convert 0..(2^63-1) into -0..-(2^63-1)
1165  * then conver to -1..-(2^63)
1166  */
1167  neg = -value;
1168  neg--;
1169 
1170  switch (type) {
1171  case FR_TYPE_INT8:
1172  if (neg < INT8_MIN) goto invalid;
1173  vb->vb_int8 = neg;
1174  break;
1175 
1176  case FR_TYPE_INT16:
1177  if (neg < INT16_MIN) goto invalid;
1178  vb->vb_int16 = neg;
1179  break;
1180 
1181  case FR_TYPE_INT32:
1182  if (neg < INT32_MIN) goto invalid;
1183  vb->vb_int32 = neg;
1184  break;
1185 
1186  case FR_TYPE_INT64:
1187  vb->vb_int64 = neg;
1188  break;
1189 
1190  default:
1191  goto integer_type_mismatch;
1192  }
1193  break;
1194 
1195  case CBOR_FLOAT:
1196  /*
1197  * Simple values. See RFC 8489 Section 3.3.
1198  *
1199  * 20 - false
1200  * 21 - true
1201  * 22 - NULL
1202  */
1203  if (info < 24) {
1204  switch (type) {
1205  case FR_TYPE_BOOL:
1206  if (info == 20) {
1207  vb->vb_bool = false;
1208  break;
1209  }
1210 
1211  if (info == 21) {
1212  vb->vb_bool = true;
1213  break;
1214  }
1215 
1216  invalid_bool:
1217  fr_strerror_printf("Invalid cbor - boolean is not encoded as 'true' or 'false'");
1218  return -fr_dbuff_used(&work_dbuff);
1219 
1220  case FR_TYPE_OCTETS:
1221  case FR_TYPE_STRING:
1222  case FR_TYPE_TLV:
1223  case FR_TYPE_VENDOR:
1224  case FR_TYPE_GROUP:
1225  case FR_TYPE_STRUCT:
1226  /*
1227  * Be a little forgiving. 22 is NULL, so we treat that as "nothing".
1228  *
1229  * i.e. empty string, empty set, etc.
1230  */
1231  if (info == 22) break;
1232 
1233  FALL_THROUGH;
1234 
1235  default:
1236  fr_strerror_printf("Invalid cbor - unexpected 'simple value' %u", info);
1237  return -fr_dbuff_used(&work_dbuff);
1238  }
1239  break;
1240  }
1241 
1242  /*
1243  * Or as one-byte integers.
1244  */
1245  if (info == CBOR_1_BYTE) {
1246  uint8_t data;
1247 
1248  FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1249 
1250  switch (type) {
1251  case FR_TYPE_FLOAT32:
1252  vb->vb_float32 = data;
1253  break;
1254 
1255  case FR_TYPE_FLOAT64:
1256  vb->vb_float64 = data;
1257  break;
1258 
1259  default:
1260  float_type_mismatch:
1261  fr_strerror_printf("Unexpected cbor type 'float' when decoding data type %s",
1262  fr_type_to_str(type));
1263  return -1;
1264  }
1265 
1266  break;
1267  }
1268 
1269  /*
1270  * We don't support float16
1271  */
1272 
1273  if (info == CBOR_4_BYTE) {
1274  float data;
1275 
1276  FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1277 
1278  switch (type) {
1279  case FR_TYPE_FLOAT32:
1280  vb->vb_float32 = data;
1281  break;
1282 
1283  case FR_TYPE_FLOAT64:
1284  vb->vb_float64 = (double) data;
1285  break;
1286 
1287  default:
1288  goto float_type_mismatch;
1289  }
1290 
1291  break;
1292  }
1293 
1294  if (info == CBOR_8_BYTE) {
1295  double data;
1296 
1297  FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1298 
1299  switch (type) {
1300  case FR_TYPE_FLOAT32:
1301  vb->vb_float32 = data; /* maybe loses precision? */
1302  break;
1303 
1304  case FR_TYPE_FLOAT64:
1305  vb->vb_float64 = data;
1306  break;
1307 
1308  default:
1309  goto float_type_mismatch;
1310  }
1311 
1312  break;
1313  }
1314 
1315  /*
1316  * 24 is FLOAT16, which we don't support.
1317  * 31 is BREAK, which the caller should have checked for.
1318  */
1319  goto float_type_mismatch;
1320 
1321  case CBOR_TAG:
1322  /*
1323  * We only support a limited number of tags.
1324  */
1325  slen = cbor_decode_integer(&value, info, &work_dbuff);
1326  if (slen < 0) return_slen;
1327 
1329 
1330  /*
1331  * No tag defined for this data type, that's on us.
1332  */
1333  if (!cbor_type_to_tag[type]) {
1334  fr_strerror_printf("Unknown cbor tag %" PRIu64 " for expected data type %s",
1336  return -fr_dbuff_used(&work_dbuff);
1337  }
1338 
1339  /*
1340  * Wrong tag for this data type, that's on them.
1341  */
1342  if (cbor_type_to_tag[type] != value) {
1343  fr_strerror_printf("Invalid cbor tag %" PRIu64 " for expected data type %s",
1345  return -fr_dbuff_used(&work_dbuff);
1346  }
1347 
1348  fr_value_box_init(vb, type, enumv, tainted);
1349 
1350  slen = cbor_decode_type[type](ctx, vb, &work_dbuff);
1351  if (slen < 0) return_slen;
1352  break;
1353 
1354  case CBOR_ARRAY:
1355  if (type != FR_TYPE_GROUP) goto invalid_type;
1356 
1357  /*
1358  * Loop until done.
1359  */
1360  if (info == 31) {
1361  value = ~0;
1362  indefinite = true;
1363 
1364  } else {
1365  slen = cbor_decode_integer(&value, info, &work_dbuff);
1366  if (slen < 0) return_slen;
1367 
1368  indefinite = false;
1369  }
1370 
1371 #ifdef STATIC_ANALYZER
1372  if (value > fr_dbuff_remaining(&work_dbuff)) return -1;
1373 #endif
1374 
1375  /*
1376  * Loop until we decode everything. For simplicity, we handle indefinite and definite
1377  * length arrays in the same loop.
1378  */
1379  for (/* nothing */; value > 0; value--) {
1380  uint8_t header;
1381  fr_value_box_t *child;
1382 
1383  /*
1384  * Require at least one byte in the buffer.
1385  */
1386  FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
1387 
1388  /*
1389  * Peek ahead for a break.
1390  */
1391  header = *fr_dbuff_current(&work_dbuff);
1392  if (header == 0xff) {
1393  if (!indefinite) {
1394  fr_strerror_const("Unexpected 'break' found in cbor data");
1395  return -fr_dbuff_used(&work_dbuff);
1396  }
1397 
1398  /*
1399  * Done!
1400  */
1401  fr_dbuff_advance(&work_dbuff, 1);
1402  break;
1403  }
1404 
1405  child = fr_value_box_alloc(ctx, FR_TYPE_NULL, NULL);
1406  if (!child) {
1407  fr_strerror_const("Out of memory");
1408  return -fr_dbuff_used(&work_dbuff);
1409  }
1410 
1411  /*
1412  * We have to decode at least one value.
1413  */
1414  slen = fr_cbor_decode_value_box(child, child, &work_dbuff, FR_TYPE_NULL, NULL, tainted);
1415  if (slen <= 0) return_slen;
1416 
1417  fr_value_box_list_insert_tail(&vb->vb_group, child);
1418  }
1419  break;
1420 
1421  /*
1422  * These are not value-box types.
1423  */
1424  case CBOR_MAP:
1425  invalid_type:
1426  fr_strerror_printf("Invalid data type %s for cbor to value-box", fr_type_to_str(type));
1427  return -1;
1428  }
1429 
1430  return fr_dbuff_set(dbuff, &work_dbuff);
1431 }
1432 
1433 /** Encode a pair
1434  *
1435  */
1437 {
1438  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1439  ssize_t slen;
1440  fr_dict_attr_t const *parent;
1441  size_t count;
1442 
1443  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_MAP << 5) | 1)); /* map of 1 item */
1444 
1445  /*
1446  * Key is the attribute number.
1447  */
1448  slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vp->da->attr);
1449  if (slen <= 0) return_slen;
1450 
1451  /*
1452  * Value is the actual value of the leaf, or the array of children.
1453  */
1454  switch (vp->vp_type) {
1455  case FR_TYPE_LEAF:
1456  slen = fr_cbor_encode_value_box(&work_dbuff, &vp->data);
1457  if (slen <= 0) return_slen;
1458  break;
1459 
1460  /*
1461  * Groups reparent to the ref.
1462  */
1463  case FR_TYPE_GROUP:
1465  fr_assert(parent != NULL);
1466  goto encode_children;
1467 
1468  /*
1469  * The only difference between TLV and VSA is that the children of VSA are all VENDORs.
1470  */
1471  case FR_TYPE_VENDOR:
1472  case FR_TYPE_VSA:
1473  case FR_TYPE_TLV:
1474  parent = vp->da;
1475 
1476  /*
1477  * The value is array(children)
1478  */
1479 encode_children:
1480  if (fr_pair_list_num_elements(&vp->vp_group) == 0) {
1481  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | 22)); /* NULL */
1482  break;
1483  }
1484 
1485  /*
1486  * The groups, etc. may contain internal attributes. We don't yet deal with those.
1487  */
1488  count = 0;
1489  fr_pair_list_foreach(&vp->vp_group, child) {
1490  if (child->da->parent != parent) continue;
1491  count++;
1492  }
1493 
1494  slen = cbor_encode_integer(&work_dbuff, CBOR_ARRAY, count);
1495  if (slen <= 0) return_slen;
1496 
1497  fr_pair_list_foreach(&vp->vp_group, child) {
1498  /*
1499  * We don't allow changing dictionaries here.
1500  */
1501  if (child->da->parent != parent) continue;
1502 
1503  slen = fr_cbor_encode_pair(&work_dbuff, child);
1504  if (slen <= 0) return_slen;
1505  }
1506  break;
1507 
1508  /*
1509  * @todo - struct, except if we hit the end of the struct, check if the next child is the child
1510  * of the key? That makes it all more annoying :(
1511  */
1512 
1513  default:
1514  fr_strerror_printf("Invalid data type %s for cbor encoding", fr_type_to_str(vp->vp_type));
1515  return -1;
1516  }
1517 
1518  return fr_dbuff_set(dbuff, &work_dbuff);
1519 }
1520 
1521 /** Guess the data type of the CBOR data.
1522  *
1523  * We've parsed the attribute number, and found that we don't have a dictionary entry for it. But rather
1524  * than create an attribute of type octets, we try to guess the data type.
1525  */
1526 static fr_type_t cbor_guess_type(fr_dbuff_t *dbuff, bool pair)
1527 {
1528  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1529  ssize_t slen;
1530  uint8_t major, info;
1531  uint64_t value;
1532 
1533  /*
1534  * get the next byte, which is a CBOR header.
1535  */
1536  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1537 
1538  info = major & 0x1f;
1539  major >>= 5;
1540 
1541  switch (major) {
1542  case CBOR_INTEGER:
1543  return FR_TYPE_UINT64;
1544 
1545  case CBOR_NEGATIVE:
1546  return FR_TYPE_UINT64;
1547 
1548  case CBOR_STRING:
1549  return FR_TYPE_STRING;
1550 
1551  case CBOR_OCTETS:
1552  return FR_TYPE_OCTETS;
1553 
1554  case CBOR_ARRAY:
1555  if (!pair) return FR_TYPE_GROUP;
1556  break;
1557 
1558  case CBOR_MAP:
1559  return FR_TYPE_TLV;
1560 
1561  /*
1562  * Look at the tag to determine what it is
1563  */
1564  case CBOR_TAG:
1565  slen = cbor_decode_integer(&value, info, &work_dbuff);
1566  if (slen < 0) break;
1567 
1568  switch (value) {
1569  case 1:
1570  case 1001:
1571  return FR_TYPE_DATE;
1572 
1573  case 1002:
1574  return FR_TYPE_TIME_DELTA;
1575 
1576  case 48:
1577  return FR_TYPE_ETHERNET;
1578 
1579  case 52:
1580  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1581 
1582  major >>= 5;
1583 
1584  if (major == CBOR_ARRAY) {
1585  return FR_TYPE_IPV4_PREFIX;
1586  }
1587  return FR_TYPE_IPV4_ADDR;
1588 
1589  case 54:
1590  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1591 
1592  major >>= 5;
1593 
1594  if (major == CBOR_ARRAY) {
1595  return FR_TYPE_IPV6_PREFIX;
1596  }
1597  return FR_TYPE_IPV6_ADDR;
1598 
1599  default:
1600  break;
1601  }
1602 
1603  break;
1604 
1605  case CBOR_FLOAT:
1606  /*
1607  * In-place values are special. false / true / NULL
1608  */
1609  if (info < 24) {
1610  if ((info == 20) || (info == 21)) return FR_TYPE_BOOL;
1611 
1612  return FR_TYPE_NULL;
1613  }
1614 
1615  return FR_TYPE_FLOAT64;
1616  }
1617 
1618 
1619  /*
1620  * No idea. :(
1621  *
1622  * @todo - also check the cbor data, and return the length of cbor data which needs to be
1623  * converted to data type 'octets'. This work involves mostly parsing the cbor data, which isn't
1624  * trivial.
1625  */
1626  return FR_TYPE_NULL;
1627 }
1628 
1630  fr_dict_attr_t const *parent, bool tainted)
1631 {
1632  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1633  uint8_t header, major, info;
1634  bool indefinite;
1635  ssize_t slen;
1636  fr_pair_t *vp;
1637  uint64_t value = 0;
1638  fr_dict_attr_t const *da;
1639 
1640  FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
1641 
1642  /*
1643  * We require a 2-element array(attribute number, value)
1644  */
1645  if (header != (((CBOR_MAP) << 5) | 1)) {
1646  fr_strerror_printf("Invalid cbor header - expected map of 1 elements, got %02x", header);
1647  return -1;
1648  }
1649 
1650  /*
1651  * This should be a CBOR_INTEGER.
1652  */
1653  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1654 
1655  info = major & 0x1f;
1656  major >>= 5;
1657 
1658  if (major != CBOR_INTEGER) {
1659  fr_strerror_printf("Invalid cbor - expected 'integer', got major type %d",
1660  major);
1661  return -1;
1662  }
1663 
1664  slen = cbor_decode_integer(&value, info, &work_dbuff);
1665  if (slen < 0) {
1666  return_slen;
1667  }
1668 
1670  if (!da) {
1671  fr_type_t type;
1672 
1673  type = cbor_guess_type(&work_dbuff, true);
1674  if (type == FR_TYPE_NULL) {
1675  fr_strerror_printf("Invalid cbor - unable to determine data type");
1676  return -fr_dbuff_used(&work_dbuff);
1677  }
1678 
1679  /*
1680  * @todo - the value here isn't a cbor octets type, but is instead cbor data. Since cbor
1681  * is typed, we _could_ perhaps instead discover the type from the cbor data, and then
1682  * use that instead. This would involve creating a function which maps cbor types to our
1683  * data types.
1684  */
1686  if (!da) goto oom;
1687  }
1688 
1689  vp = fr_pair_afrom_da(ctx, da);
1690  if (!vp) {
1691  oom:
1692  fr_strerror_const("Out of memory");
1693  return -fr_dbuff_used(&work_dbuff);
1694  }
1695 
1696  /*
1697  * Leaf values are easy.
1698  */
1699  if (fr_type_is_leaf(da->type)) {
1700  slen = fr_cbor_decode_value_box(vp, &vp->data, &work_dbuff, da->type, da, tainted);
1701  if (slen <= 0) {
1702  talloc_free(vp);
1703  return_slen;
1704  }
1705 
1706  goto done;
1707  }
1708 
1709  switch (da->type) {
1710  /*
1711  * All of these are essentially the same.
1712  */
1713  case FR_TYPE_VENDOR:
1714  case FR_TYPE_VSA:
1715  case FR_TYPE_TLV:
1716  parent = vp->da;
1717  break;
1718 
1719  /*
1720  * Groups reparent to the ref.
1721  */
1722  case FR_TYPE_GROUP:
1724  fr_assert(parent != NULL);
1725  break;
1726 
1727  default:
1728  talloc_free(vp);
1729  fr_strerror_printf("Invalid data type %s for child %s of %s",
1730  fr_type_to_str(da->type), vp->da->name, parent->name);
1731  return -1;
1732  }
1733 
1734  /*
1735  * This should be a CBOR_ARRAY.
1736  */
1737  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1738 
1739  info = major & 0x1f;
1740  major >>= 5;
1741 
1742  if (major != CBOR_ARRAY) {
1743  /*
1744  * Allow NULL as a synonym for "no children".
1745  */
1746  if ((major == CBOR_FLOAT) && (info == 22)) goto done;
1747 
1748  talloc_free(vp);
1749  fr_strerror_printf("Invalid cbor - expected 'array', got major type %d",
1750  major);
1751  return -1;
1752  }
1753 
1754  if (info == 31) {
1755  value = ~0;
1756  indefinite = true;
1757 
1758  } else {
1759  slen = cbor_decode_integer(&value, info, &work_dbuff);
1760  if (slen < 0) {
1761  talloc_free(vp);
1762  return_slen;
1763  }
1764 
1765  indefinite = false;
1766  }
1767 
1768 #ifdef STATIC_ANALYZER
1769  if (value > fr_dbuff_remaining(&work_dbuff)) return -1;
1770 #endif
1771 
1772  /*
1773  * Loop until we decode everything. For simplicity, we handle indefinite and definite
1774  * length arrays in the same loop.
1775  */
1776  for (/* nothing */; value > 0; value--) {
1777  /*
1778  * Require at least one byte in the buffer.
1779  */
1780  if (fr_dbuff_extend_lowat(NULL, &work_dbuff, 1) == 0) {
1781  talloc_free(vp);
1782  return -fr_dbuff_used(&work_dbuff);
1783  }
1784 
1785  /*
1786  * Peek ahead for a break.
1787  */
1788  header = *fr_dbuff_current(&work_dbuff);
1789  if (header == 0xff) {
1790  if (!indefinite) {
1791  talloc_free(vp);
1792  fr_strerror_const("Unexpected 'break' found in cbor data");
1793  return -fr_dbuff_used(&work_dbuff);
1794  }
1795 
1796  /*
1797  * Done!
1798  */
1799  fr_dbuff_advance(&work_dbuff, 1);
1800  break;
1801  }
1802 
1803  slen = fr_cbor_decode_pair(vp, &vp->vp_group, &work_dbuff, parent, tainted);
1804  if (slen <= 0) {
1805  talloc_free(vp);
1806  return_slen;
1807  }
1808  }
1809 
1810 done:
1811  PAIR_VERIFY(vp);
1812 
1813  fr_pair_append(out, vp);
1814  return fr_dbuff_set(dbuff, &work_dbuff);
1815 }
1816 
1817 /*
1818  * @todo - cbor_print
1819  * [] for array
1820  * [_...] for indefinite array
1821  * {a:b} for map
1822  * digits for integer
1823  * 'string' for string
1824  * h'HHHH' for octets
1825  */
static int const char char buffer[256]
Definition: acutest.h:574
#define RCSID(id)
Definition: build.h:481
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
#define UNUSED
Definition: build.h:313
static int invalid_type(fr_type_t type)
Definition: calc.c:698
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:618
static ssize_t cbor_decode_int64(int64_t *out, fr_dbuff_t *dbuff, fr_type_t type)
Definition: cbor.c:817
#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:676
#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:560
#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:1436
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:871
#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:972
static ssize_t cbor_decode_time_delta(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition: cbor.c:890
static ssize_t cbor_decode_ipv4_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition: cbor.c:735
#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:1526
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:486
static ssize_t cbor_decode_ethernet(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition: cbor.c:613
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:989
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:776
#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:1629
#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 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:558
static ssize_t cbor_decode_count(uint64_t *out, int expected, fr_dbuff_t *dbuff)
Definition: cbor.c:535
#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:1072
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition: dbuff.h:767
#define FR_DBUFF_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:673
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition: dbuff.h:911
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
Definition: dbuff.h:660
#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:743
#define FR_DBUFF_OUT_MEMCPY_RETURN(_out, _dbuff_or_marker, _outlen)
Copy outlen bytes from the dbuff returning if there's insufficient data in the dbuff.
Definition: dbuff.h:1752
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
Definition: dbuff.h:1382
#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff returning if there is insufficient space.
Definition: dbuff.h:1585
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition: dbuff.h:222
#define FR_DBUFF_OUT_RETURN(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type returning if there is insufficient data.
Definition: dbuff.h:1818
#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker returning if there's insufficient space.
Definition: dbuff.h:1472
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:562
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:3328
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:184
Test enumeration values.
Definition: dict_test.h:92
if(rcode > 0)
Definition: fd_read.h:9
talloc_free(reap)
unsigned short uint16_t
Definition: merged_model.c:31
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
Definition: merged_model.c:113
@ FR_TYPE_FLOAT32
Single precision floating point.
Definition: merged_model.c:108
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
Definition: merged_model.c:86
@ FR_TYPE_INT8
8 Bit signed integer.
Definition: merged_model.c:103
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
Definition: merged_model.c:93
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
Definition: merged_model.c:89
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_MAX
Number of defined data types.
Definition: merged_model.c:130
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
Definition: merged_model.c:81
@ FR_TYPE_UINT16
16 Bit unsigned integer.
Definition: merged_model.c:98
@ FR_TYPE_INT64
64 Bit signed integer.
Definition: merged_model.c:106
@ FR_TYPE_INT16
16 Bit signed integer.
Definition: merged_model.c:104
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
Definition: merged_model.c:111
@ FR_TYPE_UINT8
8 Bit unsigned integer.
Definition: merged_model.c:97
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
Definition: merged_model.c:119
@ FR_TYPE_INT32
32 Bit signed integer.
Definition: merged_model.c:105
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
Definition: merged_model.c:122
@ FR_TYPE_UINT64
64 Bit unsigned integer.
Definition: merged_model.c:100
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
Definition: merged_model.c:88
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
Definition: merged_model.c:87
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
Definition: merged_model.c:121
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
@ FR_TYPE_FLOAT64
Double precision floating point.
Definition: merged_model.c:109
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
#define UINT8_MAX
Definition: merged_model.c:32
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:283
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition: pair.c:1345
static bool done
Definition: radclient.c:80
return count
Definition: module.c:163
fr_assert(0)
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:647
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 PAIR_VERIFY(_x)
Definition: pair.h:191
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition: pair.h:261
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
Definition: pair_inline.c:151
static fr_slen_t parent
Definition: pair.h:851
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const(_msg)
Definition: strerror.h:223
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition: types.h:433
#define fr_type_is_leaf(_x)
Definition: types.h:372
#define FR_TYPE_LEAF
Definition: types.h:297
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:4548
return fr_dbuff_set(dbuff, &our_dbuff)
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:4036
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:621
static fr_slen_t data
Definition: value.h:1265
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition: value.h:587
#define fr_value_box_list_foreach(_list_head, _iter)
Definition: value.h:206
static size_t char ** out
Definition: value.h:997