23 RCSID(
"$Id: 2ae42f051d45500ccd7105538d69d3dacb3c6def $")
25 #include <freeradius-devel/util/cbor.h>
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)
34 #define CBOR_FLOAT (7)
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)
42 "integer",
"negative",
"octets",
"string",
43 "array",
"map",
"tag",
"float"
80 if (
data < (((uint64_t) 1) << 8)) {
88 if (
data < (((uint64_t) 1) << 16)) {
96 if (
data < (((uint64_t) 1) << 32)) {
116 #define cbor_encode_array(_dbuff, _size) cbor_encode_integer(_dbuff, CBOR_ARRAY, _size);
118 #define cbor_encode_tag(_dbuff, _tag) cbor_encode_integer(_dbuff, CBOR_TAG, _tag);
123 #define return_slen return slen - fr_dbuff_used(&work_dbuff)
160 #define cbor_encode_key cbor_encode_int64
188 data = vb->vb_uint16;
192 data = vb->vb_uint64;
196 data = vb->vb_uint64;
323 if (vb->vb_ip.scope_id != 0) {
331 if (vb->vb_ip.scope_id == 0)
break;
346 if (vb->vb_ip.scope_id != 0) {
357 if (vb->vb_ip.scope_id == 0)
break;
381 p = (
uint8_t const *) &vb->vb_ip.addr.v4.s_addr;
393 if (*end != 0)
break;
417 p = (
uint8_t const *) &vb->vb_ip.addr.v6.s6_addr;
429 if (*end != 0)
break;
457 if (fr_value_box_list_num_elements(&vb->vb_group) == 0) {
466 fr_value_box_list_num_elements(&vb->vb_group));
546 if (major != expected) {
569 if (
value < dst_min) {
574 if (
value > dst_max) {
595 if (
value > (1 << 20)) {
630 count = header & 0x1f;
633 fr_strerror_printf(
"Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
641 vb->vb_ip.prefix = 32;
647 sizeof(vb->vb_ip.addr.v4.s_addr),
648 sizeof(vb->vb_ip.addr.v4.s_addr), &work_dbuff);
661 vb->vb_ip.prefix =
value;
671 vb->vb_ip.scope_id =
value;
688 count = header & 0x1f;
691 fr_strerror_printf(
"Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
699 vb->vb_ip.prefix = 128;
705 sizeof(vb->vb_ip.addr.v6.s6_addr),
706 sizeof(vb->vb_ip.addr.v6.s6_addr), dbuff);
720 vb->vb_ip.prefix =
value;
730 vb->vb_ip.scope_id =
value;
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;
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;
835 if (
value >= ((uint64_t) 1) << 63) {
849 if (
value > ((uint64_t) 1) << 63)
goto invalid;
895 int64_t key, seconds, fraction, scale;
905 key = seconds = fraction = 0;
952 if (seconds > (INT64_MAX / scale)) {
955 }
else if (seconds < (INT64_MIN / scale)) {
964 fraction += seconds * scale;
1012 info = major & 0x1f;
1018 if (((info >= 28) && (info <= 30)) ||
1019 ((info == 31) && ((major == 0) || (major == 1) || (major == 6)))) {
1028 fr_strerror_printf(
"cbor data contains invalid content %d for expected data type %s",
1044 if (
value > (1 << 20)) {
1054 talloc_set_type(ptr,
char);
1076 if (
value > (1 << 20)) {
1098 if (
value > 1)
goto invalid_bool;
1099 vb->vb_bool =
value;
1109 vb->vb_uint8 =
value;
1113 if (
value > UINT16_MAX)
goto invalid;
1114 vb->vb_uint16 =
value;
1118 if (
value > UINT32_MAX)
goto invalid;
1119 vb->vb_uint32 =
value;
1123 vb->vb_uint64 =
value;
1127 if (
value > INT8_MAX)
goto invalid;
1128 vb->vb_int8 =
value;
1132 if (
value > INT16_MAX)
goto invalid;
1133 vb->vb_int16 =
value;
1137 if (
value > INT32_MAX)
goto invalid;
1138 vb->vb_int32 =
value;
1142 if (
value > INT64_MAX)
goto invalid;
1143 vb->vb_int64 =
value;
1147 integer_type_mismatch:
1161 if (
value > ((uint64_t) 1) << 63)
goto invalid;
1172 if (neg < INT8_MIN)
goto invalid;
1177 if (neg < INT16_MIN)
goto invalid;
1182 if (neg < INT32_MIN)
goto invalid;
1191 goto integer_type_mismatch;
1207 vb->vb_bool =
false;
1231 if (info == 22)
break;
1252 vb->vb_float32 =
data;
1256 vb->vb_float64 =
data;
1260 float_type_mismatch:
1280 vb->vb_float32 =
data;
1284 vb->vb_float64 = (double)
data;
1288 goto float_type_mismatch;
1301 vb->vb_float32 =
data;
1305 vb->vb_float64 =
data;
1309 goto float_type_mismatch;
1319 goto float_type_mismatch;
1371 #ifdef STATIC_ANALYZER
1392 if (header == 0xff) {
1417 fr_value_box_list_insert_tail(&vb->vb_group, child);
1454 switch (
vp->vp_type) {
1466 goto encode_children;
1490 if (child->da->parent !=
parent)
continue;
1501 if (child->da->parent !=
parent)
continue;
1538 info = major & 0x1f;
1566 if (slen < 0)
break;
1645 if (header != (((
CBOR_MAP) << 5) | 1)) {
1646 fr_strerror_printf(
"Invalid cbor header - expected map of 1 elements, got %02x", header);
1655 info = major & 0x1f;
1739 info = major & 0x1f;
1768 #ifdef STATIC_ANALYZER
1789 if (header == 0xff) {
static int const char char buffer[256]
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
static int invalid_type(fr_type_t type)
ssize_t fr_cbor_encode_value_box(fr_dbuff_t *dbuff, fr_value_box_t *vb)
Encode CBOR.
static ssize_t cbor_decode_ipv4_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
static ssize_t cbor_decode_int64(int64_t *out, fr_dbuff_t *dbuff, fr_type_t type)
static ssize_t cbor_decode_ipv6_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
static ssize_t cbor_decode_octets_memcpy(uint8_t *dst, size_t dst_min, size_t dst_max, fr_dbuff_t *dbuff)
#define cbor_encode_tag(_dbuff, _tag)
static ssize_t cbor_encode_octets(fr_dbuff_t *dbuff, uint8_t const *data, size_t data_len)
ssize_t fr_cbor_encode_pair(fr_dbuff_t *dbuff, fr_pair_t *vp)
Encode a pair.
static const uint64_t cbor_type_to_tag[FR_TYPE_MAX+1]
static ssize_t cbor_decode_date(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
static cbor_decode_type_t cbor_decode_type[FR_TYPE_MAX]
static ssize_t cbor_decode_time_delta(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
static ssize_t cbor_decode_ipv4_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
static fr_type_t cbor_guess_type(fr_dbuff_t *dbuff, bool pair)
Guess the data type of the CBOR data.
static ssize_t cbor_encode_integer(fr_dbuff_t *dbuff, uint8_t type, uint64_t data)
static ssize_t cbor_decode_integer(uint64_t *out, uint8_t info, fr_dbuff_t *dbuff)
static ssize_t cbor_decode_ethernet(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
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)
static ssize_t cbor_encode_int64(fr_dbuff_t *dbuff, int64_t neg)
static ssize_t cbor_decode_ipv6_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
#define cbor_encode_array(_dbuff, _size)
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)
static const char * cbor_type_to_str[8]
ssize_t(* cbor_decode_type_t)(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
static ssize_t cbor_decode_count(uint64_t *out, int expected, fr_dbuff_t *dbuff)
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
#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...
#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.
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
#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.
#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.
#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.
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#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.
#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker returning if there's insufficient space.
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)
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.
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.
@ 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.
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)
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)
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)
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.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
fr_aka_sim_id_type_t type
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
#define fr_time_delta_min()
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
static int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
#define fr_time_delta_wrap(_time)
static int64_t fr_time_delta_to_sec(fr_time_delta_t delta)
static fr_unix_time_t fr_unix_time_from_sec(int64_t sec)
#define fr_time_delta_max()
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
#define fr_type_is_leaf(_x)
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.
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.
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
#define fr_value_box_list_foreach(_list_head, _iter)
static size_t char ** out