From: Alan T. DeKok Date: Thu, 21 Aug 2025 14:51:48 +0000 (-0400) Subject: rearrange in preparation for encoding unions X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6038e6aa68692df8e7743fc3d5b6d60600fa260c;p=thirdparty%2Ffreeradius-server.git rearrange in preparation for encoding unions --- diff --git a/src/lib/util/struct.c b/src/lib/util/struct.c index f4c5205c4c..cbd20df2a2 100644 --- a/src/lib/util/struct.c +++ b/src/lib/util/struct.c @@ -611,22 +611,6 @@ ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, FR_PROTO_TRACE("fr_struct_to_network child %s", child->name); - /* - * Encode child TLVs at the end of a struct. - * - * In order to encode the child TLVs, we need to - * know the length of "T" and "L", and we don't. - * So just let the caller do the work. - */ - if (child->type == FR_TYPE_TLV) { - if (offset != 0) goto leftover_bits; - - fr_assert(!key_da); - - tlv = child; - goto done; - } - /* * The MEMBER may be raw, in which case it is encoded as octets. * @@ -642,7 +626,14 @@ ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, fr_assert(vp->vp_type == FR_TYPE_OCTETS); fr_assert(!da_is_bit_field(child)); - goto raw; + goto raw; /* we may have a raw entry in an array :( */ + } + + /* + * Remember the key field. Note that we ignore raw key fields. + */ + if (fr_dict_attr_is_key_field(child)) { + key_da = child; } /* @@ -664,9 +655,10 @@ ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, continue; } - if (fr_dict_attr_is_key_field(child)) { - key_da = child; - } + /* + * A child TLV is missing, we're done, and we don't encode any data. + */ + if (child->type == FR_TYPE_TLV) goto done; /* * Zero out the unused field. @@ -687,6 +679,8 @@ ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, if (da_is_bit_field(child)) { uint64_t value; + FR_PROTO_TRACE("child %s is a bit field", child->name); + switch (child->type) { case FR_TYPE_BOOL: value = vp->vp_bool; @@ -733,14 +727,25 @@ ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, } /* - * Remember key_da before we do any encoding. + * Encode child TLVs at the end of a struct. + * + * In order to encode the child TLVs, we need to + * know the length of "T" and "L", and we don't. + * So just let the caller do the work. */ - if (fr_dict_attr_is_key_field(child)) { - key_da = child; + if (child->type == FR_TYPE_TLV) { + fr_assert(!key_da); + + FR_PROTO_TRACE("child %s is a TLV field", child->name); + tlv = child; + goto done; } if (encode_value) { ssize_t len; + + FR_PROTO_TRACE("child %s encode_value", child->name); + /* * Call the protocol encoder for non-bit fields. */ @@ -754,11 +759,19 @@ ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, if (len < 0) return len; vp = fr_dcursor_current(cursor); + } else if (!fr_type_is_leaf(child->type)) { + fr_strerror_printf("non-leaf attribute %s of type %s in struct %s, but no 'encode_value' callback was specified", + child->name, fr_type_to_str(child->type), parent->name); + return PAIR_ENCODE_FATAL_ERROR; + } else { - redo: + continue_array: +#if 0 /* * Hack until we find all places that don't set data.enumv */ + fr_assert(!vp->da->flags.length || (vp->data.enumv == vp->da)); +#else if (vp->da->flags.length && (vp->data.enumv != vp->da)) { fr_dict_attr_t const * const *c = &vp->data.enumv; fr_dict_attr_t **u; @@ -766,17 +779,20 @@ ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, memcpy(&u, &c, sizeof(c)); /* const issues */ memcpy(u, &vp->da, sizeof(vp->da)); } +#endif /* * Determine the nested type and call the appropriate encoder */ raw: + FR_PROTO_TRACE("child %s encode to network", child->name); + if (fr_value_box_to_network(&work_dbuff, &vp->data) <= 0) return PAIR_ENCODE_FATAL_ERROR; vp = fr_dcursor_next(cursor); if (!vp) break; - if (child->flags.array && (vp->da == child)) goto redo; + if (child->flags.array && (vp->da == child)) goto continue_array; } next: diff --git a/src/tests/unit/protocols/radius/struct.txt b/src/tests/unit/protocols/radius/struct.txt index 701c6e96da..938cc3d25f 100644 --- a/src/tests/unit/protocols/radius/struct.txt +++ b/src/tests/unit/protocols/radius/struct.txt @@ -3,6 +3,9 @@ proto-dictionary radius load-dictionary dictionary.test fuzzer-out radius +# +# The struct has a TLV child, but we didn't ask to encode one. Silently omit it. +# encode-pair Extended-Attribute-1 = { Unit-Ext-241-Struct2 = { Unit-Struct2-Int1 = 1, Unit-Struct2-Short = 4 } } match f1 09 f8 00 00 00 01 00 04