From: Alan T. DeKok Date: Mon, 4 Nov 2019 21:07:56 +0000 (-0500) Subject: start of autoload and validation for dictionaries. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=98399279fdb6b9948d68f922a95041de73b0d6d2;p=thirdparty%2Ffreeradius-server.git start of autoload and validation for dictionaries. if we load protocol FOO, we now look for libfreeradius-FOO which *should* already be loaded. i.e. when the application links to libfreeradius-radius and calls fr_radius_init(), that function loads the RADIUS dictionaries. Which now link back to the library. The dictionary code then looks for a symbol called libfreeradius_FOO_dict_protocol and saves a pointer to that structure in the dictionary. We can now have protocol-specific validation functions. --- diff --git a/src/lib/util/dict.h b/src/lib/util/dict.h index c67884c0a72..80fc52e4f7c 100644 --- a/src/lib/util/dict.h +++ b/src/lib/util/dict.h @@ -196,6 +196,13 @@ typedef enum { FR_DICT_ATTR_EINVAL = -5 //!< Invalid arguments. } fr_dict_attr_err_t; +/** Protocol-specific callbacks in libfreeradius-PROTOCOL + * + */ +typedef struct { + char const *name; //!< name of this protocol +} fr_dict_protocol_t; + /* * Dictionary constants */ diff --git a/src/lib/util/dict_priv.h b/src/lib/util/dict_priv.h index c9012169383..3c12777f53b 100644 --- a/src/lib/util/dict_priv.h +++ b/src/lib/util/dict_priv.h @@ -27,6 +27,7 @@ extern "C" { #include #include +#include #include #define DICT_POOL_SIZE (1024 * 1024 * 2) @@ -87,6 +88,9 @@ struct fr_dict { unsigned int vsa_parent; //!< varies with different protocols int default_type_size; //!< for TLVs and VSAs int default_type_length; //!< for TLVs and VSAs + + dl_t *dl; //!< for validation + fr_dict_protocol_t const *proto; //!< protocol-specific validation functions }; extern bool dict_initialised; @@ -96,7 +100,7 @@ extern TALLOC_CTX *dict_ctx; extern fr_table_num_ordered_t const date_precision_table[]; extern size_t date_precision_table_len; -fr_dict_t *dict_alloc(TALLOC_CTX *ctx); +fr_dict_t *dict_alloc(TALLOC_CTX *ctx, char const *name); /** Initialise fields in a dictionary attribute structure * diff --git a/src/lib/util/dict_tokenize.c b/src/lib/util/dict_tokenize.c index 972b5a3d06e..7c7f2bbc6ba 100644 --- a/src/lib/util/dict_tokenize.c +++ b/src/lib/util/dict_tokenize.c @@ -1236,7 +1236,7 @@ static int dict_read_process_protocol(char **argv, int argc) return 0; } - dict = dict_alloc(NULL); + dict = dict_alloc(NULL, argv[0]); /* * Set the root attribute with the protocol name @@ -2240,7 +2240,7 @@ int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir) memcpy(&tmp, &dict_dir_default, sizeof(tmp)); dict_path = dict_subdir ? talloc_asprintf(NULL, "%s%c%s", dict_dir_default, FR_DIR_SEP, dict_subdir) : tmp; - dict = dict_alloc(dict_ctx); + dict = dict_alloc(dict_ctx, NULL); if (!dict) { error: if (!fr_dict_internal) talloc_free(dict); diff --git a/src/lib/util/dict_util.c b/src/lib/util/dict_util.c index 537d30a363f..4296bcfc5e5 100644 --- a/src/lib/util/dict_util.c +++ b/src/lib/util/dict_util.c @@ -24,7 +24,6 @@ RCSID("$Id$") #include #include -#include #include #include #include @@ -42,6 +41,8 @@ char *dict_dir_default; //!< The default location for loading dictionaries if ///< wasn't provided. TALLOC_CTX *dict_ctx; +static dl_loader_t *dict_loader; //!< for protocol validation + static fr_hash_table_t *protocol_by_name = NULL; //!< Hash containing names of all the registered protocols. static fr_hash_table_t *protocol_by_num = NULL; //!< Hash containing numbers of all the registered protocols. @@ -2152,6 +2153,27 @@ fr_dict_enum_t *fr_dict_enum_by_alias(fr_dict_attr_t const *da, char const *alia return fr_hash_table_finddata(dict->values_by_alias, &find); } +static int dict_dlopen(fr_dict_t *dict, char const *name) +{ + char *module_name; + + if (!name) return 0; + + module_name = talloc_typed_asprintf(NULL, "libfreeradius-%s", name); + + /* + * Pass in dict as the uctx so that we can get at it in + * any callbacks. + * + * Not all dictionaries have validation functions. It's + * a soft error if they don't exist. + */ + dict->dl = dl_by_name(dict_loader, module_name, dict, false); + + talloc_free(module_name); + return 0; +} + static int _dict_free_autoref(UNUSED void *ctx, void *data) { fr_dict_t *dict = data; @@ -2184,10 +2206,11 @@ static int _dict_free(fr_dict_t *dict) /** Allocate a new dictionary * * @param[in] ctx to allocate dictionary in. + * @param[in] name the name of the protocol * @return * - NULL on memory allocation error. */ -fr_dict_t *dict_alloc(TALLOC_CTX *ctx) +fr_dict_t *dict_alloc(TALLOC_CTX *ctx, char const *name) { fr_dict_t *dict; @@ -2248,6 +2271,12 @@ fr_dict_t *dict_alloc(TALLOC_CTX *ctx) dict->values_by_da = fr_hash_table_create(dict, dict_enum_value_hash, dict_enum_value_cmp, hash_pool_free); if (!dict->values_by_da) goto error; + if (dict_dlopen(dict, name) < 0) goto error; + + /* + * Try to load libfreeradius-NAME + */ + return dict; } @@ -2429,6 +2458,28 @@ void fr_dict_dump(fr_dict_t const *dict) _fr_dict_dump(dict, dict->root, 0); } +/** Callback to automatically load validation routines for dictionaries. + * + * @param[in] dl the library we just loaded + * @param[in] symbol pointer to a fr_dict_protocol_t table + * @param[in] user_ctx the global context which we don't need + * @return + * - 0 on success. + * - -1 on failure. + */ +static int dict_onload_func(dl_t const *dl, void *symbol, UNUSED void *user_ctx) +{ + fr_dict_t *dict = talloc_get_type_abort(dl->uctx, fr_dict_t); + fr_dict_protocol_t const *proto = symbol; + + /* + * Set the protocol-specific callbacks. + */ + dict->proto = proto; + + return 0; +} + /** Initialise the global protocol hashes * * @note Must be called before any other dictionary functions. @@ -2460,6 +2511,13 @@ int fr_dict_global_init(TALLOC_CTX *ctx, char const *dict_dir) talloc_free(dict_dir_default); /* Free previous value */ dict_dir_default = talloc_strdup(ctx, dict_dir); + dict_loader = dl_loader_init(ctx, NULL, NULL, false, false); + if (!dict_loader) return -1; + + if (dl_symbol_init_cb_register(dict_loader, 0, "dict_protocol", dict_onload_func, NULL) < 0) { + return -1; + } + dict_initialised = true; return 0; diff --git a/src/protocols/radius/base.c b/src/protocols/radius/base.c index 7c9bae5fe86..c9978767f87 100644 --- a/src/protocols/radius/base.c +++ b/src/protocols/radius/base.c @@ -1122,3 +1122,8 @@ void fr_radius_free(void) fr_dict_autofree(libfreeradius_radius_dict); } + +extern fr_dict_protocol_t libfreeradius_radius_dict_protocol; +fr_dict_protocol_t libfreeradius_radius_dict_protocol = { + .name = "radius", +};