From: Alan T. DeKok Date: Fri, 10 Feb 2023 20:34:00 +0000 (-0500) Subject: add function to check for "da can contain other da" X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0da0ff922631e8f9c4187e194f5f47f54c338c3a;p=thirdparty%2Ffreeradius-server.git add function to check for "da can contain other da" really for fr_pair_t validation, but it's still useful to have a sanity check function in the dictionary code. --- diff --git a/src/lib/util/dict.h b/src/lib/util/dict.h index 12709aa98c0..dcce2e6ae35 100644 --- a/src/lib/util/dict.h +++ b/src/lib/util/dict.h @@ -470,6 +470,8 @@ fr_dict_attr_t const *fr_dict_attr_by_oid(fr_dict_attr_err_t *err, bool fr_dict_attr_compatible(fr_dict_attr_t const *a, fr_dict_attr_t const *b) CC_HINT(nonnull); +bool fr_dict_attr_can_contain(fr_dict_attr_t const *parent, fr_dict_attr_t const *child) CC_HINT(nonnull); + /** @} */ /** @name Attribute, vendor and dictionary lookup diff --git a/src/lib/util/dict_util.c b/src/lib/util/dict_util.c index 89030f86999..9bf38a836f3 100644 --- a/src/lib/util/dict_util.c +++ b/src/lib/util/dict_util.c @@ -4304,3 +4304,63 @@ bool fr_dict_attr_compatible(fr_dict_attr_t const *a, fr_dict_attr_t const *b) return (a == b); } + +/** See if a structural da is allowed to contain another da + * + * We have some complex rules with different structural types, + * different protocol dictionaries, references to other protocols, + * etc. + * + * @param[in] parent The parent da, must be structural + * @param[in] child The alleged child + * @return + * - false - the child is not allowed to be contained by the parent + * - true - the child is allowed to be contained by the parent + */ +bool fr_dict_attr_can_contain(fr_dict_attr_t const *parent, fr_dict_attr_t const *child) +{ + /* + * This is the common case: child is from the parent. + */ + if (child->parent == parent) return true; + + /* + * Only structural types can have children. + * + * @todo - yes, "key" members of FR_TYPE_STRUCT. + */ + if (!fr_type_structural[parent->type]) return false; + + /* + * An internal attribute can go into any other container. + * + * Any other attribute can go into an internal structural + * attribute, because why not? + */ + if (dict_gctx) { + if (child->dict == dict_gctx->internal) return true; + + if (parent->dict == dict_gctx->internal) return true; + } + + /* + * Protocol attributes have to be in the same dictionary. + * + * Unless they're a cross-protocol grouping attribute. + * In which case we check if the ref is the same. + */ + if (child->dict != parent->dict) { + fr_dict_attr_t const *ref; + + ref = fr_dict_attr_ref(parent); + return (ref && (ref->dict == child->dict)); + } + + /* + * We're in the same protocol dictionary, but the child + * isn't directly from the parent. Therefore the only + * type of same-protocol structure it can go into is a + * group. + */ + return (parent->type == FR_TYPE_GROUP); +} diff --git a/src/lib/util/pair.c b/src/lib/util/pair.c index 2c39808477c..f38db6c1443 100644 --- a/src/lib/util/pair.c +++ b/src/lib/util/pair.c @@ -2979,6 +2979,7 @@ void fr_pair_verify(char const *file, int line, fr_pair_list_t const *list, fr_p vp, talloc_get_name(vp), parent, talloc_get_name(parent)); + fr_assert(fr_dict_attr_can_contain(vp->da, child->da)); fr_pair_verify(file, line, &vp->vp_group, child); } }