From: Alan T. DeKok Date: Sun, 17 Apr 2022 18:37:37 +0000 (-0400) Subject: move decode_array() to generic fr_pair_array_from_network() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=819740c751603f35e614cf5fe595ae770f7971ce;p=thirdparty%2Ffreeradius-server.git move decode_array() to generic fr_pair_array_from_network() --- diff --git a/src/lib/util/decode.c b/src/lib/util/decode.c new file mode 100644 index 00000000000..e2874cb8a25 --- /dev/null +++ b/src/lib/util/decode.c @@ -0,0 +1,59 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * + * @file src/lib/util/decode.c + * @brief Generic functions for decoding protocols. + * + * @copyright 2022 Network RADIUS SAS (legal@networkradius.com) + */ +#include +#include +#include + +/** Decode an array of values from the network + * + * @param[in] ctx context to alloc new attributes in. + * @param[out] out Where to write the decoded options. + * @param[in] parent dictionary entry, must have parent->flags.array set + * @param[in] data to parse. + * @param[in] data_len of data to parse. + * @param[in] decode_ctx passed to decode_value + * @param[in] decode_value function to decode one value. + */ +ssize_t fr_pair_array_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, + uint8_t const *data, size_t data_len, void *decode_ctx, fr_pair_decode_value_t decode_value) +{ + uint8_t const *p = data, *end = p + data_len; + ssize_t slen; + + FR_PROTO_HEX_DUMP(data, data_len, "fr_pair_array_from_network"); + + if (!fr_cond_assert_msg(parent->flags.array, + "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set", + __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR; + + while (p < end) { + slen = decode_value(ctx, out, parent, p, (end - p), decode_ctx); + if (slen < 0) return slen - (p - data); + + p += slen; + } + + return data_len; +} diff --git a/src/lib/util/decode.h b/src/lib/util/decode.h index b42f031a1e4..6f4b50357c5 100644 --- a/src/lib/util/decode.h +++ b/src/lib/util/decode.h @@ -19,7 +19,7 @@ * * @file src/lib/util/decode.h * - * @copyright 2021 Network RADIUS SAS + * @copyright 2022 Network RADIUS SAS (legal@networkradius.com) */ RCSIDH(decode_h, "$Id$") @@ -32,16 +32,17 @@ extern "C" { /** Typedefs for simplifying the use and declaration of protocol decoders. * */ -typedef struct fr_proto_decode_ctx_s fr_proto_decode_ctx_t; - -typedef ssize_t (*fr_proto_decode_pair_t)(TALLOC_CTX *ctx, fr_pair_list_t *out, +typedef ssize_t (*fr_pair_decode_value_t)(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, - uint8_t const *data, size_t const data_len, fr_proto_decode_ctx_t *decode_ctx); + uint8_t const *data, size_t const data_len, void *decode_ctx); #define PROTO_DECODE_FUNC(_name) static ssize_t _name(TALLOC_CTX *ctx, fr_pair_list_t *out, \ fr_dict_attr_t const *parent, \ uint8_t const *data, size_t const data_len, fr_proto_decode_ctx_t *decode_ctx); \ +ssize_t fr_pair_array_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, + uint8_t const *data, size_t data_len, void *decode_ctx, fr_pair_decode_value_t decode_value); + #ifdef __cplusplus } #endif diff --git a/src/lib/util/libfreeradius-util.mk b/src/lib/util/libfreeradius-util.mk index 0d9074ea619..22a0cf8c4b0 100644 --- a/src/lib/util/libfreeradius-util.mk +++ b/src/lib/util/libfreeradius-util.mk @@ -14,6 +14,7 @@ SOURCES := \ cap.c \ dbuff.c \ debug.c \ + decode.c \ dict_ext.c \ dict_fixup.c \ dict_print.c \ diff --git a/src/lib/util/struct.c b/src/lib/util/struct.c index 75732d64687..5c7f326f271 100644 --- a/src/lib/util/struct.c +++ b/src/lib/util/struct.c @@ -64,7 +64,7 @@ fr_pair_t *fr_raw_from_network(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, ui ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, bool nested, void *decode_ctx, - fr_decode_value_t decode_value, fr_decode_value_t decode_tlv) + fr_pair_decode_value_t decode_value, fr_pair_decode_value_t decode_tlv) { unsigned int child_num; uint8_t const *p = data, *end = data + data_len; @@ -273,7 +273,11 @@ ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, if (decode_value) { ssize_t slen; - slen = decode_value(child_ctx, child_list, child, p, child_length, decode_ctx); + if (child->flags.array) { + slen = fr_pair_array_from_network(child_ctx, child_list, child, p, child_length, decode_ctx, decode_value); + } else { + slen = decode_value(child_ctx, child_list, child, p, child_length, decode_ctx); + } if (slen < 0) { FR_PROTO_TRACE("Failed decoding value"); goto unknown; diff --git a/src/lib/util/struct.h b/src/lib/util/struct.h index 5d458117327..367438a88e6 100644 --- a/src/lib/util/struct.h +++ b/src/lib/util/struct.h @@ -27,19 +27,16 @@ RCSIDH(struct_h, "$Id$") #include #include #include +#include #ifdef __cplusplus extern "C" { #endif -typedef ssize_t (*fr_decode_value_t)(TALLOC_CTX *ctx, fr_pair_list_t *out, - fr_dict_attr_t const *parent, - uint8_t const *data, size_t const data_len, void *decode_ctx); - ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, bool nested, void *decode_ctx, - fr_decode_value_t decode_value, fr_decode_value_t decode_tlv) CC_HINT(nonnull(2,3,4)); + fr_pair_decode_value_t decode_value, fr_pair_decode_value_t decode_tlv) CC_HINT(nonnull(2,3,4)); typedef ssize_t (*fr_encode_dbuff_t)(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx); diff --git a/src/protocols/dhcpv4/decode.c b/src/protocols/dhcpv4/decode.c index be80f6a7694..7bb00bbc2cf 100644 --- a/src/protocols/dhcpv4/decode.c +++ b/src/protocols/dhcpv4/decode.c @@ -39,9 +39,6 @@ static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, static ssize_t decode_tlv(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx); -static ssize_t decode_array(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, - uint8_t const *data, size_t data_len, void *decode_ctx); - static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx); @@ -65,8 +62,6 @@ static ssize_t decode_value_trampoline(TALLOC_CTX *ctx, fr_pair_list_t *out, return decode_dns_labels(ctx, out, parent, data, data_len, decode_ctx); } - if (parent->flags.array) return decode_array(ctx, out, parent, data, data_len, decode_ctx); - return decode_value(ctx, out, parent, data, data_len, decode_ctx); } @@ -448,32 +443,6 @@ static ssize_t decode_tlv(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t c return data_len; } -static ssize_t decode_array(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, - uint8_t const *data, size_t data_len, void *decode_ctx) -{ - uint8_t const *p = data, *end = p + data_len; - ssize_t slen; - - FR_PROTO_HEX_DUMP(data, data_len, "decode_array"); - - if (!fr_cond_assert_msg(parent->flags.array, - "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set", - __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR; - - while (p < end) { - slen = decode_value(ctx, out, parent, p, (end - p), decode_ctx); - if (slen < 0) return slen - (p - data); - - p += slen; - } - - /* - * We MUST have decoded the entire input. If - * not, we ignore the extra bits. - */ - return data_len; -} - static ssize_t decode_dns_labels(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx) @@ -702,7 +671,7 @@ static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_pair_list_append(out, &tmp); } else if (da->flags.array) { - slen = decode_array(ctx, out, da, data + 2, len, decode_ctx); + slen = fr_pair_array_from_network(ctx, out, da, data + 2, len, decode_ctx, decode_value); } else if (da->type == FR_TYPE_VSA) { slen = decode_vsa(ctx, out, da, data + 2, len, decode_ctx); @@ -817,7 +786,7 @@ ssize_t fr_dhcpv4_decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, slen = decode_tlv(ctx, out, da, packet_ctx->buffer, q - packet_ctx->buffer, packet_ctx); } else if (da->flags.array) { - slen = decode_array(ctx, out, da, packet_ctx->buffer, q - packet_ctx->buffer, packet_ctx); + slen = fr_pair_array_from_network(ctx, out, da, packet_ctx->buffer, q - packet_ctx->buffer, packet_ctx, decode_value); } else { slen = decode_value(ctx, out, da, packet_ctx->buffer, q - packet_ctx->buffer, packet_ctx); diff --git a/src/protocols/dhcpv6/decode.c b/src/protocols/dhcpv6/decode.c index 9b096289174..98671080f1b 100644 --- a/src/protocols/dhcpv6/decode.c +++ b/src/protocols/dhcpv6/decode.c @@ -99,9 +99,6 @@ static ssize_t decode_raw(TALLOC_CTX *ctx, fr_pair_list_t *out, static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx); -static ssize_t decode_array(TALLOC_CTX *ctx, fr_pair_list_t *out, - fr_dict_attr_t const *parent, - uint8_t const *data, size_t const data_len, void *decode_ctx); static ssize_t decode_dns_labels(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx); @@ -117,8 +114,6 @@ static ssize_t decode_value_trampoline(TALLOC_CTX *ctx, fr_pair_list_t *out, return decode_dns_labels(ctx, out, parent, data, data_len, decode_ctx); } - if (parent->flags.array) return decode_array(ctx, out, parent, data, data_len, decode_ctx); - return decode_value(ctx, out, parent, data, data_len, decode_ctx); } @@ -304,33 +299,6 @@ static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out, } -static ssize_t decode_array(TALLOC_CTX *ctx, fr_pair_list_t *out, - fr_dict_attr_t const *parent, - uint8_t const *data, size_t const data_len, void *decode_ctx) -{ - uint8_t const *p = data, *end = p + data_len; - ssize_t slen; - - FR_PROTO_HEX_DUMP(data, data_len, "decode_array"); - - if (!fr_cond_assert_msg(parent->flags.array, - "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set", - __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR; - - while (p < end) { - slen = decode_value(ctx, out, parent, p, (end - p), decode_ctx); - if (slen < 0) return slen; - - p += slen; - } - - /* - * We MUST have decoded the entire input. If - * not, we ignore the extra bits. - */ - return data_len; -} - static ssize_t decode_dns_labels(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx) @@ -570,7 +538,7 @@ static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_pair_list_append(out, &tmp); } else if (da->flags.array) { - slen = decode_array(ctx, out, da, data + 4, len, decode_ctx); + slen = fr_pair_array_from_network(ctx, out, da, data + 4, len, decode_ctx, decode_value); } else if (da->type == FR_TYPE_VSA) { slen = decode_vsa(ctx, out, da, data + 4, len, decode_ctx); diff --git a/src/protocols/dns/decode.c b/src/protocols/dns/decode.c index 93fc9cde9a8..abf64ae353a 100644 --- a/src/protocols/dns/decode.c +++ b/src/protocols/dns/decode.c @@ -82,9 +82,7 @@ static ssize_t decode_raw(TALLOC_CTX *ctx, fr_pair_list_t *out, static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx); -static ssize_t decode_array(TALLOC_CTX *ctx, fr_pair_list_t *out, - fr_dict_attr_t const *parent, - uint8_t const *data, size_t const data_len, void *decode_ctx); + static ssize_t decode_dns_labels(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx); @@ -100,9 +98,7 @@ static ssize_t decode_value_trampoline(TALLOC_CTX *ctx, fr_pair_list_t *out, FR_PROTO_TRACE("decode DNS labels"); return decode_dns_labels(ctx, out, parent, data, data_len, decode_ctx); } - - if (parent->flags.array) return decode_array(ctx, out, parent, data, data_len, decode_ctx); - + return decode_value(ctx, out, parent, data, data_len, decode_ctx); } @@ -212,50 +208,6 @@ static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out, } -static ssize_t decode_array(TALLOC_CTX *ctx, fr_pair_list_t *out, - fr_dict_attr_t const *parent, - uint8_t const *data, size_t const data_len, void *decode_ctx) -{ - uint8_t const *p = data, *end = p + data_len; - ssize_t slen; - size_t element_len; - - FR_PROTO_HEX_DUMP(data, data_len, "decode_array"); - - if (!fr_cond_assert_msg(parent->flags.array, - "%s: Internal sanity check failed, attribute \"%s\" does not have array bit set", - __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR; - - /* - * If the data is variable length i.e. strings or octets - * there is a length field before each element. - * - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+ - * | text-len | String | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+ - */ - while (p < end) { - if ((end - p) < 2) { - raw: - slen = decode_raw(ctx, out, parent, p, end - p , decode_ctx); - if (slen < 0) return slen; - break; - } - - element_len = fr_nbo_to_uint16(p); - if ((p + 2 + element_len) > end) { - goto raw; - } - - p += 2; - slen = decode_value(ctx, out, parent, p, element_len, decode_ctx); - if (slen < 0) return slen; - p += slen; - } - - return data_len; -} - static ssize_t decode_dns_labels(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx) @@ -395,7 +347,7 @@ static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, } } else if (da->flags.array) { - slen = decode_array(ctx, out, da, data + 4, len, decode_ctx); + slen = fr_pair_array_from_network(ctx, out, da, data + 4, len, decode_ctx, decode_value); } else { slen = decode_value(ctx, out, da, data + 4, len, decode_ctx);