]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
start of autoload and validation for dictionaries.
authorAlan T. DeKok <aland@freeradius.org>
Mon, 4 Nov 2019 21:07:56 +0000 (16:07 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 4 Nov 2019 21:18:06 +0000 (16:18 -0500)
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.

src/lib/util/dict.h
src/lib/util/dict_priv.h
src/lib/util/dict_tokenize.c
src/lib/util/dict_util.c
src/protocols/radius/base.c

index c67884c0a72cda76ac46304aa4e4441e0893ce5f..80fc52e4f7c77b1cda17d0b26ab6b59c37acb6f5 100644 (file)
@@ -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
  */
index c9012169383b3d6f68baba389d66bff99be6053a..3c12777f53ba6ad50cc79e84234e85567d0b4dea 100644 (file)
@@ -27,6 +27,7 @@ extern "C" {
 
 #include <freeradius-devel/util/dict.h>
 #include <freeradius-devel/util/hash.h>
+#include <freeradius-devel/util/dl.h>
 #include <freeradius-devel/protocol/base.h>
 
 #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
  *
index 972b5a3d06ee09624d471354d5c05fa1b7d1e0f6..7c7f2bbc6ba8217f5f858553a9401ad2af2d84ce 100644 (file)
@@ -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);
index 537d30a363f1327d3614196a63932c934ce92946..4296bcfc5e55aedd27f4bfd3af4e44ec56d0834d 100644 (file)
@@ -24,7 +24,6 @@ RCSID("$Id$")
 
 #include <freeradius-devel/util/conf.h>
 #include <freeradius-devel/util/dict_priv.h>
-#include <freeradius-devel/util/dl.h>
 #include <freeradius-devel/util/hash.h>
 #include <freeradius-devel/util/misc.h>
 #include <freeradius-devel/util/proto.h>
@@ -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;
index 7c9bae5fe86a48b34d44d3a222a2019a29cabecc..c9978767f87585cdea7e85c844a4d96b481e99b8 100644 (file)
@@ -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",
+};