]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
move decode_array() to generic fr_pair_array_from_network()
authorAlan T. DeKok <aland@freeradius.org>
Sun, 17 Apr 2022 18:37:37 +0000 (14:37 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 20 Apr 2022 13:15:08 +0000 (09:15 -0400)
src/lib/util/decode.c [new file with mode: 0644]
src/lib/util/decode.h
src/lib/util/libfreeradius-util.mk
src/lib/util/struct.c
src/lib/util/struct.h
src/protocols/dhcpv4/decode.c
src/protocols/dhcpv6/decode.c
src/protocols/dns/decode.c

diff --git a/src/lib/util/decode.c b/src/lib/util/decode.c
new file mode 100644 (file)
index 0000000..e2874cb
--- /dev/null
@@ -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 <freeradius-devel/io/test_point.h>
+#include <freeradius-devel/util/proto.h>
+#include <freeradius-devel/util/decode.h>
+
+/** 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;
+}
index b42f031a1e4c6b4b19e1961d8d67c618d3de0d1e..6f4b50357c5b967b0817e88a496e3303488fba74 100644 (file)
@@ -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
index 0d9074ea61962978a87ae6ba1cc293cb9aab8edb..22a0cf8c4b0974402c19563f19164b9790052f66 100644 (file)
@@ -14,6 +14,7 @@ SOURCES               := \
                   cap.c \
                   dbuff.c \
                   debug.c \
+                  decode.c \
                   dict_ext.c \
                   dict_fixup.c \
                   dict_print.c \
index 75732d64687076e9fd6a534f788baca7e857827f..5c7f326f2716429993b21c2856961496f5bd5318 100644 (file)
@@ -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;
index 5d458117327dad9047f48c877df4abd56218867b..367438a88e60d1e4229b1be9387b51e597c77112 100644 (file)
@@ -27,19 +27,16 @@ RCSIDH(struct_h, "$Id$")
 #include <freeradius-devel/util/pair.h>
 #include <freeradius-devel/util/value.h>
 #include <freeradius-devel/util/proto.h>
+#include <freeradius-devel/util/decode.h>
 
 #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);
index be80f6a76944151c5adbe55964d7652d7e40e33b..7bb00bbc2cf5b8011a7b418e0243e9ccda9860b0 100644 (file)
@@ -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);
index 9b096289174d7a27620e9fafbf2358449e047b16..98671080f1b4d625131fafbdc165b6a0fb017646 100644 (file)
@@ -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);
index 93fc9cde9a86b233f1500321773740ff387cbb4b..abf64ae353ad329e35c9a52d88f7d13381d8f48d 100644 (file)
@@ -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);