From: Alan T. DeKok Date: Fri, 12 Oct 2018 18:16:17 +0000 (-0400) Subject: decode TLVs after fixed-length structs, too X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=045bea980267cd283d2cee0a00f415f74ee04551;p=thirdparty%2Ffreeradius-server.git decode TLVs after fixed-length structs, too --- diff --git a/src/lib/util/struct.c b/src/lib/util/struct.c index 3581cef9af9..c993bece42a 100644 --- a/src/lib/util/struct.c +++ b/src/lib/util/struct.c @@ -55,7 +55,8 @@ VALUE_PAIR *fr_unknown_from_network(TALLOC_CTX *ctx, fr_dict_attr_t const *paren * */ ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_cursor_t *cursor, - fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len) + fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, + fr_dict_attr_t const **child_p) { unsigned int child_num; uint8_t const *p = data, *end = data + data_len; @@ -70,6 +71,7 @@ ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_cursor_t *cursor, * Record where we were in the list when this function was called */ fr_cursor_init(&child_cursor, &head); + *child_p = NULL; /* * Data is too small for the structure, ignore it. @@ -93,6 +95,21 @@ ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_cursor_t *cursor, child = fr_dict_attr_child_by_num(parent, child_num); if (!child) break; + /* + * Decode child TLVs, according to the parent attribute. + * + * Return only PARTIALLY decoded data. Let the + * caller decode the rest. + */ + if (child->type == FR_TYPE_TLV) { + *child_p = child; + + fr_cursor_head(&child_cursor); + fr_cursor_tail(cursor); + fr_cursor_merge(cursor, &child_cursor); /* Wind to the end of the new pairs */ + return (p - data); + } + child_length = child->flags.length; if (!child_length) child_length = (end - p); diff --git a/src/lib/util/struct.h b/src/lib/util/struct.h index a34e1a21a3c..63a4414881f 100644 --- a/src/lib/util/struct.h +++ b/src/lib/util/struct.h @@ -32,7 +32,8 @@ extern "C" { #endif ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_cursor_t *cursor, - fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len) CC_HINT(nonnull); + fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, + fr_dict_attr_t const **child) CC_HINT(nonnull(2,3,4)); ssize_t fr_struct_to_network(uint8_t *out, size_t outlen, fr_dict_attr_t const *parent, fr_cursor_t *cursor) CC_HINT(nonnull); diff --git a/src/protocols/radius/decode.c b/src/protocols/radius/decode.c index 37b13c58a01..a0ae481054b 100644 --- a/src/protocols/radius/decode.c +++ b/src/protocols/radius/decode.c @@ -1262,8 +1262,29 @@ ssize_t fr_radius_decode_pair_value(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dic * attribute, OR it's already been grouped * into a contiguous memory buffer. */ - rcode = fr_struct_from_network(ctx, cursor, parent, p, attr_len); + rcode = fr_struct_from_network(ctx, cursor, parent, p, attr_len, &child); if (rcode < 0) goto raw; + + /* + * The above function only decodes fixed fields + * and strings. If there are TLVs at the end of + * the struct, we have to decode them manually + * here. + */ + if (child && ((size_t) rcode < attr_len)) { + size_t tlv_len; + + /* + * Try to decode the TLVs + */ + tlv_len = fr_radius_decode_tlv(ctx, cursor, child, p + rcode, attr_len - rcode, + decoder_ctx); + if (tlv_len < 0) { + vp = fr_unknown_from_network(ctx, child, p + rcode, attr_len - rcode); + if (vp) fr_cursor_append(cursor, vp); + } + } + return attr_len; case FR_TYPE_VSA: