From: Arran Cudbard-Bell Date: Wed, 23 Oct 2024 05:37:35 +0000 (-0600) Subject: Add utility functions for applying alias fixups X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=180e190351a9b87fb55279ef4f9791f8a8cb6cb0;p=thirdparty%2Ffreeradius-server.git Add utility functions for applying alias fixups --- diff --git a/src/lib/util/dict_fixup.c b/src/lib/util/dict_fixup.c index c90c8068139..769686ce3bb 100644 --- a/src/lib/util/dict_fixup.c +++ b/src/lib/util/dict_fixup.c @@ -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 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); diff --git a/src/lib/util/dict_fixup_priv.h b/src/lib/util/dict_fixup_priv.h index 562f169b4bc..68d3499c425 100644 --- a/src/lib/util/dict_fixup_priv.h +++ b/src/lib/util/dict_fixup_priv.h @@ -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); diff --git a/src/lib/util/dict_priv.h b/src/lib/util/dict_priv.h index c7279ee3e55..8149532cfed 100644 --- a/src/lib/util/dict_priv.h +++ b/src/lib/util/dict_priv.h @@ -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); diff --git a/src/lib/util/dict_util.c b/src/lib/util/dict_util.c index 52f2d9862b7..91ce6776248 100644 --- a/src/lib/util/dict_util.c +++ b/src/lib/util/dict_util.c @@ -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