From: Alan T. DeKok Date: Thu, 7 Sep 2023 17:19:55 +0000 (-0400) Subject: loop over nested extended types X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9d6fa24182c0993d6fc694f6e52dbc3f98780ffa;p=thirdparty%2Ffreeradius-server.git loop over nested extended types --- diff --git a/src/protocols/radius/encode.c b/src/protocols/radius/encode.c index 0c3d89ef0e5..07ae2f1c769 100644 --- a/src/protocols/radius/encode.c +++ b/src/protocols/radius/encode.c @@ -784,6 +784,9 @@ static ssize_t encode_extended(fr_dbuff_t *dbuff, FR_PROTO_HEX_DUMP(fr_dbuff_current(&hdr), hlen, "header extended"); } + /* + * This also handles TLVs + */ slen = encode_value(&work_dbuff, da_stack, depth, cursor, encode_ctx); if (slen <= 0) return slen; @@ -810,6 +813,54 @@ static ssize_t encode_extended(fr_dbuff_t *dbuff, return fr_dbuff_set(dbuff, &work_dbuff); } +/* + * The encode_extended() function expects to see the TLV or + * STRUCT inside of the extended attribute, in which case it + * creates the attribute header and calls encode_value() for the + * leaf type, or child TLV / struct. + * + * If we see VSA or VENDOR, then we recurse past that to a child + * which is either a leaf, or a TLV, or a STRUCT. + */ +static ssize_t encode_extended_nested(fr_dbuff_t *dbuff, + fr_da_stack_t *da_stack, unsigned int depth, + fr_dcursor_t *cursor, void *encode_ctx) +{ + ssize_t slen; + fr_pair_t *parent, *vp; + fr_dcursor_t child_cursor; + fr_dbuff_t work_dbuff = FR_DBUFF(dbuff); + + parent = fr_dcursor_current(cursor); + fr_assert(fr_type_is_structural(parent->vp_type)); + + (void) fr_pair_dcursor_init(&child_cursor, &parent->vp_group); + + while ((vp = fr_dcursor_current(&child_cursor)) != NULL) { + if (fr_type_is_leaf(vp->vp_type) || + ((depth > 1) && ((vp->vp_type == FR_TYPE_TLV) || (vp->vp_type == FR_TYPE_STRUCT)))) { + fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL); + slen = encode_extended(&work_dbuff, da_stack, 0, &child_cursor, encode_ctx); + + } else { + slen = encode_extended_nested(&work_dbuff, da_stack, 0, &child_cursor, encode_ctx); + } + + if (slen < 0) return slen; + } + + vp = fr_dcursor_next(cursor); + + /* + * @fixme: attributes with 'concat' MUST of type + * 'octets', and therefore CANNOT have any TLV data in them. + */ + fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL); + + return fr_dbuff_set(dbuff, &work_dbuff); +} + + /** Encode an RFC format attribute, with the "concat" flag set * * If there isn't enough freespace in the packet, the data is @@ -824,7 +875,7 @@ static ssize_t encode_concat(fr_dbuff_t *dbuff, { uint8_t const *p; size_t data_len; - fr_pair_t const *vp = fr_dcursor_current(cursor); + fr_pair_t const *vp = fr_dcursor_current(cursor); fr_dbuff_t work_dbuff = FR_DBUFF(dbuff); fr_dbuff_marker_t hdr; @@ -1555,8 +1606,12 @@ ssize_t fr_radius_encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *enc case FR_TYPE_TLV: if (!flag_extended(&da->flags)) { slen = encode_child(&work_dbuff, &da_stack, 0, cursor, encode_ctx); - } else { + + } else if (vp->da != da) { slen = encode_extended(&work_dbuff, &da_stack, 0, cursor, encode_ctx); + + } else { + slen = encode_extended_nested(&work_dbuff, &da_stack, 0, cursor, encode_ctx); } if (slen < 0) return slen; break;