]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
dict: Move a subset of dict functions to use sbuffs
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sat, 2 May 2020 01:08:48 +0000 (20:08 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sat, 2 May 2020 01:08:48 +0000 (20:08 -0500)
src/lib/server/tmpl.c
src/lib/util/dict.h
src/lib/util/dict_priv.h
src/lib/util/dict_tokenize.c
src/lib/util/dict_util.c
src/lib/util/pair_legacy.c
src/lib/util/pair_tokenize.c

index 8996489a6dca7b20781206b1a67a22a879fba6fc..78d603c35768d9b1b9012920d7284bffc22321e5 100644 (file)
@@ -760,7 +760,8 @@ ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, attr_ref_error_t *err,
         *      parsing the configuration files.
         */
        slen = fr_dict_attr_by_qualified_name_substr(NULL, &vpt->tmpl_da,
-                                                    rules->dict_def, p, !rules->disallow_internal);
+                                                    rules->dict_def, &FR_SBUFF_TMP(p, strlen(p)),
+                                                    !rules->disallow_internal);
        if (slen <= 0) {
                fr_strerror();  /* Clear out any existing errors */
 
index b11c251eea9bd9bdfa0e1df2a4f16aafbc675cfe..900276323f45529d6fec4b7a0781ae4e9c0c2aab 100644 (file)
@@ -29,6 +29,7 @@ extern "C" {
 #include <freeradius-devel/build.h>
 #include <freeradius-devel/missing.h>
 #include <freeradius-devel/util/dl.h>
+#include <freeradius-devel/util/sbuff.h>
 #include <freeradius-devel/util/table.h>
 #include <freeradius-devel/util/types.h>
 
@@ -187,7 +188,12 @@ typedef enum {
        FR_DICT_ATTR_PROTOCOL_NOTFOUND  = -2,                   //!< Protocol couldn't be found.
        FR_DICT_ATTR_PARSE_ERROR        = -3,                   //!< Attribute string couldn't be parsed
        FR_DICT_ATTR_OOM                = -4,                   //!< Memory allocation error.
-       FR_DICT_ATTR_EINVAL             = -5                    //!< Invalid arguments.
+       FR_DICT_ATTR_NOT_DESCENDENT     = -5,                   //!< Attribute is not a descendent of the parent
+                                                               ///< attribute.
+       FR_DICT_ATTR_NOT_ANCESTOR       = -6,                   //!< Attribute is not an ancestor of the child
+                                                               ///< attribute.
+       FR_DICT_ATTR_NO_CHILDREN        = -7,                   //!< Child lookup in attribute with no children.
+       FR_DICT_ATTR_EINVAL             = -8                    //!< Invalid arguments.
 } fr_dict_attr_err_t;
 
 typedef bool (*fr_dict_attr_valid_func_t)(fr_dict_t *dict, fr_dict_attr_t const *parent,
@@ -238,7 +244,7 @@ typedef struct fr_dict_gctx_s fr_dict_gctx_t;
 /** Characters that are allowed in dictionary attribute names
  *
  */
-extern bool const      fr_dict_attr_allowed_chars[UINT8_MAX];
+extern bool const      fr_dict_attr_allowed_chars[UINT8_MAX + 1];
 extern bool const      fr_dict_non_data_types[FR_TYPE_MAX + 1];
 
 /** @name Programatically create dictionary attributes and values
@@ -306,7 +312,8 @@ ssize_t                     fr_dict_attr_by_oid(fr_dict_t const *dict, fr_dict_attr_t const **pare
  */
 fr_dict_attr_t const   *fr_dict_root(fr_dict_t const *dict);
 
-ssize_t                        fr_dict_by_protocol_substr(fr_dict_t const **out, char const *name, fr_dict_t const *dict_def);
+ssize_t                        fr_dict_by_protocol_substr(fr_dict_attr_err_t *err,
+                                                  fr_dict_t const **out, fr_sbuff_t *name, fr_dict_t const *dict_def);
 
 fr_dict_t const                *fr_dict_by_protocol_name(char const *name);
 
@@ -358,13 +365,13 @@ fr_dict_attr_t const      *fr_dict_vendor_attr_by_da(fr_dict_attr_t const *da);
 fr_dict_attr_t const   *fr_dict_vendor_attr_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen);
 
 ssize_t                        fr_dict_attr_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
-                                                   fr_dict_t const *dict, char const *name) CC_HINT(nonnull(2,4));
+                                                   fr_dict_t const *dict, fr_sbuff_t *name) CC_HINT(nonnull(2,4));
 
 fr_dict_attr_t const   *fr_dict_attr_by_name(fr_dict_t const *dict, char const *attr);
 
 ssize_t                        fr_dict_attr_by_qualified_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
                                                              fr_dict_t const *dict_def,
