]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
loop over nested extended types
authorAlan T. DeKok <aland@freeradius.org>
Thu, 7 Sep 2023 17:19:55 +0000 (13:19 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 7 Sep 2023 17:19:55 +0000 (13:19 -0400)
src/protocols/radius/encode.c

index 0c3d89ef0e50b39ee4e299abd3d6567f825a2e21..07ae2f1c769b5fb6339153270d5d4e08279b431c 100644 (file)
@@ -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;