]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add utility functions for applying alias fixups
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 23 Oct 2024 05:37:35 +0000 (23:37 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 24 Oct 2024 23:07:55 +0000 (17:07 -0600)
src/lib/util/dict_fixup.c
src/lib/util/dict_fixup_priv.h
src/lib/util/dict_priv.h
src/lib/util/dict_util.c

index c90c8068139db68fc62db03a375aa5291c72d6dc..769686ce3bb343bd32b75920b984c6b2a6e87ecf 100644 (file)
@@ -37,6 +37,19 @@ typedef struct {
        int                     line;                   //!< ditto.
 } dict_fixup_common_t;
 
+/** Add an enumeration value to an attribute that wasn't defined at the time the value was parsed
+ *
+ */
+typedef struct {
+       dict_fixup_common_t     common;                 //!< Common fields.
+
+       char                    *alias;                 //!< we need to create.
+       fr_dict_attr_t          *alias_parent;          //!< Where to add the alias.
+
+       char                    *ref;                   //!< what the alias references.
+       fr_dict_attr_t          *ref_parent;            //!< Parent attribute to resolve the 'attribute' string in.
+} dict_fixup_alias_t;
+
 /** Add an enumeration value to an attribute that wasn't defined at the time the value was parsed
  *
  */
@@ -655,6 +668,59 @@ static inline CC_HINT(always_inline) int dict_fixup_vsa_apply(UNUSED dict_fixup_
 }
 
 
+/** Resolve a group reference
+ *
+ * This is required as the reference may point to another dictionary which
+ * hasn't been loaded yet.
+ *
+ * @param[in] fctx             Holds current dictionary parsing information.
+ * @param[in] filename         this fixup relates to.
+ * @param[in] line             this fixup relates to.
+ * @param[in] alias_parent     where to add the alias.
+ * @param[in] alias            alias to add.
+ * @param[in] ref_parent       attribute that should contain the reference.
+ * @param[in] ref              OID string representing what the group references.
+ * @return
+ *     - 0 on success.
+ *     - -1 on out of memory.
+ */
+int dict_fixup_alias(dict_fixup_ctx_t *fctx, char const *filename, int line,
+                    fr_dict_attr_t *alias_parent, char const *alias,
+                    fr_dict_attr_t *ref_parent, char const *ref)
+{
+       dict_fixup_alias_t *fixup;
+
+       fixup = talloc(fctx->pool, dict_fixup_alias_t);
+       if (!fixup) {
+               fr_strerror_const("Out of memory");
+               return -1;
+       }
+       *fixup = (dict_fixup_alias_t) {
+               .alias = talloc_typed_strdup(fixup, alias),
+               .alias_parent = alias_parent,
+               .ref = talloc_typed_strdup(fixup, ref),
+               .ref_parent = ref_parent
+       };
+
+       return dict_fixup_common(filename, line, &fctx->alias, &fixup->common);
+}
+
+static inline CC_HINT(always_inline) int dict_fixup_alias_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_alias_t *fixup)
+{
+       fr_dict_attr_t const *da;
+
+       /*
+        *      The <ref> can be a name.
+        */
+       da = fr_dict_attr_by_oid(NULL, fixup->ref_parent, fixup->ref);
+       if (!da) {
+               fr_strerror_printf("Attribute '%s' aliased by '%s' doesn't exist in namespace '%s'",
+                                  fixup->ref, fixup->alias, fixup->ref_parent->name);
+               return -1;
+       }
+
+       return dict_attr_alias_add(fixup->alias_parent, fixup->alias, da);
+}
 
 /** Initialise a fixup ctx
  *
@@ -672,6 +738,7 @@ int dict_fixup_init(TALLOC_CTX *ctx, dict_fixup_ctx_t *fctx)
        fr_dlist_talloc_init(&fctx->group, dict_fixup_group_t, common.entry);
        fr_dlist_talloc_init(&fctx->clone, dict_fixup_clone_t, common.entry);
        fr_dlist_talloc_init(&fctx->vsa, dict_fixup_vsa_t, common.entry);
+       fr_dlist_talloc_init(&fctx->alias, dict_fixup_alias_t, common.entry);
 
        fctx->pool = talloc_pool(ctx, DICT_FIXUP_POOL_SIZE);
        if (!fctx->pool) return -1;
@@ -698,16 +765,19 @@ do { \
        /*
         *      Apply all the fctx in order
         *
+
         *      - Enumerations first as they have no dependencies
         *      - Group references next, as group attributes may be cloned.
         *      - Clones last as all other references and additions should
         *        be applied before cloning.
-        *      - Hash table fctx last.
+        *      - VSAs
+        *      - Aliases last as all attributes need to be defined.
         */
        APPLY_FIXUP(fctx, enumv, dict_fixup_enumv_apply, dict_fixup_enumv_t);
        APPLY_FIXUP(fctx, group, dict_fixup_group_apply, dict_fixup_group_t);
        APPLY_FIXUP(fctx, clone, dict_fixup_clone_apply, dict_fixup_clone_t);
        APPLY_FIXUP(fctx, vsa,   dict_fixup_vsa_apply,   dict_fixup_vsa_t);