-                                                             char const *attr, bool fallback);
+                                                             fr_sbuff_t *name, bool fallback);
 
 fr_dict_attr_err_t     fr_dict_attr_by_qualified_name(fr_dict_attr_t const **out,
                                                       fr_dict_t const *dict_def, char const *attr, bool fallback);
@@ -375,6 +382,10 @@ fr_dict_attr_t const       *fr_dict_attr_child_by_da(fr_dict_attr_t const *parent, fr_
 
 fr_dict_attr_t const   *fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr);
 
+ssize_t                        fr_dict_attr_child_by_name_substr(fr_dict_attr_err_t *err,
+                                                         fr_dict_attr_t const **out, fr_dict_attr_t const *parent,
+                                                         fr_sbuff_t *name, bool is_direct_decendent);
+
 fr_dict_enum_t         *fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value);
 
 char const             *fr_dict_enum_name_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value);
index 02b8a093ccb909de14671bc06302d53232eeedd9..a0090f31defd5d0c4088152434e1ec6d04620e09 100644 (file)
@@ -198,7 +198,8 @@ fr_dict_attr_t              *dict_attr_by_name(fr_dict_t const *dict, char const *name);
 
 fr_dict_attr_t         *dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr);
 
-ssize_t                        dict_by_protocol_substr(fr_dict_t **out, char const *name, fr_dict_t const *dict_def);
+ssize_t                        dict_by_protocol_substr(fr_dict_attr_err_t *err,
+                                               fr_dict_t **out, fr_sbuff_t *name, fr_dict_t const *dict_def);
 
 fr_dict_t              *dict_by_protocol_name(char const *name);
 
index 1645731176b79248b9349b5ec5916e99e3f0e289..648c37f83c9bbfb845f516cc6533e77cd1cc4db3 100644 (file)
@@ -687,7 +687,7 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *ctx, char **argv, in
                /*
                 *      Get / skip protocol name.
                 */
