diff --git a/src/protocols/radius/decode.c b/src/protocols/radius/decode.c index 5423f32f49e7..08e8f9c43141 100644 --- a/src/protocols/radius/decode.c +++ b/src/protocols/radius/decode.c @@ -454,7 +454,7 @@ ssize_t fr_radius_decode_tlv(TALLOC_CTX *ctx, fr_cursor_t *cursor, */ static ssize_t fr_radius_decode_struct(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, - void *decoder_ctx) + UNUSED void *decoder_ctx) { unsigned int child_num; uint8_t const *p = data, *end = data + data_len; @@ -466,16 +466,20 @@ static ssize_t fr_radius_decode_struct(TALLOC_CTX *ctx, fr_cursor_t *cursor, FR_PROTO_HEX_DUMP("struct", p, data_len); + /* + * Data is too small for the structure, ignore it. + */ if (data_len < parent->flags.length) goto raw; /* * Record where we were in the list when this function was called */ fr_cursor_init(&child_cursor, &head); + child_num = 1; while (p < end) { - ssize_t decoded_len; size_t child_length; + VALUE_PAIR *vp; /* * Go to the next child. If it doesn't exist, we're done. @@ -488,18 +492,36 @@ static ssize_t fr_radius_decode_struct(TALLOC_CTX *ctx, fr_cursor_t *cursor, child_length = child->flags.length; if (!child_length) child_length = (end - p); + vp = fr_pair_afrom_da(ctx, child); + if (!vp) return -1; + /* - * Decode the next field based on the length of the child. - * dict.c enforces that child->flags.length is non-zero. + * We only allow a limited number of data types + * inside of a struct. */ - decoded_len = fr_radius_decode_pair_value(ctx, &child_cursor, child, p, - child_length, child_length, - decoder_ctx); - if (decoded_len < 0) { + switch (child->type) { + default: + fr_strerror_printf("Invalid data type passed to encode_struct"); + return -1; + + case FR_TYPE_VALUES: + case FR_TYPE_STRUCT: + break; + } + + /* + * No protocol-specific magic here. + * + * @todo - allow it, if necessary + */ + if (fr_value_box_from_network(vp, &vp->data, vp->da->type, vp->da, p, child_length, true) < 0) { + TALLOC_FREE(vp); + FR_PROTO_TRACE("Failed to decode child %u of STRUCT %s", child_num, parent->name); - raw: fr_pair_list_free(&head); + + raw: fr_cursor_init(&child_cursor, &head); /* @@ -509,15 +531,24 @@ static ssize_t fr_radius_decode_struct(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_vendor_num_by_da(parent), parent->attr); if (!child) return -1; - /* - * Decode the whole STRUCT as an unknown attribute - */ - decoded_len = fr_radius_decode_pair_value(ctx, &child_cursor, child, - data, data_len, data_len, decoder_ctx); - if (decoded_len < 0) return decoded_len; + vp = fr_pair_afrom_da(ctx, child); + if (!vp) return -1; + + if (fr_value_box_from_network(vp, &vp->data, vp->da->type, vp->da, data, data_len, true) < 0) { + TALLOC_FREE(vp); + return -1; + } + + vp->type = VT_DATA; + vp->vp_tainted = true; + fr_cursor_append(&child_cursor, vp); break; } + vp->type = VT_DATA; + vp->vp_tainted = true; + fr_cursor_append(&child_cursor, vp); + /* * Note that we're decoding fixed fields here. * So we skip the input based on the *known* @@ -526,6 +557,7 @@ static ssize_t fr_radius_decode_struct(TALLOC_CTX *ctx, fr_cursor_t *cursor, p += child_length; child_num++; /* go to the next child */ } + fr_cursor_head(&child_cursor); fr_cursor_tail(cursor); fr_cursor_merge(cursor, &child_cursor); /* Wind to the end of the new pairs */