+       APPLY_FIXUP(fctx, alias, dict_fixup_alias_apply, dict_fixup_alias_t);
 
        TALLOC_FREE(fctx->pool);
 
index 562f169b4bc3b4abbca7aa85c1a3557b3d299f85..68d3499c42558957a1faae26fdbccf0aa534bfd2 100644 (file)
@@ -36,6 +36,7 @@ typedef struct {
        fr_dlist_head_t         group;          //!< Group references to resolve.
        fr_dlist_head_t         clone;          //!< Clone operation to apply.
        fr_dlist_head_t         vsa;            //!< VSAs to add vendors for
+       fr_dlist_head_t         alias;          //!< Aliases that can't be resolved immediately.
 } dict_fixup_ctx_t;
 
 int    dict_fixup_enumv(dict_fixup_ctx_t *fctx, char const *filename, int line,
@@ -54,6 +55,10 @@ int  dict_fixup_clone(dict_fixup_ctx_t *fctx, char const *filename, int line,
 int    dict_fixup_vsa(dict_fixup_ctx_t *fctx, char const *filename, int line,
                         fr_dict_attr_t *da);
 
+int    dict_fixup_alias(dict_fixup_ctx_t *fctx, char const *filename, int line,
+                        fr_dict_attr_t *alias_parent, char const *alias,
+                        fr_dict_attr_t *ref_parent, char const *ref);
+
 int    dict_fixup_init(TALLOC_CTX *ctx, dict_fixup_ctx_t *fctx);
 
 int    dict_fixup_apply(dict_fixup_ctx_t *fctx);
index c7279ee3e55209207c35d1d157bf5eb77dd5627e..8149532cfed1802ead256887b978b04fd5263b53 100644 (file)
@@ -198,6 +198,8 @@ int                 dict_attr_acopy_children(fr_dict_t *dict, fr_dict_attr_t *dst, fr_dict_att
 
 int                    dict_attr_acopy_enumv(fr_dict_attr_t *dst, fr_dict_attr_t const *src);
 
+int                    dict_attr_alias_add(fr_dict_attr_t const *parent, char const *alias, fr_dict_attr_t const *ref);
+
 int                    dict_attr_child_add(fr_dict_attr_t *parent, fr_dict_attr_t *child);
 
 int                    dict_protocol_add(fr_dict_t *dict);
index 52f2d9862b7129c251c8d27b6d13d78422deef65..91ce677624836b0ccff36e60b999d4964a2ee4e7 100644 (file)
@@ -958,6 +958,61 @@ int dict_attr_acopy_enumv(fr_dict_attr_t *dst, fr_dict_attr_t const *src)
        return copied;
 }
 
+/** Add an alias to an existing attribute
+ *
+ */
+int dict_attr_alias_add(fr_dict_attr_t const *parent, char const *alias, fr_dict_attr_t const *ref)
+{
+       fr_dict_attr_t const *da;
+       fr_dict_attr_t *self;
+       fr_hash_table_t *namespace;
+
+       da = dict_attr_by_name(NULL, parent, alias);
+       if (da) {
+               fr_strerror_printf("ALIAS '%s' conflicts with another attribute in namespace %s",
+                                  alias, parent->name);
+               return -1;
+       }
+
+       /*
+        *      Note that we do NOT call fr_dict_attr_add() here.
+        *
+        *      When that function adds two equivalent attributes, the
+        *      second one is prioritized for printing.  For ALIASes,
+        *      we want the pre-existing one to be prioritized.
+        *
+        *      i.e. you can lookup the ALIAS by "name", but you
+        *      actually get returned "ref".
+        */
+       {
+               fr_dict_attr_flags_t flags = ref->flags;
+
+               flags.is_alias = 1;     /* These get followed automatically by public functions */
+
+               self = dict_attr_alloc(parent->dict->pool, parent, alias, ref->attr, ref->type, (&(dict_attr_args_t){ .flags = &flags, .ref = ref }));
+               if (unlikely(!self)) return -1;
+       }
+
+       self->dict = parent->dict;
+
+       fr_assert(fr_dict_attr_ref(self) == ref);
+
+       namespace = dict_attr_namespace(parent);
+       if (!namespace) {
+               fr_strerror_printf("Attribute '%s' does not contain a namespace", parent->name);
+       error:
+               talloc_free(self);
+               return -1;
+       }
+
+       if (!fr_hash_table_insert(namespace, self)) {
+               fr_strerror_const("Internal error storing attribute");
+               goto error;
+       }
+
+       return 0;
+}
+
 /** Add a protocol to the global protocol table
  *
  * Inserts a protocol into the global protocol table.  Uses the root attributes