-               slen = dict_by_protocol_substr(&dict, ref, ctx->dict);
+               slen = dict_by_protocol_substr(NULL, &dict, &FR_SBUFF_TMP(ref, strlen(ref)), ctx->dict);
                if (slen < 0) {
                        talloc_free(ref);
                        return -1;
@@ -1507,7 +1507,8 @@ static int fr_dict_finalise(dict_tokenize_ctx_t *ctx)
                        /*
                         *      Get / skip protocol name.
                         */
-                       slen = dict_by_protocol_substr(&dict, this->ref, ctx->dict);
+                       slen = dict_by_protocol_substr(NULL,
+                                                      &dict, &FR_SBUFF_TMP(this->ref, strlen(this->ref)), ctx->dict);
                        if (slen <= 0) {
                                fr_dict_t *other;
 
index e1d04341d44fd5068a1062da6d19572fadd8f6f7..79fd131554747ad754e01a573d879fdaee8b8977 100644 (file)
@@ -97,7 +97,7 @@ size_t const dict_attr_sizes[FR_TYPE_MAX + 1][2] = {
 /** Characters allowed in dictionary names
  *
  */
-bool const fr_dict_attr_allowed_chars[UINT8_MAX] = {
+bool const fr_dict_attr_allowed_chars[UINT8_MAX + 1] = {
        ['-'] = true, ['/'] = true, ['_'] = true,
        ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true,
        ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true,
@@ -1316,15 +1316,17 @@ fr_dict_attr_t const *fr_dict_root(fr_dict_t const *dict)
        return dict->root;
 }
 
-ssize_t dict_by_protocol_substr(fr_dict_t **out, char const *name, fr_dict_t const *dict_def)
+ssize_t dict_by_protocol_substr(fr_dict_attr_err_t *err,
+                               fr_dict_t **out, fr_sbuff_t *name, fr_dict_t const *dict_def)
 {
        fr_dict_attr_t          root;
 
        fr_dict_t               *dict;
-       char const              *p;
        size_t                  len;
+       char                    buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1 + 1];      /* +1 \0 +1 for "too long" */
+       fr_sbuff_t              our_name = FR_SBUFF_NO_ADVANCE(name);
 
-       if (!dict_gctx || !name || !*name || !out) return 0;
+       if (!dict_gctx || !name || !fr_sbuff_remaining(name) || !out) return 0;
 
        memset(&root, 0, sizeof(root));
 
@@ -1332,44 +1334,45 @@ ssize_t dict_by_protocol_substr(fr_dict_t **out, char const *name, fr_dict_t con
         *      Advance p until we get something that's not part of
         *      the dictionary attribute name.
         */
-       for (p = name; fr_dict_attr_allowed_chars[(uint8_t)*p] && (*p != '.'); p++);
-
-       /*
-        *      If what we stopped at wasn't a '.', then there
-        *      can't be a protocol name in this string.
-        */
-       if (*p != '.') {
-               memcpy(out, &dict_def, sizeof(*out));
+       len = fr_sbuff_strncpy_allowed(buffer, sizeof(buffer),
+                                      &our_name, SIZE_MAX,
+                                      fr_dict_attr_allowed_chars);
+       if (len == 0) {
+               fr_strerror_printf("Zero length attribute name");
+               if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
                return 0;
        }
-
-       len = p - name;
        if (len > FR_DICT_ATTR_MAX_NAME_LEN) {
                fr_strerror_printf("Attribute name too long");
+               if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
                return -(FR_DICT_ATTR_MAX_NAME_LEN);
        }
 
-       root.name = talloc_bstrndup(NULL, name, len);
-       if (!root.name) {
-               fr_strerror_printf("Out of memory");
-               *out = NULL;
+       /*
+        *      If what we stopped at wasn't a '.', then there
+        *      can't be a protocol name in this string.
+        */
+       if (*(our_name.p) != '.') {
+               memcpy(out, &dict_def, sizeof(*out));
                return 0;
        }
+
+       root.name = buffer;
        dict = fr_hash_table_finddata(dict_gctx->protocol_by_name, &(fr_dict_t){ .root = &root });
-       talloc_const_free(root.name);
 
        if (!dict) {
-               fr_strerror_printf("Unknown protocol '%.*s'", (int) len, name);
+               fr_strerror_printf("Unknown protocol '%s'", root.name);
                *out = NULL;
                return 0;
        }
        *out = dict;
 
-       return p - name;
+       return (size_t)fr_sbuff_set(name, &our_name);
 }
 
 /** Look up a protocol name embedded in another string
  *
+ * @param[out] err             Parsing error.
  * @param[out] out             the resolve dictionary or NULL if the dictionary
  *                             couldn't be resolved.
  * @param[in] name             string start.
@@ -1379,12 +1382,12 @@ ssize_t dict_by_protocol_substr(fr_dict_t **out, char const *name, fr_dict_t con
  *     - <= 0 on error and (*out == NULL) (offset as negative integer)
  *     - > 0 on success (number of bytes parsed).
  */
-ssize_t fr_dict_by_protocol_substr(fr_dict_t const **out, char const *name, fr_dict_t const *dict_def)
+ssize_t fr_dict_by_protocol_substr(fr_dict_attr_err_t *err, fr_dict_t const **out, fr_sbuff_t *name, fr_dict_t const *dict_def)
 {
        ssize_t         slen;
        fr_dict_t       *dict = NULL;
 
-       slen = dict_by_protocol_substr(&dict, name, dict_def);
+       slen = dict_by_protocol_substr(err, &dict, name, dict_def);
        *out = dict;
 
        return slen;
@@ -1717,53 +1720,41 @@ fr_dict_attr_t const *fr_dict_vendor_attr_by_num(fr_dict_attr_t const *vendor_ro
  *     - The number of bytes of name consumed on success.
  */
 ssize_t fr_dict_attr_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
-                                   fr_dict_t const *dict, char const *name)
+                                   fr_dict_t const *dict, fr_sbuff_t *name)
 {
        fr_dict_attr_t const    *da;
-       char const              *p;
        size_t                  len;
-       char                    buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1];
-
+       char                    buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1 + 1];      /* +1 \0 +1 for "too long" */
+       fr_sbuff_t              our_name = FR_SBUFF_NO_ADVANCE(name);
        *out = NULL;
 
        INTERNAL_IF_NULL(dict, 0);
 
-       if (!*name) {
-       zero_length_name:
+       len = fr_sbuff_strncpy_allowed(buffer, sizeof(buffer),
+                                      &our_name, SIZE_MAX,
+                                      fr_dict_attr_allowed_chars);
+       if (len == 0) {
                fr_strerror_printf("Zero length attribute name");
                if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
                return 0;
        }
-
-       /*
-        *      Advance p until we get something that's not part of
-        *      the dictionary attribute name.
-        */
-       for (p = name; fr_dict_attr_allowed_chars[(uint8_t)*p]; p++);
-
-       len = p - name;
-       if (len == 0) goto zero_length_name;
-
        if (len > FR_DICT_ATTR_MAX_NAME_LEN) {
                fr_strerror_printf("Attribute name too long");
                if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
                return -(FR_DICT_ATTR_MAX_NAME_LEN);
        }
 
-       memcpy(buffer, name, len);
-       buffer[len] = '\0';
-
        da = fr_hash_table_finddata(dict->attributes_by_name, &(fr_dict_attr_t){ .name = buffer });
        if (!da) {
                if (err) *err = FR_DICT_ATTR_NOTFOUND;
-               fr_strerror_printf("Unknown attribute '%.*s'", (int) len, name);
+               fr_strerror_printf("Unknown attribute '%s'", buffer);
                return 0;
        }
 
        *out = da;
        if (err) *err = FR_DICT_ATTR_OK;
 
-       return p - name;
+       return (size_t)fr_sbuff_set(name, &our_name);
 }
 
 /* Internal version of fr_dict_attr_by_name
@@ -1811,27 +1802,27 @@ fr_dict_attr_t const *fr_dict_attr_by_name(fr_dict_t const *dict, char const *na
  *     - The number of bytes of name consumed on success.
  */
 ssize_t fr_dict_attr_by_qualified_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
-                                             fr_dict_t const *dict_def, char const *name, bool fallback)
+                                             fr_dict_t const *dict_def, fr_sbuff_t *name, bool fallback)
 {
        fr_dict_t               *dict = NULL;
        fr_dict_t               *dict_iter = NULL;
-       char const              *p = name;
        ssize_t                 slen;
        fr_dict_attr_err_t      aerr = FR_DICT_ATTR_OK;
        bool                    internal = false;
        fr_hash_iter_t          iter;
-
+       fr_sbuff_t              our_name = FR_SBUFF_NO_ADVANCE(name);
        *out = NULL;
 
+       fr_sbuff_trim_start(&our_name); /* So we can figure out the amount we advanced */
+
        INTERNAL_IF_NULL(dict_def, -1);
 
        /*
         *      Figure out if we should use the default dictionary
         *      or if the string was qualified.
         */
-       slen = dict_by_protocol_substr(&dict, p, dict_def);
+       slen = dict_by_protocol_substr(err, &dict, &our_name, dict_def);
        if (slen < 0) {
-               if (err) *err = FR_DICT_ATTR_PROTOCOL_NOTFOUND;
                return 0;
 
        /*
@@ -1844,12 +1835,10 @@ ssize_t fr_dict_attr_by_qualified_name_substr(fr_dict_attr_err_t *err, fr_dict_a
         *      Has dictionary qualifier, can't fallback
         */
        } else if (slen > 0) {
-               p += slen;
-
                /*
                 *      Next thing SHOULD be a '.'
                 */
-               if (*p++ != '.') {
+               if (fr_sbuff_next_char(&our_name) != '.') {
                        if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
                        return 0;
                }
@@ -1858,8 +1847,11 @@ ssize_t fr_dict_attr_by_qualified_name_substr(fr_dict_attr_err_t *err, fr_dict_a
        }
 
 again:
-       slen = fr_dict_attr_by_name_substr(&aerr, out, dict, p);
-
+       /*
+        *      We rely on the fact the sbuff is only
+        *      advanced on success.
+        */
+       fr_dict_attr_by_name_substr(&aerr, out, dict, &our_name);
        switch (aerr) {
        case FR_DICT_ATTR_OK:
                break;
@@ -1904,18 +1896,16 @@ again:
 
        fail:
                if (err) *err = aerr;
-               return -((p - name) + slen);
+               FR_SBUFF_ERROR_RETURN(&our_name);
 
        /*
         *      Other error codes are the same
         */
        default:
                if (err) *err = aerr;
-               return -((p - name) + slen);
+               FR_SBUFF_ERROR_RETURN(&our_name);
        }
 
-       p += slen;
-
        /*
         *      If we're returning a success code indication,
         *      ensure we populated out
@@ -1927,28 +1917,31 @@ again:
 
        if (err) *err = FR_DICT_ATTR_OK;
 
-       return p - name;
+       return (size_t)fr_sbuff_set(name, &our_name);
 }
 
 /** Locate a qualified #fr_dict_attr_t by its name and a dictionary qualifier
  *
  * @param[out] out             Dictionary found attribute.
  * @param[in] dict_def         Default dictionary for non-qualified dictionaries.
- * @param[in] attr             Dictionary/Attribute name.
+ * @param[in] name             Dictionary/Attribute name.
  * @param[in] fallback         If true, fallback to the internal dictionary.
  * @return an #fr_dict_attr_err_t value.
  */
 fr_dict_attr_err_t fr_dict_attr_by_qualified_name(fr_dict_attr_t const **out, fr_dict_t const *dict_def,
-                                                 char const *attr, bool fallback)
+                                                 char const *name, bool fallback)
 {
        ssize_t                 slen;
        fr_dict_attr_err_t      err = FR_DICT_ATTR_PARSE_ERROR;
+       fr_sbuff_t              our_name;
+
+       fr_sbuff_parse_init(&our_name, name, strlen(name));
 
-       slen = fr_dict_attr_by_qualified_name_substr(&err, out, dict_def, attr, fallback);
+       slen = fr_dict_attr_by_qualified_name_substr(&err, out, dict_def, &our_name, fallback);
        if (slen <= 0) return err;
 
-       if ((size_t)slen != strlen(attr)) {
-               fr_strerror_printf("Trailing garbage after attr string \"%s\"", attr);
+       if ((size_t)slen != fr_sbuff_len(&our_name)) {
+               fr_strerror_printf("Trailing garbage after attr string \"%s\"", name);
                return FR_DICT_ATTR_PARSE_ERROR;
        }
 
@@ -2070,6 +2063,44 @@ fr_dict_attr_t const *fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, un
        return dict_attr_child_by_num(parent, attr);
 }
 
+
+/** Look up an attribute by name in the dictionary that contains the parent
+ *
+ */
+ssize_t fr_dict_attr_child_by_name_substr(fr_dict_attr_err_t *err,
+                                         fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *name,
+                                         bool is_direct_decendent)
+{
+       ssize_t                 slen;
+
+       DA_VERIFY(parent);
+
+       if (!parent->children) {
+               if (err) *err = FR_DICT_ATTR_NO_CHILDREN;
+               return 0;
+       }
+
+       /*
+        *      We return the child of the referenced attribute, and
+        *      not of the "group" attribute.
+        */
+       if (parent->type == FR_TYPE_GROUP) parent = parent->ref;
+
+       slen = fr_dict_attr_by_name_substr(err, out, fr_dict_by_da(parent), name);
+       if (slen <= 0) return slen;
+
+       if (is_direct_decendent) {
+               if ((*out)->parent != parent) {
+               not_decendent:
+                       if (err) *err = FR_DICT_ATTR_NOT_DESCENDENT;
+                       *out = NULL;
+                       return 0;
+               }
+       } else if (!fr_dict_parent_common(parent, *out, true)) goto not_decendent;
+
+       return slen;
+}
+
 /** Lookup the structure representing an enum value in a #fr_dict_attr_t
  *
  * @param[in] da               to search in.
index b26f6afb899fe10c557877f0ad370ea89c4e6ca3..21813610f4c9c729e1bf72f96f9c41d34bb8f7c6 100644 (file)
@@ -416,7 +416,7 @@ static ssize_t fr_pair_list_afrom_substr(TALLOC_CTX *ctx, fr_dict_t const *dict,
                /*
                 *      Parse the name.
                 */
-               slen = fr_dict_attr_by_qualified_name_substr(NULL, &da, dict, p, true);
+               slen = fr_dict_attr_by_qualified_name_substr(NULL, &da, dict, &FR_SBUFF_TMP(p, strlen(p)), true);
                if (slen <= 0) {
 
                        slen = fr_dict_unknown_afrom_oid_substr(ctx, &da_unknown, root, p);
index dc36cdfe375283c69e7a534309e4ae676019c687..226297fc2ab73be2bbab2b794ad979e7ad443e77 100644 (file)
@@ -191,7 +191,7 @@ static ssize_t fr_pair_afrom_str(fr_pair_ctx_t *pair_ctx, char const *start, cha
        VALUE_PAIR *vp;
        FR_TOKEN op;
 
-       slen = fr_dict_attr_by_name_substr(NULL, &da, pair_ctx->parent->dict, in);
+       slen = fr_dict_attr_by_name_substr(NULL, &da, pair_ctx->parent->dict, &FR_SBUFF_TMP(p, end - p));
        if (slen <= 0) return slen - (in - start);
 
        if (da->parent != pair_ctx->parent) {
@@ -305,7 +305,7 @@ static ssize_t fr_pair_ctx_set(fr_pair_ctx_t *pair_ctx, char const *in, size_t i
         *      Parse the attribute name.
         */
        while (p < end) {
-               slen = fr_dict_attr_by_name_substr(NULL, &da, parent->dict, p);
+               slen = fr_dict_attr_by_name_substr(NULL, &da, parent->dict, &FR_SBUFF_TMP(p, end - p));
                if (slen <= 0) return slen - (p - in);
 
                if (da->parent != parent) {
@@ -440,7 +440,7 @@ ssize_t fr_pair_ctx_afrom_str(fr_pair_ctx_t *pair_ctx, char const *in, size_t in
                /*
                 *      We allow a leaf OR a reference here.
                 */
-               slen = fr_dict_attr_by_name_substr(NULL, &da, pair_ctx->parent->dict, p);
+               slen = fr_dict_attr_by_name_substr(NULL, &da, pair_ctx->parent->dict, &FR_SBUFF_TMP(p, end - p));
                if (slen <= 0) return slen - (p - in);
 
                /*