]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
decode TLVs after fixed-length structs, too
authorAlan T. DeKok <aland@freeradius.org>
Fri, 12 Oct 2018 18:16:17 +0000 (14:16 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 12 Oct 2018 18:16:17 +0000 (14:16 -0400)
src/lib/util/struct.c
src/lib/util/struct.h
src/protocols/radius/decode.c

index 3581cef9af9df4c055050bcfbaa6a20614663cea..c993bece42a87b4811e8c464bc6117ced362eab0 100644 (file)
@@ -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);
 
index a34e1a21a3cd5ccce850cc6a78ccf9158fc13a1f..63a4414881f32f69c512ef4a2f61aee5183e293b 100644 (file)
@@ -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);
 
index 37b13c58a010934fae8bd078af1cba54b4c2b081..a0ae481054bc6e7df35d1ed52a1ad85dff360aa1 100644 (file)
@@ -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: