]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add new top level dict_gctx, fix a bunch of const issues, make dictionaries read...
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 5 Nov 2019 20:17:25 +0000 (14:17 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 5 Nov 2019 20:17:25 +0000 (14:17 -0600)
33 files changed:
src/bin/radiusd.c
src/bin/unit_test_attribute.c
src/lib/server/cf_file.c
src/lib/server/cond_tokenize.c
src/lib/server/exec.c
src/lib/server/exfile.c
src/lib/server/paircmp.c
src/lib/server/tmpl.c
src/lib/server/trigger.c
src/lib/server/virtual_servers.c
src/lib/unlang/compile.c
src/lib/util/dict.h
src/lib/util/dict_priv.h
src/lib/util/dict_tokenize.c
src/lib/util/dict_unknown.c
src/lib/util/dict_util.c
src/lib/util/pair.c
src/modules/proto_detail/proto_detail.c
src/modules/proto_ldap_sync/proto_ldap_sync.c
src/modules/rlm_chap/rlm_chap.c
src/modules/rlm_dict/rlm_dict.c
src/modules/rlm_digest/rlm_digest.c
src/modules/rlm_eap/rlm_eap.c
src/modules/rlm_eap/types/rlm_eap_gtc/rlm_eap_gtc.c
src/modules/rlm_eap/types/rlm_eap_mschapv2/rlm_eap_mschapv2.c
src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c
src/modules/rlm_mschap/rlm_mschap.c
src/modules/rlm_opendirectory/rlm_opendirectory.c
src/modules/rlm_pap/rlm_pap.c
src/modules/rlm_winbind/rlm_winbind.c
src/modules/rlm_yubikey/rlm_yubikey.c
src/protocols/dhcpv4/base.c
src/protocols/dhcpv6/base.c

index 4969d97ecd8b7a281715e89d19c67e9d60f9b267..525951125ad0fd687dfe0e95fc6157982ae535d5 100644 (file)
@@ -874,6 +874,12 @@ int main(int argc, char *argv[])
         */
        if (sync_time) fr_time_sync_event(main_loop_event_list(), fr_time(), NULL);
 
+       /*
+        *      Prevent anything from modifying the dictionaries
+        *      they're now immutable.
+        */
+       fr_dict_global_read_only();
+
        /*
         *  Process requests until HUP or exit.
         */
index 903d5e488b547d97c468a8bee0c0727b030014d5..338a04b6a6f61d1aa8ab7300c9a6c1d0c053fecb 100644 (file)
@@ -788,7 +788,7 @@ static ssize_t load_test_point_by_command(void **symbol, char *command, char con
 
 /** Common dictionary load function
  *
- * Callers call fr_dict_dir_set to set the dictionary root to
+ * Callers call fr_dict_global_dir_set to set the dictionary root to
  * load dictionaries from, then provide a relative path to
  * navigate through test subdirectories or protocols
  */
@@ -1586,7 +1586,7 @@ static size_t command_proto(command_result_t *result, UNUSED command_ctx_t *cc,
                RETURN_PARSE_ERROR(0);
        }
 
-       fr_dict_dir_set(dict_dir);
+       fr_dict_global_dir_set(dict_dir);
        slen = load_proto_library(in);
        if (slen <= 0) RETURN_PARSE_ERROR(-(slen));
 
@@ -1596,7 +1596,7 @@ static size_t command_proto(command_result_t *result, UNUSED command_ctx_t *cc,
 static size_t command_proto_dictionary(command_result_t *result, command_ctx_t *cc,
                                       UNUSED char *data, UNUSED size_t data_used, char *in, UNUSED size_t inlen)
 {
-       fr_dict_dir_set(dict_dir);
+       fr_dict_global_dir_set(dict_dir);
 
        return dictionary_load_common(result, cc, in, NULL);
 }
@@ -1616,7 +1616,7 @@ static size_t command_touch(command_result_t *result, UNUSED command_ctx_t *cc,
 static size_t command_test_dictionary(command_result_t *result, command_ctx_t *cc,
                                      UNUSED char *data, UNUSED size_t data_used, char *in, UNUSED size_t inlen)
 {
-       fr_dict_dir_set(cc->path);
+       fr_dict_global_dir_set(cc->path);
 
        return dictionary_load_common(result, cc, in, ".");
 }
index 6fc859f65009b5bbf9c8f5ee9a682132d0d34f10..899382e36133ee4f2c6d78446a06ca0c10fb187e 100644 (file)
@@ -1049,7 +1049,7 @@ static CONF_SECTION *process_if(CONF_SECTION *parent, char const **ptr_p, char *
 
        cd = cf_data_find_in_parent(parent, fr_dict_t **, "dictionary");
        if (!cd) {
-               dict = fr_dict_internal;        /* HACK - To fix policy sections */
+               dict = fr_dict_internal();      /* HACK - To fix policy sections */
        } else {
                dict = *((fr_dict_t **)cf_data_value(cd));
        }
index b0ea64d2b6118bfd47a69e8da3ea28ce250e93f7..4ca7ae2ea3ee8b8b15af517f28b50cde57846579 100644 (file)
@@ -448,14 +448,14 @@ static ssize_t cond_check_attrs(fr_cond_t *c, char const *start,
                case FR_TYPE_IPV4_ADDR:
                        if (strchr(c->data.map->rhs->name, '/') != NULL) {
                                type = FR_TYPE_IPV4_PREFIX;
-                               c->cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal), FR_CAST_BASE + type);
+                               c->cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_CAST_BASE + type);
                        }
                        break;
 
                case FR_TYPE_IPV6_ADDR:
                        if (strchr(c->data.map->rhs->name, '/') != NULL) {
                                type = FR_TYPE_IPV6_PREFIX;
-                               c->cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal), FR_CAST_BASE + type);
+                               c->cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_CAST_BASE + type);
                        }
                        break;
 
@@ -516,12 +516,12 @@ static ssize_t cond_check_attrs(fr_cond_t *c, char const *start,
             tmpl_is_xlat_struct(c->data.map->rhs) ||
             tmpl_is_exec(c->data.map->rhs))) {
                if (c->data.map->lhs->tmpl_da->type == FR_TYPE_IPV4_ADDR) {
-                       c->cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal),
+                       c->cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()),
                                                            FR_CAST_BASE + FR_TYPE_IPV4_PREFIX);
                }
 
                if (c->data.map->lhs->tmpl_da->type == FR_TYPE_IPV6_ADDR) {
-                       c->cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal),
+                       c->cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()),
                                                            FR_CAST_BASE + FR_TYPE_IPV6_PREFIX);
                }
        }
@@ -760,7 +760,7 @@ static ssize_t cond_tokenize(TALLOC_CTX *ctx, CONF_SECTION *cs,
                        return_P("Empty octet string is invalid");
                }
 
-               c->cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal),
+               c->cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()),
                                                            FR_CAST_BASE + FR_TYPE_OCTETS);
        }
 
@@ -967,7 +967,7 @@ static ssize_t cond_tokenize(TALLOC_CTX *ctx, CONF_SECTION *cs,
                              (map->lhs->tmpl_da->type == FR_TYPE_UINT16) ||
                              (map->lhs->tmpl_da->type == FR_TYPE_UINT32) ||
                              (map->lhs->tmpl_da->type == FR_TYPE_UINT64))) {
-                               c->cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal),
+                               c->cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()),
                                                                    FR_CAST_BASE + FR_TYPE_OCTETS);
                        }
                }
index cdf60f970afa39eb872387d63084c5b8677e08f3..e028a8eb419429ab325f16fca41412a66cf74326 100644 (file)
@@ -227,7 +227,7 @@ pid_t radius_start_program(char const *cmd, REQUEST *request, bool exec_wait,
                }
 
                if (request) {
-                       da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal), FR_EXEC_EXPORT);
+                       da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_EXEC_EXPORT);
                        if (da) {
                                for (vp = fr_cursor_iter_by_da_init(&cursor, &request->control, da);
                                     vp && (envlen < ((NUM_ELEMENTS(envp)) - 1));
index 4e0c1bc25652843b098635419b240506b6bf36cd..7819b2d15518413d20af90667dce7eaac61dd666 100644 (file)
@@ -76,7 +76,7 @@ static inline void exfile_trigger_exec(exfile_t *ef, REQUEST *request, exfile_en
 
        if (!ef->trigger_prefix) return;
 
-       da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal), FR_EXFILE_NAME);
+       da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_EXFILE_NAME);
        if (!da) {
                ROPTIONAL(RERROR, ERROR, "Incomplete internal dictionary: Missing definition for \"Exfile-Name\"");
                return;
index 5457edec8d01bd4045df9f0318b3b090ad3beb1d..c59966fa55b61c63b85da1dfefd52ac548cfa2fe 100644 (file)
@@ -754,7 +754,7 @@ int paircmp_register_by_name(char const *name, fr_dict_attr_t const *from,
 
        memset(&flags, 0, sizeof(flags));
 
-       da = fr_dict_attr_by_name(fr_dict_internal, name);
+       da = fr_dict_attr_by_name(fr_dict_internal(), name);
        if (da) {
                if (paircmp_find(da)) {
                        fr_strerror_printf_push("Cannot register two comparions for attribute %s",
@@ -762,13 +762,13 @@ int paircmp_register_by_name(char const *name, fr_dict_attr_t const *from,
                        return -1;
                }
        } else if (from) {
-               if (fr_dict_attr_add(fr_dict_internal, fr_dict_root(fr_dict_internal),
+               if (fr_dict_attr_add(fr_dict_unconst(fr_dict_internal()), fr_dict_root(fr_dict_internal()),
                                     name, -1, from->type, &flags) < 0) {
                        fr_strerror_printf_push("Failed creating attribute '%s'", name);
                        return -1;
                }
 
-               da = fr_dict_attr_by_name(fr_dict_internal, name);
+               da = fr_dict_attr_by_name(fr_dict_internal(), name);
                if (!da) {
                        fr_strerror_printf("Failed finding attribute '%s'", name);
                        return -1;
index 50502d53bb3e400227e4d03d1c8fc761f9149f86..7f2132ca40fdd69173dc70b651e41f88e372ce07 100644 (file)
@@ -835,13 +835,13 @@ ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, attr_ref_error_t *err,
         *      Attribute location checks
         */
        {
-               fr_dict_t *found_in = fr_dict_by_da(vpt->tmpl_da);
+               fr_dict_t const *found_in = fr_dict_by_da(vpt->tmpl_da);
 
                /*
                 *      Even if allow_foreign is false, if disallow_internal is not
                 *      true, we still allow foreign
                 */
-               if (found_in == fr_dict_internal) {
+               if (found_in == fr_dict_internal()) {
                        if (rules->disallow_internal) {
                                fr_strerror_printf("Internal attributes not allowed here");
                                if (err) *err = ATTR_REF_ERROR_INTERNAL_ATTRIBUTE_NOT_ALLOWED;
@@ -1448,7 +1448,7 @@ int tmpl_define_unknown_attr(vp_tmpl_t *vpt)
 
        if (!vpt->tmpl_da->flags.is_unknown) return 1;
 
-       da = fr_dict_unknown_add(fr_dict_internal, vpt->tmpl_da);
+       da = fr_dict_unknown_add(fr_dict_unconst(fr_dict_internal()), vpt->tmpl_da);
        if (!da) return -1;
        vpt->tmpl_da = da;
 
@@ -1487,7 +1487,7 @@ int tmpl_define_undefined_attr(fr_dict_t *dict_def, vp_tmpl_t *vpt,
 
        if (!tmpl_is_attr_undefined(vpt)) return 1;
 
-       if (fr_dict_attr_add(dict_def, fr_dict_root(fr_dict_internal), vpt->tmpl_unknown_name, -1, type, flags) < 0) {
+       if (fr_dict_attr_add(dict_def, fr_dict_root(fr_dict_internal()), vpt->tmpl_unknown_name, -1, type, flags) < 0) {
                return -1;
        }
        da = fr_dict_attr_by_name(dict_def, vpt->tmpl_unknown_name);
@@ -2964,7 +2964,7 @@ ssize_t tmpl_preparse(char const **out, size_t *outlen, char const *start,
                        return_P("Forbidden data type in cast");
                }
 
-               *castda = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal), FR_CAST_BASE + cast);
+               *castda = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_CAST_BASE + cast);
                if (!*castda) {
                        return_P("Cannot cast to this data type");
                }
index 5b62b31472b0459f3662a30459329dbe4dd0db78..343640c23b79625b3ed863c9cb1a73a69230de98 100644 (file)
@@ -361,13 +361,13 @@ VALUE_PAIR *trigger_args_afrom_server(TALLOC_CTX *ctx, char const *server, uint1
        VALUE_PAIR              *out = NULL, *vp;
        fr_cursor_t             cursor;
 
-       server_da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal), FR_CONNECTION_POOL_SERVER);
+       server_da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_CONNECTION_POOL_SERVER);
        if (!server_da) {
                ERROR("Incomplete dictionary: Missing definition for \"Connection-Pool-Server\"");
                return NULL;
        }
 
-       port_da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal), FR_CONNECTION_POOL_PORT);
+       port_da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_CONNECTION_POOL_PORT);
        if (!port_da) {
                ERROR("Incomplete dictionary: Missing definition for \"Connection-Pool-Port\"");
                return NULL;
index 31e2d488e476fd622f7d384660770ebe1b104af9..7a7b5a726c837e5d34847378e816b920e37acbab 100644 (file)
@@ -398,7 +398,7 @@ int virtual_server_section_attribute_define(CONF_SECTION *server_cs, char const
                 *      this code, so it doesn't matter.  The only
                 *      requirement is that it's unique.
                 */
-               if (fr_dict_enum_add_name_next(da, name2) < 0) {
+               if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(da), name2) < 0) {
                        PERROR("Failed adding section value");
                        return -1;
                }
@@ -1066,7 +1066,7 @@ rlm_rcode_t process_authenticate(int auth_type, REQUEST *request)
                return RLM_MODULE_REJECT;
        }
 
-       da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal), FR_AUTH_TYPE);
+       da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_AUTH_TYPE);
        if (!da) return RLM_MODULE_FAIL;
 
        dv = fr_dict_enum_by_value(da, fr_box_uint32((uint32_t) auth_type));
index de749bf551d9701b1880e6a8c97ad79d1d0df90a..39cecccedaa2c5f57c82993470a44b2f1063bc24 100644 (file)
@@ -502,14 +502,14 @@ static bool pass2_fixup_map(fr_cond_t *c, vp_tmpl_rules_t const *rules)
                        switch (cast->type) {
                        case FR_TYPE_IPV4_ADDR:
                                if (strchr(c->data.map->lhs->name, '/') != NULL) {
-                                       c->cast = cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal),
+                                       c->cast = cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()),
                                                                                   FR_CAST_BASE + FR_TYPE_IPV4_PREFIX);
                                }
                                break;
 
                        case FR_TYPE_IPV6_ADDR:
                                if (strchr(c->data.map->lhs->name, '/') != NULL) {
-                                       c->cast = cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal),
+                                       c->cast = cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()),
                                                                                   FR_CAST_BASE + FR_TYPE_IPV6_PREFIX);
                                }
                                break;
@@ -529,14 +529,14 @@ static bool pass2_fixup_map(fr_cond_t *c, vp_tmpl_rules_t const *rules)
                        switch (cast->type) {
                        case FR_TYPE_IPV4_ADDR:
                                if (strchr(c->data.map->rhs->name, '/') != NULL) {
-                                       c->cast = cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal),
+                                       c->cast = cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()),
                                                                                   FR_CAST_BASE + FR_TYPE_IPV4_PREFIX);
                                }
                                break;
 
                        case FR_TYPE_IPV6_ADDR:
                                if (strchr(c->data.map->rhs->name, '/') != NULL) {
-                                       c->cast = cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal),
+                                       c->cast = cast = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()),
                                                                                   FR_CAST_BASE + FR_TYPE_IPV6_PREFIX);
                                }
                                break;
@@ -3056,7 +3056,7 @@ static unlang_t *compile_call(unlang_t *parent, unlang_compile_t *unlang_ctx, CO
         *      The dictionaries are not compatible, forbid it.
         */
        dict = virtual_server_namespace(server);
-       if (dict && (dict != fr_dict_internal) && fr_dict_internal &&
+       if (dict && (dict != fr_dict_internal()) && fr_dict_internal() &&
            unlang_ctx->rules->dict_def && (unlang_ctx->rules->dict_def != dict)) {
                cf_log_err(cs, "Cannot call namespace '%s' from namespaces '%s'",
                           fr_dict_root(dict)->name, fr_dict_root(unlang_ctx->rules->dict_def)->name);
@@ -3185,7 +3185,7 @@ static unlang_t *compile_module(unlang_t *parent, unlang_compile_t *unlang_ctx,
         *      Can't use "chap" in "dhcp".
         */
        if (inst->module->dict && *inst->module->dict && unlang_ctx->rules && unlang_ctx->rules->dict_def &&
-           (unlang_ctx->rules->dict_def != fr_dict_internal) &&
+           (unlang_ctx->rules->dict_def != fr_dict_internal()) &&
            (*inst->module->dict != unlang_ctx->rules->dict_def)) {
                cf_log_err(ci, "The \"%s\" module can only used with 'namespace = %s'.  It cannot be used with 'namespace = %s'.",
                           inst->module->name,
index bbb775b1e93c03cd1c41427c9bba9c6f73b4f6a3..a271722cc249afabc83e328cf1d2f851df12f3e6 100644 (file)
@@ -106,7 +106,6 @@ enum {
 #define da_is_length_field(_da) ((_da)->flags.extra && ((_da)->flags.subtype == FLAG_LENGTH_UINT16))
 
 extern const size_t dict_attr_sizes[FR_TYPE_MAX + 1][2];
-extern fr_dict_t *fr_dict_internal;
 
 /** Dictionary attribute
  */
@@ -248,10 +247,10 @@ extern bool const fr_dict_non_data_types[FR_TYPE_MAX + 1];
 int                    fr_dict_attr_add(fr_dict_t *dict, fr_dict_attr_t const *parent, char const *name, int attr,
                                         fr_type_t type, fr_dict_attr_flags_t const *flags) CC_HINT(nonnull(1,2,3));
 
-int                    fr_dict_enum_add_name(fr_dict_attr_t const *da, char const *name,
-                                              fr_value_box_t const *value, bool coerce, bool replace);
+int                    fr_dict_enum_add_name(fr_dict_attr_t *da, char const *name,
+                                             fr_value_box_t const *value, bool coerce, bool replace);
 
-int                    fr_dict_enum_add_name_next(fr_dict_attr_t const *da, char const *name) CC_HINT(nonnull);
+int                    fr_dict_enum_add_name_next(fr_dict_attr_t *da, char const *name) CC_HINT(nonnull);
 
 int                    fr_dict_str_to_argv(char *str, char **argv, int max_argc);
 /** @} */
@@ -296,7 +295,7 @@ int                 fr_dict_oid_component(unsigned int *out, char const **oid);
 size_t                 fr_dict_print_attr_oid(size_t *need, char *buffer, size_t outlen,
                                               fr_dict_attr_t const *ancestor, fr_dict_attr_t const *da);
 
-ssize_t                        fr_dict_attr_by_oid(fr_dict_t *dict, fr_dict_attr_t const **parent,
+ssize_t                        fr_dict_attr_by_oid(fr_dict_t const *dict, fr_dict_attr_t const **parent,
                                            unsigned int *attr, char const *oid) CC_HINT(nonnull);
 /** @} */
 
@@ -308,13 +307,13 @@ fr_dict_attr_t const      *fr_dict_root(fr_dict_t const *dict);
 
 ssize_t                        fr_dict_by_protocol_substr(fr_dict_t const **out, char const *name, fr_dict_t const *dict_def);
 
-fr_dict_t              *fr_dict_by_protocol_name(char const *name);
+fr_dict_t const                *fr_dict_by_protocol_name(char const *name);
 
-fr_dict_t              *fr_dict_by_protocol_num(unsigned int num);
+fr_dict_t const                *fr_dict_by_protocol_num(unsigned int num);
 
-fr_dict_t              *fr_dict_by_da(fr_dict_attr_t const *da);
+fr_dict_t const                *fr_dict_by_da(fr_dict_attr_t const *da);
 
-fr_dict_t              *fr_dict_by_attr_name(fr_dict_attr_t const **found, char const *name);
+fr_dict_t const                *fr_dict_by_attr_name(fr_dict_attr_t const **found, char const *name);
 
 /** Return true if this attribute is parented directly off the dictionary root
  *
@@ -422,15 +421,24 @@ void                      fr_dict_free(fr_dict_t **dict);
 
 /** @} */
 
-/** @name Initialisation
+/** @name Global dictionary management
  *
  * @{
  */
- int                   fr_dict_global_init(TALLOC_CTX *ctx, char const *dict_dir);
+int                    fr_dict_global_init(TALLOC_CTX *ctx, char const *dict_dir);
 
- int                   fr_dict_dir_set(char const *dict_dir);
+int                    fr_dict_global_dir_set(char const *dict_dir);
+
+void                   fr_dict_global_read_only(void);
+
+char const             *fr_dict_global_dir(void);
 
 fr_dict_t              *fr_dict_unconst(fr_dict_t const *dict);
+
+fr_dict_attr_t         *fr_dict_attr_unconst(fr_dict_attr_t const *da);
+
+fr_dict_t const                *fr_dict_internal(void);
+
 /** @} */
 
 /** @name Dictionary testing and validation
index 1659bff8c5f59553e19d527637db9e95156140f0..c14c92e7b3897e22162d57206b7ee3d79a56f523 100644 (file)
@@ -41,7 +41,7 @@ extern "C" {
 #define INTERNAL_IF_NULL(_dict, _ret) \
        do { \
                if (!(_dict)) { \
-                       _dict = fr_dict_internal; \
+                       _dict = dict_gctx ? dict_gctx->internal : NULL; \
                        if (unlikely(!(_dict))) { \
                                fr_strerror_printf("No dictionaries available for attribute resolution"); \
                                return (_ret); \
@@ -58,6 +58,8 @@ extern "C" {
  * There would also be conflicts for DHCP(v6)/RADIUS attributes etc...
  */
 struct fr_dict {
+       bool                    read_only;              //!< If true, disallow modifications.
+
        bool                    in_protocol_by_name;    //!< Whether the dictionary has been inserted into the
                                                        ///< protocol_by_name hash.
        bool                    in_protocol_by_num;     //!< Whether the dictionary has been inserted into the
@@ -93,9 +95,30 @@ struct fr_dict {
        fr_dict_protocol_t const *proto;                //!< protocol-specific validation functions
 };
 
-extern bool dict_initialised;
-extern char *dict_dir_default;
-extern TALLOC_CTX *dict_ctx;
+typedef struct {
+       bool                    read_only;
+       char                    *dict_dir_default;      //!< The default location for loading dictionaries if one
+                                                       ///< wasn't provided.
+
+       dl_loader_t             *dict_loader;           //!< for protocol validation
+
+       fr_hash_table_t         *protocol_by_name;      //!< Hash containing names of all the
+                                                       ///< registered protocols.
+       fr_hash_table_t         *protocol_by_num;       //!< Hash containing numbers of all the
+                                                       ///< registered protocols.
+
+       /** Magic internal dictionary
+        *
+        * Internal dictionary is checked in addition to the protocol dictionary
+        * when resolving attribute names.
+        *
+        * This is because internal attributes are valid for every
+        * protocol.
+        */
+       fr_dict_t               *internal;
+} dict_gctx_t;
+
+extern dict_gctx_t *dict_gctx;
 
 extern fr_table_num_ordered_t const date_precision_table[];
 extern size_t date_precision_table_len;
@@ -147,6 +170,17 @@ bool                       dict_attr_fields_valid(fr_dict_t *dict, fr_dict_attr_t const *parent,
                                               char const *name, int *attr, fr_type_t type,
                                               fr_dict_attr_flags_t *flags);
 
+fr_dict_attr_t         *dict_attr_by_name(fr_dict_t const *dict, char const *name);
+
+fr_dict_attr_t         *dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr);
+
+fr_dict_t              *dict_by_protocol_name(char const *name);
+
+fr_dict_t              *dict_by_protocol_num(unsigned int num);
+
+fr_dict_t              *dict_by_da(fr_dict_attr_t const *da);
+
+fr_dict_t              *dict_by_attr_name(fr_dict_attr_t const **found, char const *name);
 
 #ifdef __cplusplus
 }
index 4481407acdfbb7323a415401bd5a790ee37305cc..6a36b63b204a897a66431db89891438711cdef6f 100644 (file)
@@ -82,9 +82,9 @@ typedef struct {
        dict_tokenize_frame_t   stack[MAX_STACK];       //!< stack of attributes to track
        int                     stack_depth;            //!< points to the last used stack frame
 
-       fr_dict_attr_t const    *value_attr;            //!< Cache of last attribute to speed up
+       fr_dict_attr_t          *value_attr;            //!< Cache of last attribute to speed up
                                                        ///< value processing.
-       fr_dict_attr_t const    *relative_attr;         //!< for ".82" instead of "1.2.3.82".
+       fr_dict_attr_t          *relative_attr;         //!< for ".82" instead of "1.2.3.82".
                                                        ///< only for parents of type "tlv"
 
        TALLOC_CTX              *fixup_pool;            //!< Temporary pool for fixups, reduces holes
@@ -447,7 +447,7 @@ static int dict_process_flag_field(dict_tokenize_ctx_t *ctx, char *name, fr_type
 }
 
 
-static int dict_ctx_push(dict_tokenize_ctx_t *ctx, fr_dict_attr_t const *da)
+static int dict_gctx_push(dict_tokenize_ctx_t *ctx, fr_dict_attr_t const *da)
 {
        if ((ctx->stack_depth + 1) >= MAX_STACK) {
                fr_strerror_printf_push("Attribute definitions are nested too deep.");
@@ -465,7 +465,7 @@ static int dict_ctx_push(dict_tokenize_ctx_t *ctx, fr_dict_attr_t const *da)
        return 0;
 }
 
-static fr_dict_attr_t const *dict_ctx_unwind(dict_tokenize_ctx_t *ctx)
+static fr_dict_attr_t const *dict_gctx_unwind(dict_tokenize_ctx_t *ctx)
 {
        while ((ctx->stack_depth > 0) &&
               (ctx->stack[ctx->stack_depth].nest == FR_TYPE_INVALID)) {
@@ -519,7 +519,7 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *ctx, char **argv, in
         *      unwind the stack to match.
         */
        if (argv[1][0] != '.') {
-               parent = dict_ctx_unwind(ctx);
+               parent = dict_gctx_unwind(ctx);
 
                /*
                 *      Allow '0xff00' as attribute numbers, but only
@@ -603,7 +603,7 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *ctx, char **argv, in
                fr_dict_t const *dict;
                char *p;
 
-               da = fr_dict_attr_child_by_num(parent, attr);
+               da = dict_attr_child_by_num(parent, attr);
                if (!da) {
                        fr_strerror_printf("Failed to find attribute '%s' we just added.", argv[0]);
                        return -1;
@@ -620,7 +620,7 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *ctx, char **argv, in
                        goto check;
                }
 
-               da = fr_dict_attr_by_name(ctx->dict, ref);
+               da = dict_attr_by_name(ctx->dict, ref);
                if (da) {
                        dict = ctx->dict;
                        goto check;
@@ -681,7 +681,7 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *ctx, char **argv, in
                        /*
                         *      Look up the attribute.
                         */
-                       da = fr_dict_attr_by_name(dict, ref + slen);
+                       da = dict_attr_by_name(dict, ref + slen);
                        if (!da) {
                                fr_strerror_printf("protocol loaded, but no attribute '%s'", ref + slen);
                                talloc_free(ref);
@@ -707,21 +707,21 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *ctx, char **argv, in
         *      *canonical* previous attribute, and not any potential
         *      duplicate which was just added.
         */
-       if (set_relative_attr) ctx->relative_attr = fr_dict_attr_child_by_num(parent, attr);
+       if (set_relative_attr) ctx->relative_attr = dict_attr_child_by_num(parent, attr);
 
        /*
         *      Adding an attribute of type 'struct' is an implicit
         *      BEGIN-STRUCT.
         */
        if (type == FR_TYPE_STRUCT) {
-               fr_dict_attr_t const *da = fr_dict_attr_child_by_num(parent, attr);
+               fr_dict_attr_t const *da = dict_attr_child_by_num(parent, attr);
 
                if (!da) {
                        fr_strerror_printf("Failed adding attribute %s", argv[0]);
                        return -1;
                }
 
-               if (dict_ctx_push(ctx, da) < 0) return -1;
+               if (dict_gctx_push(ctx, da) < 0) return -1;
        }
 
        return 0;
@@ -771,7 +771,11 @@ static int dict_read_process_member(dict_tokenize_ctx_t *ctx, char **argv, int a
        /*
         *      Add the MEMBER to the parent.
         */
-       if (fr_dict_attr_add(ctx->dict, ctx->stack[ctx->stack_depth].da, argv[0], ++ctx->stack[ctx->stack_depth].member_num, type, &flags) < 0) return -1;
+       if (fr_dict_attr_add(ctx->dict,
+                            ctx->stack[ctx->stack_depth].da,
+                            argv[0],
+                            ++ctx->stack[ctx->stack_depth].member_num,
+                            type, &flags) < 0) return -1;
 
        /*
         *      A 'struct' can have a MEMBER of type 'tlv', but ONLY
@@ -782,8 +786,9 @@ static int dict_read_process_member(dict_tokenize_ctx_t *ctx, char **argv, int a
         *      to them.
         */
        if (type == FR_TYPE_TLV) {
-               ctx->relative_attr = fr_dict_attr_child_by_num(ctx->stack[ctx->stack_depth].da, ctx->stack[ctx->stack_depth].member_num);
-               if (dict_ctx_push(ctx, ctx->relative_attr) < 0) return -1;
+               ctx->relative_attr = dict_attr_child_by_num(ctx->stack[ctx->stack_depth].da,
+                                                            ctx->stack[ctx->stack_depth].member_num);
+               if (dict_gctx_push(ctx, ctx->relative_attr) < 0) return -1;
 
        } else {
                fr_dict_attr_t *mutable;
@@ -812,8 +817,8 @@ static int dict_read_process_member(dict_tokenize_ctx_t *ctx, char **argv, int a
  */
 static int dict_read_process_value(dict_tokenize_ctx_t *ctx, char **argv, int argc)
 {
-       fr_dict_attr_t const            *da;
-       fr_value_box_t                  value;
+       fr_dict_attr_t          *da;
+       fr_value_box_t          value;
 
        if (argc != 3) {
                fr_strerror_printf("Invalid VALUE syntax");
@@ -826,7 +831,7 @@ static int dict_read_process_value(dict_tokenize_ctx_t *ctx, char **argv, int ar
         *      caching the last attribute for a VALUE.
         */
        if (!ctx->value_attr || (strcasecmp(argv[0], ctx->value_attr->name) != 0)) {
-               ctx->value_attr = fr_dict_attr_by_name(ctx->dict, argv[0]);
+               ctx->value_attr = dict_attr_by_name(ctx->dict, argv[0]);
        }
        da = ctx->value_attr;
 
@@ -956,7 +961,7 @@ static int dict_read_process_struct(dict_tokenize_ctx_t *ctx, char **argv, int a
        /*
         *      This SHOULD be the "key" field.
         */
-       parent = fr_dict_attr_by_name(ctx->dict, key_attr);
+       parent = dict_attr_by_name(ctx->dict, key_attr);
        if (!parent) {
                fr_strerror_printf("Unknown attribute '%s'", key_attr);
                return -1;
@@ -1066,14 +1071,14 @@ get_value:
         */
        if (fr_dict_attr_add(ctx->dict, parent, argv[1], attr, FR_TYPE_STRUCT, &flags) < 0) return -1;
 
-       da = fr_dict_attr_by_name(ctx->dict, argv[1]);
+       da = dict_attr_by_name(ctx->dict, argv[1]);
        if (!da) return -1;
 
        /*
         *      A STRUCT definition is an implicit BEGIN-STRUCT.
         */
        ctx->relative_attr = NULL;
-       if (dict_ctx_push(ctx, da) < 0) return -1;
+       if (dict_gctx_push(ctx, da) < 0) return -1;
 
        return 0;
 }
@@ -1200,7 +1205,7 @@ static int dict_read_process_protocol(char **argv, int argc)
        /*
         *      Cross check name / number.
         */
-       dict = fr_dict_by_protocol_name(argv[0]);
+       dict = dict_by_protocol_name(argv[0]);
        if (dict) {
 #ifdef __clang_analyzer__
                if (!dict->root) return -1;
@@ -1212,7 +1217,7 @@ static int dict_read_process_protocol(char **argv, int argc)
                        return -1;
                }
 
-       } else if ((dict = fr_dict_by_protocol_num(value)) != NULL) {
+       } else if ((dict = dict_by_protocol_num(value)) != NULL) {
 #ifdef __clang_analyzer__
                if (!dict->root || !dict->root->name || !argv[0]) return -1;
 #endif
@@ -1335,7 +1340,7 @@ static int fr_dict_finalise(dict_tokenize_ctx_t *ctx)
         *      before the attributes they reference.
         */
        if (ctx->enum_fixup) {
-               fr_dict_attr_t const *da;
+               fr_dict_attr_t *da;
                dict_enum_fixup_t *this, *next;
 
                for (this = ctx->enum_fixup; this != NULL; this = next) {
@@ -1344,7 +1349,7 @@ static int fr_dict_finalise(dict_tokenize_ctx_t *ctx)
                        int             ret;
 
                        next = this->next;
-                       da = fr_dict_attr_by_name(ctx->dict, this->attribute);
+                       da = dict_attr_by_name(ctx->dict, this->attribute);
                        if (!da) {
                                fr_strerror_printf("No ATTRIBUTE '%s' defined for VALUE '%s' at %s[%d]",
                                                   this->attribute, this->name, this->filename, this->line);
@@ -1411,7 +1416,7 @@ static int fr_dict_finalise(dict_tokenize_ctx_t *ctx)
                        char *p;
                        ssize_t slen;
 
-                       da = fr_dict_attr_by_name(ctx->dict, this->ref);
+                       da = dict_attr_by_name(ctx->dict, this->ref);
                        if (da) {
                                dict = ctx->dict;
                                goto check;
@@ -1474,7 +1479,7 @@ static int fr_dict_finalise(dict_tokenize_ctx_t *ctx)
                        /*
                         *      Look up the attribute.
                         */
-                       da = fr_dict_attr_by_name(dict, this->ref + slen + 1);
+                       da = dict_attr_by_name(dict, this->ref + slen + 1);
                        if (!da) {
                                fr_strerror_printf("No such attribute '%s' in reference at %s[%d]",
                                                   this->ref + slen + 1, this->filename, this->line);
@@ -1825,12 +1830,12 @@ static int _dict_from_file(dict_tokenize_ctx_t *ctx,
                         *      dictionary, then we don't allow BEGIN-PROTOCOL
                         *      statements.
                         */
-                       if (ctx->dict != fr_dict_internal) {
+                       if (ctx->dict != dict_gctx->internal) {
                                fr_strerror_printf_push("Nested BEGIN-PROTOCOL statements are not allowed");
                                goto error;
                        }
 
-                       found = fr_dict_by_protocol_name(argv[1]);
+                       found = dict_by_protocol_name(argv[1]);
                        if (!found) {
                                fr_strerror_printf("Unknown protocol '%s'", argv[1]);
                                goto error;
@@ -1852,7 +1857,7 @@ static int _dict_from_file(dict_tokenize_ctx_t *ctx,
 
                        ctx->dict = found;
 
-                       if (dict_ctx_push(ctx, ctx->dict->root) < 0) goto error;
+                       if (dict_gctx_push(ctx, ctx->dict->root) < 0) goto error;
                        ctx->stack[ctx->stack_depth].nest = FR_TYPE_MAX;
                        continue;
                }
@@ -1868,7 +1873,7 @@ static int _dict_from_file(dict_tokenize_ctx_t *ctx,
                                goto error;
                        }
 
-                       found = fr_dict_by_protocol_name(argv[1]);
+                       found = dict_by_protocol_name(argv[1]);
                        if (!found) {
                                fr_strerror_printf("END-PROTOCOL %s does not refer to a valid protocol", argv[1]);
                                goto error;
@@ -1933,7 +1938,7 @@ static int _dict_from_file(dict_tokenize_ctx_t *ctx,
                                goto error;
                        }
 
-                       da = fr_dict_attr_by_name(ctx->dict, argv[1]);
+                       da = dict_attr_by_name(ctx->dict, argv[1]);
                        if (!da) {
                                fr_strerror_printf_push("Unknown attribute '%s'", argv[1]);
                                goto error;
@@ -1954,7 +1959,7 @@ static int _dict_from_file(dict_tokenize_ctx_t *ctx,
                                goto error;
                        }
 
-                       if (dict_ctx_push(ctx, da) < 0) goto error;
+                       if (dict_gctx_push(ctx, da) < 0) goto error;
                        ctx->stack[ctx->stack_depth].nest = FR_TYPE_TLV;
                        continue;
                } /* BEGIN-TLV */
@@ -1968,7 +1973,7 @@ static int _dict_from_file(dict_tokenize_ctx_t *ctx,
                                goto error;
                        }
 
-                       da = fr_dict_attr_by_name(ctx->dict, argv[1]);
+                       da = dict_attr_by_name(ctx->dict, argv[1]);
                        if (!da) {
                                fr_strerror_printf_push("Unknown attribute '%s'", argv[1]);
                                goto error;
@@ -2034,7 +2039,7 @@ static int _dict_from_file(dict_tokenize_ctx_t *ctx,
                                }
 
                                p = argv[2] + 7;
-                               da = fr_dict_attr_by_name(ctx->dict, p);
+                               da = dict_attr_by_name(ctx->dict, p);
                                if (!da) {
                                        fr_strerror_printf_push("Invalid format for BEGIN-VENDOR: Unknown "
                                                                "parent attribute '%s'", p);
@@ -2066,7 +2071,7 @@ static int _dict_from_file(dict_tokenize_ctx_t *ctx,
                                /*
                                 *      Check that the protocol-specific VSA parent exists.
                                 */
-                               vsa_da = fr_dict_attr_child_by_num(ctx->stack[ctx->stack_depth].da, ctx->dict->vsa_parent);
+                               vsa_da = dict_attr_child_by_num(ctx->stack[ctx->stack_depth].da, ctx->dict->vsa_parent);
                                if (!vsa_da) {
                                        fr_strerror_printf_push("Failed finding VSA parent for Vendor %s",
                                                                vendor->name);
@@ -2078,7 +2083,7 @@ static int _dict_from_file(dict_tokenize_ctx_t *ctx,
                         *      Create a VENDOR attribute on the fly, either in the context
                         *      of the VSA (26) attribute.
                         */
-                       vendor_da = fr_dict_attr_child_by_num(vsa_da, vendor->pen);
+                       vendor_da = dict_attr_child_by_num(vsa_da, vendor->pen);
                        if (!vendor_da) {
                                memset(&flags, 0, sizeof(flags));
 
@@ -2114,7 +2119,7 @@ static int _dict_from_file(dict_tokenize_ctx_t *ctx,
                                vendor_da = new;
                        }
 
-                       if (dict_ctx_push(ctx, vendor_da) < 0) goto error;
+                       if (dict_gctx_push(ctx, vendor_da) < 0) goto error;
                        ctx->stack[ctx->stack_depth].nest = FR_TYPE_VENDOR;
                        continue;
                } /* BEGIN-VENDOR */
@@ -2228,12 +2233,11 @@ int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir)
 {
        fr_dict_t               *dict;
        char                    *dict_path = NULL;
-       char                    *tmp;
        size_t                  i;
        fr_dict_attr_flags_t    flags = { .internal = true };
        char                    *type_name;
 
-       if (unlikely(!dict_initialised)) {
+       if (unlikely(!dict_gctx)) {
                fr_strerror_printf("fr_dict_global_init() must be called before loading dictionary files");
                return -1;
        }
@@ -2241,19 +2245,20 @@ int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir)
        /*
         *      Increase the reference count of the internal dictionary.
         */
-       if (fr_dict_internal) {
-                talloc_increase_ref_count(fr_dict_internal);
-                *out = fr_dict_internal;
+       if (dict_gctx->internal) {
+                talloc_increase_ref_count(dict_gctx->internal);
+                *out = dict_gctx->internal;
                 return 0;
        }
 
-       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_path = dict_subdir ?
+                   talloc_asprintf(NULL, "%s%c%s", fr_dict_global_dir(), FR_DIR_SEP, dict_subdir) :
+                   talloc_strdup(NULL, fr_dict_global_dir());
 
-       dict = dict_alloc(dict_ctx);
+       dict = dict_alloc(dict_gctx);
        if (!dict) {
        error:
-               if (!fr_dict_internal) talloc_free(dict);
+               if (!dict_gctx->internal) talloc_free(dict);
                talloc_free(dict_path);
                return -1;
        }
@@ -2303,7 +2308,7 @@ int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir)
        talloc_free(dict_path);
 
        *out = dict;
-       if (!fr_dict_internal) fr_dict_internal = dict;
+       if (!dict_gctx->internal) dict_gctx->internal = dict;
 
        return 0;
 }
@@ -2325,12 +2330,12 @@ int fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char co
        char            *dict_dir = NULL;
        fr_dict_t       *dict;
 
-       if (unlikely(!dict_initialised)) {
+       if (unlikely(!dict_gctx)) {
                fr_strerror_printf("fr_dict_global_init() must be called before loading dictionary files");
                return -1;
        }
 
-       if (unlikely(!fr_dict_internal)) {
+       if (unlikely(!dict_gctx->internal)) {
                fr_strerror_printf("Internal dictionary must be initialised before loading protocol dictionaries");
                return -1;
        }
@@ -2339,7 +2344,7 @@ int fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char co
         *      Increment the reference count if the dictionary
         *      has already been loaded and return that.
         */
-       dict = fr_dict_by_protocol_name(proto_name);
+       dict = dict_by_protocol_name(proto_name);
        if (dict && dict->autoloaded) {
                talloc_increase_ref_count(dict);
                *out = dict;
@@ -2347,9 +2352,9 @@ int fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char co
        }
 
        if (!proto_dir) {
-               dict_dir = talloc_asprintf(NULL, "%s%c%s", dict_dir_default, FR_DIR_SEP, proto_name);
+               dict_dir = talloc_asprintf(NULL, "%s%c%s", fr_dict_global_dir(), FR_DIR_SEP, proto_name);
        } else {
-               dict_dir = talloc_asprintf(NULL, "%s%c%s", dict_dir_default, FR_DIR_SEP, proto_dir);
+               dict_dir = talloc_asprintf(NULL, "%s%c%s", fr_dict_global_dir(), FR_DIR_SEP, proto_dir);
        }
 
        /*
@@ -2361,7 +2366,7 @@ int fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char co
         *      for multiple protocols, which'll probably be useful
         *      at some point.
         */
-       if (dict_from_file(fr_dict_internal, dict_dir, FR_DICTIONARY_FILE, NULL, 0) < 0) {
+       if (dict_from_file(dict_gctx->internal, dict_dir, FR_DICTIONARY_FILE, NULL, 0) < 0) {
        error:
                talloc_free(dict_dir);
                return -1;
@@ -2370,7 +2375,7 @@ int fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char co
        /*
         *      Check the dictionary actually defined the protocol
         */
-       dict = fr_dict_by_protocol_name(proto_name);
+       dict = dict_by_protocol_name(proto_name);
        if (!dict) {
                fr_strerror_printf("Dictionary \"%s\" missing \"BEGIN-PROTOCOL %s\" declaration", dict_dir, proto_name);
                goto error;
@@ -2405,6 +2410,11 @@ int fr_dict_read(fr_dict_t *dict, char const *dir, char const *filename)
 {
        INTERNAL_IF_NULL(dict, -1);
 
+       if (unlikely(dict->read_only)) {
+               fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
+               return -1;
+       }
+
        if (!dict->attributes_by_name) {
                fr_strerror_printf("%s: Must initialise dictionary before calling fr_dict_read()", __FUNCTION__);
                return -1;
@@ -2447,7 +2457,7 @@ int fr_dict_parse_str(fr_dict_t *dict, char *buf, fr_dict_attr_t const *parent)
                        return -1;
                }
 
-               if (!fr_dict_attr_by_name(dict, argv[1])) {
+               if (!dict_attr_by_name(dict, argv[1])) {
                        fr_strerror_printf("Attribute \"%s\" does not exist in dictionary \"%s\"",
                                           argv[1], dict->root->name);
                        goto error;
index b83a8bc72ec527dacadb5613cbf2fc36a820e4d7..00f56b3b192ecfae2c340afc50609913813dde32 100644 (file)
@@ -83,6 +83,11 @@ fr_dict_attr_t const *fr_dict_unknown_add(fr_dict_t *dict, fr_dict_attr_t const
        fr_dict_attr_t const *parent;
        fr_dict_attr_flags_t flags;
 
+       if (unlikely(dict->read_only)) {
+               fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
+               return -1;
+       }
+
        da = fr_dict_attr_by_name(dict, old->name);
        if (da) return da;
 
@@ -316,7 +321,7 @@ fr_dict_attr_t const *fr_dict_unknown_afrom_fields(TALLOC_CTX *ctx, fr_dict_attr
         *      If so, use the pre-defined name instead of an unknown
         *      one.!
         */
-       da = fr_dict_attr_by_name(fr_dict_by_da(parent), n->name);
+       da = fr_dict_attr_by_name(dict_by_da(parent), n->name);
        if (da) {
                fr_dict_unknown_free(&parent);
                parent = n;
index ef51dd381015c226b105480ff6b22ea6d5d67675..12fff6b1b4bc48bf755180fd351c7b19ee18c1ae 100644 (file)
@@ -36,15 +36,7 @@ RCSID("$Id$")
 #  include <sys/stat.h>
 #endif
 
-bool                   dict_initialised = false;
-char                   *dict_dir_default;              //!< The default location for loading dictionaries if one
-                                                       ///< 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.
+dict_gctx_t *dict_gctx;        //!< Top level structure containing global dictionary state.
 
 fr_table_num_ordered_t const date_precision_table[] = {
        { "microseconds",       FR_TIME_RES_USEC },
@@ -73,16 +65,6 @@ static fr_table_num_ordered_t const eap_aka_sim_subtype_table[] = {
 };
 static size_t eap_aka_sim_subtype_table_len = NUM_ELEMENTS(eap_aka_sim_subtype_table);
 
-/** Magic internal dictionary
- *
- * Internal dictionary is checked in addition to the protocol dictionary
- * when resolving attribute names.
- *
- * This is because internal attributes are valid for every
- * protocol.
- */
-fr_dict_t      *fr_dict_internal = NULL;       //!< Internal server dictionary.
-
 /** Map data types to min / max data sizes
  */
 size_t const dict_attr_sizes[FR_TYPE_MAX + 1][2] = {
@@ -490,7 +472,6 @@ static fr_dict_attr_t *dict_attr_acopy(TALLOC_CTX *ctx, fr_dict_attr_t const *in
        return n;
 }
 
-
 /** Add a protocol to the global protocol table
  *
  * Inserts a protocol into the global protocol table.  Uses the root attributes
@@ -505,10 +486,10 @@ int dict_protocol_add(fr_dict_t *dict)
 {
        if (!dict->root) return -1;     /* Should always have root */
 
-       if (!fr_hash_table_insert(protocol_by_name, dict)) {
+       if (!fr_hash_table_insert(dict_gctx->protocol_by_name, dict)) {
                fr_dict_t *old_proto;
 
-               old_proto = fr_hash_table_finddata(protocol_by_name, dict);
+               old_proto = fr_hash_table_finddata(dict_gctx->protocol_by_name, dict);
                if (!old_proto) {
                        fr_strerror_printf("%s: Failed inserting protocol name %s", __FUNCTION__, dict->root->name);
                        return -1;
@@ -524,7 +505,7 @@ int dict_protocol_add(fr_dict_t *dict)
        }
        dict->in_protocol_by_name = true;
 
-       if (!fr_hash_table_insert(protocol_by_num, dict)) {
+       if (!fr_hash_table_insert(dict_gctx->protocol_by_num, dict)) {
                fr_strerror_printf("%s: Duplicate protocol number %i", __FUNCTION__, dict->root->attr);
                return -1;
        }
@@ -848,7 +829,6 @@ int dict_attr_add_by_name(fr_dict_t *dict, fr_dict_attr_t *da)
        return 0;
 }
 
-
 /** Add an attribute to the dictionary
  *
  * @param[in] dict             of protocol context we're operating in.
@@ -870,6 +850,11 @@ int fr_dict_attr_add(fr_dict_t *dict, fr_dict_attr_t const *parent,
        fr_dict_attr_t          *mutable;
        fr_dict_attr_flags_t    our_flags = *flags;
 
+       if (unlikely(dict->read_only)) {
+               fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
+               return -1;
+       }
+
        /*
         *      Check that the definition is valid.
         */
@@ -957,9 +942,9 @@ int fr_dict_attr_add(fr_dict_t *dict, fr_dict_attr_t const *parent,
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_dict_enum_add_name(fr_dict_attr_t const *da, char const *name,
-                          fr_value_box_t const *value,
-                          bool coerce, bool takes_precedence)
+int fr_dict_enum_add_name(fr_dict_attr_t *da, char const *name,
+                         fr_value_box_t const *value,
+                         bool coerce, bool takes_precedence)
 {
        size_t                  len;
        fr_dict_t               *dict;
@@ -982,7 +967,7 @@ int fr_dict_enum_add_name(fr_dict_attr_t const *da, char const *name,
                return -1;
        }
 
-       dict = fr_dict_by_da(da);
+       dict = dict_by_da(da);
 
        enumv = talloc_zero(dict->pool, fr_dict_enum_t);
        if (!enumv) {
@@ -1083,7 +1068,7 @@ int fr_dict_enum_add_name(fr_dict_attr_t const *da, char const *name,
 /** Add an name to an integer attribute hashing the name for the integer value
  *
  */
-int fr_dict_enum_add_name_next(fr_dict_attr_t const *da, char const *name)
+int fr_dict_enum_add_name_next(fr_dict_attr_t *da, char const *name)
 {
        fr_value_box_t  v = {
                                .type = da->type
@@ -1253,7 +1238,7 @@ int fr_dict_oid_component(unsigned int *out, char const **oid)
  *     - > 0 on success (number of bytes parsed).
  *     - <= 0 on parse error (negative offset of parse error).
  */
-ssize_t fr_dict_attr_by_oid(fr_dict_t *dict, fr_dict_attr_t const **parent, unsigned int *attr, char const *oid)
+ssize_t fr_dict_attr_by_oid(fr_dict_t const *dict, fr_dict_attr_t const **parent, unsigned int *attr, char const *oid)
 {
        char const              *p = oid;
        unsigned int            num = 0;
@@ -1310,7 +1295,7 @@ ssize_t fr_dict_attr_by_oid(fr_dict_t *dict, fr_dict_attr_t const **parent, unsi
                fr_dict_attr_t const *child;
                p++;
 
-               child = fr_dict_attr_child_by_num(*parent, num);
+               child = dict_attr_child_by_num(*parent, num);
                if (!child) {
                        fr_strerror_printf("Unknown attribute '%i' in OID string \"%s\" for parent %s",
                                           num, oid, (*parent)->name);
@@ -1349,7 +1334,7 @@ ssize_t fr_dict_attr_by_oid(fr_dict_t *dict, fr_dict_attr_t const **parent, unsi
  */
 fr_dict_attr_t const *fr_dict_root(fr_dict_t const *dict)
 {
-       if (!dict) return fr_dict_internal->root;       /* Remove me when dictionaries are done */
+       if (!dict) return dict_gctx->internal->root;    /* Remove me when dictionaries are done */
        return dict->root;
 }
 
@@ -1372,7 +1357,7 @@ ssize_t fr_dict_by_protocol_substr(fr_dict_t const **out, char const *name, fr_d
        char const              *p;
        size_t                  len;
 
-       if (!protocol_by_name || !name || !*name || !out) return 0;
+       if (!dict_gctx || !name || !*name || !out) return 0;
 
        memset(&root, 0, sizeof(root));
 
@@ -1403,7 +1388,7 @@ ssize_t fr_dict_by_protocol_substr(fr_dict_t const **out, char const *name, fr_d
                *out = NULL;
                return 0;
        }
-       dict = fr_hash_table_finddata(protocol_by_name, &(fr_dict_t){ .root = &root });
+       dict = fr_hash_table_finddata(dict_gctx->protocol_by_name, &(fr_dict_t){ .root = &root });
        talloc_const_free(root.name);
 
        if (!dict) {
@@ -1416,47 +1401,41 @@ ssize_t fr_dict_by_protocol_substr(fr_dict_t const **out, char const *name, fr_d
        return p - name;
 }
 
-/** Lookup a protocol by its name
+/**Internal version of #fr_dict_by_protocol_name
  *
- * @param[in] name of the protocol to locate.
- * @return
- *     - Attribute matching name.
- *     - NULL if no matching protocolibute could be found.
+ * @note For internal use by the dictionary API only.
+ *
+ * @copybrief fr_dict_by_protocol_name.
  */
-fr_dict_t *fr_dict_by_protocol_name(char const *name)
+fr_dict_t *dict_by_protocol_name(char const *name)
 {
-       if (!protocol_by_name || !name) return NULL;
+       if (!dict_gctx || !name) return NULL;
 
-       return fr_hash_table_finddata(protocol_by_name, &(fr_dict_t){ .root = &(fr_dict_attr_t){ .name = name } });
+       return fr_hash_table_finddata(dict_gctx->protocol_by_name,
+                                     &(fr_dict_t){ .root = &(fr_dict_attr_t){ .name = name } });
 }
 
-/** Lookup a protocol by its number.
+/** Internal version of #fr_dict_by_protocol_num
  *
- * Returns the #fr_dict_t belonging to the protocol with the specified number
- * if any have been registered.
+ * @note For internal use by the dictionary API only.
  *
- * @param[in] num to search for.
- * @return dictionary representing the protocol (if it exists).
+ * @copybrief fr_dict_by_protocol_num.
  */
-fr_dict_t *fr_dict_by_protocol_num(unsigned int num)
+fr_dict_t *dict_by_protocol_num(unsigned int num)
 {
-       if (!protocol_by_num) return NULL;
+       if (!dict_gctx) return NULL;
 
-       return fr_hash_table_finddata(protocol_by_num, &(fr_dict_t) { .root = &(fr_dict_attr_t){ .attr = num } });
+       return fr_hash_table_finddata(dict_gctx->protocol_by_num,
+                                     &(fr_dict_t) { .root = &(fr_dict_attr_t){ .attr = num } });
 }
 
-/** Attempt to locate the protocol dictionary containing an attribute
+/** Internal version of #fr_dict_by_da
  *
- * @note Unlike fr_dict_by_attr_name, doesn't search through all the dictionaries,
- *     just uses the fr_dict_attr_t hierarchy and the talloc hierarchy to locate
- *     the dictionary (much much faster and more scalable).
+ * @note For internal use by the dictionary API only.
  *
- * @param[in] da               To get the containing dictionary for.
- * @return
- *     - The dictionary containing da.
- *     - NULL.
+ * @copybrief fr_dict_by_da
  */
-fr_dict_t *fr_dict_by_da(fr_dict_attr_t const *da)
+fr_dict_t *dict_by_da(fr_dict_attr_t const *da)
 {
        fr_dict_attr_t const *da_p = da;
 
@@ -1511,17 +1490,13 @@ static int _dict_attr_find_in_dicts(void *ctx, void *data)
        return 1;
 }
 
-/** Attempt to locate the protocol dictionary containing an attribute
+/** Internal version of #fr_dict_by_attr_name
  *
- * @note This is O(n) and will only return the first instance of the dictionary.
+ * @note For internal use by the dictionary API only.
  *
- * @param[out] found   the attribute that was resolved from the name. May be NULL.
- * @param[in] name     the name of the attribute.
- * @return
- *     - the dictionary the attribute was found in.
- *     - NULL if an attribute with the specified name wasn't found in any dictionary.
+ * @copybrief fr_dict_by_attr_name
  */
-fr_dict_t *fr_dict_by_attr_name(fr_dict_attr_t const **found, char const *name)
+fr_dict_t *dict_by_attr_name(fr_dict_attr_t const **found, char const *name)
 {
        fr_dict_attr_t          find = {
                                        .name = name
@@ -1535,7 +1510,7 @@ fr_dict_t *fr_dict_by_attr_name(fr_dict_attr_t const **found, char const *name)
 
        if (!name || !*name) return NULL;
 
-       ret = fr_hash_table_walk(protocol_by_name, _dict_attr_find_in_dicts, &search);
+       ret = fr_hash_table_walk(dict_gctx->protocol_by_name, _dict_attr_find_in_dicts, &search);
        if (ret == 0) return NULL;
 
        if (found) *found = search.found_da;
@@ -1543,6 +1518,64 @@ fr_dict_t *fr_dict_by_attr_name(fr_dict_attr_t const **found, char const *name)
        return search.found_dict;
 }
 
+/** Lookup a protocol by its name
+ *
+ * @note For internal use by the dictionary API only.
+ *
+ * @param[in] name of the protocol to locate.
+ * @return
+ *     - Attribute matching name.
+ *     - NULL if no matching protocol could be found.
+ */
+fr_dict_t const *fr_dict_by_protocol_name(char const *name)
+{
+       return dict_by_protocol_name(name);
+}
+
+/** Lookup a protocol by its number
+ *
+ * Returns the #fr_dict_t belonging to the protocol with the specified number
+ * if any have been registered.
+ *
+ * @param[in] num to search for.
+ * @return dictionary representing the protocol (if it exists).
+ */
+fr_dict_t const *fr_dict_by_protocol_num(unsigned int num)
+{
+       return dict_by_protocol_num(num);
+}
+
+/** Attempt to locate the protocol dictionary containing an attribute
+ *
+ * @note Unlike fr_dict_by_attr_name, doesn't search through all the dictionaries,
+ *     just uses the fr_dict_attr_t hierarchy and the talloc hierarchy to locate
+ *     the dictionary (much much faster and more scalable).
+ *
+ * @param[in] da               To get the containing dictionary for.
+ * @return
+ *     - The dictionary containing da.
+ *     - NULL.
+ */
+fr_dict_t const *fr_dict_by_da(fr_dict_attr_t const *da)
+{
+       return dict_by_da(da);
+}
+
+/** Attempt to locate the protocol dictionary containing an attribute
+ *
+ * @note This is O(n) and will only return the first instance of the dictionary.
+ *
+ * @param[out] found   the attribute that was resolved from the name. May be NULL.
+ * @param[in] name     the name of the attribute.
+ * @return
+ *     - the dictionary the attribute was found in.
+ *     - NULL if an attribute with the specified name wasn't found in any dictionary.
+ */
+fr_dict_t const *fr_dict_by_attr_name(fr_dict_attr_t const **found, char const *name)
+{
+       return dict_by_attr_name(found, name);
+}
+
 /** Look up a vendor by one of its child attributes
  *
  * @param[in] da       The vendor attribute.
@@ -1558,7 +1591,7 @@ fr_dict_vendor_t const *fr_dict_vendor_by_da(fr_dict_attr_t const *da)
        dv.pen = fr_dict_vendor_num_by_da(da);
        if (!dv.pen) return NULL;
 
-       dict = fr_dict_by_da(da);
+       dict = dict_by_da(da);
 
        return fr_hash_table_finddata(dict->vendors_by_num, &dv);
 }
@@ -1651,7 +1684,7 @@ fr_dict_attr_t const *fr_dict_vendor_attr_by_num(fr_dict_attr_t const *vendor_ro
                return NULL;
        }
 
-       vendor = fr_dict_attr_child_by_num(vendor_root, vendor_pen);
+       vendor = dict_attr_child_by_num(vendor_root, vendor_pen);
        if (!vendor) {
                fr_strerror_printf("Vendor %i not defined", vendor_pen);
                return NULL;
@@ -1739,6 +1772,19 @@ ssize_t fr_dict_attr_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t cons
        return p - name;
 }
 
+/* Internal version of fr_dict_attr_by_name
+ *
+ */
+fr_dict_attr_t *dict_attr_by_name(fr_dict_t const *dict, char const *name)
+{
+       INTERNAL_IF_NULL(dict, NULL);
+
+       if (!name) return NULL;
+
+       return fr_hash_table_finddata(dict->attributes_by_name, &(fr_dict_attr_t) { .name = name });
+}
+
+
 /** Locate a #fr_dict_attr_t by its name
  *
  * @note Unlike attribute numbers, attribute names are unique to the dictionary.
@@ -1752,11 +1798,7 @@ ssize_t fr_dict_attr_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t cons
  */
 fr_dict_attr_t const *fr_dict_attr_by_name(fr_dict_t const *dict, char const *name)
 {
-       INTERNAL_IF_NULL(dict, NULL);
-
-       if (!name) return NULL;
-
-       return fr_hash_table_finddata(dict->attributes_by_name, &(fr_dict_attr_t) { .name = name });
+       return dict_attr_by_name(dict, name);
 }
 
 /** Locate a qualified #fr_dict_attr_t by its name and a dictionary qualifier
@@ -1844,8 +1886,8 @@ again:
                                 */
                                if (!internal) {
                                        internal = true;
-                                       if (dict_def != fr_dict_internal) {
-                                               dict = fr_dict_internal;
+                                       if (dict_def != dict_gctx->internal) {
+                                               dict = dict_gctx->internal;
                                                goto again;
                                        }
                                }
@@ -1853,10 +1895,10 @@ again:
                                /*
                                 *      Start the iteration over all dictionaries.
                                 */
-                               dict_iter = fr_hash_table_iter_init(protocol_by_num, &iter);
+                               dict_iter = fr_hash_table_iter_init(dict_gctx->protocol_by_num, &iter);
                        } else {
                        redo:
-                               dict_iter = fr_hash_table_iter_next(protocol_by_num, &iter);
+                               dict_iter = fr_hash_table_iter_next(dict_gctx->protocol_by_num, &iter);
                        }
 
                        if (!dict_iter) goto fail;
@@ -1931,7 +1973,7 @@ fr_dict_attr_err_t fr_dict_attr_by_qualified_name(fr_dict_attr_t const **out, fr
  */
 fr_dict_attr_t const *fr_dict_attr_by_type(fr_dict_attr_t const *da, fr_type_t type)
 {
-       return fr_hash_table_finddata(fr_dict_by_da(da)->attributes_combo,
+       return fr_hash_table_finddata(dict_by_da(da)->attributes_combo,
                                      &(fr_dict_attr_t){
                                                .parent = da->parent,
                                                .attr = da->attr,
@@ -1982,15 +2024,10 @@ fr_dict_attr_t const *fr_dict_attr_child_by_da(fr_dict_attr_t const *parent, fr_
        return NULL;
 }
 
-/** Check if a child attribute exists in a parent using an attribute number
+/** Internal version of fr_dict_attr_child_by_num
  *
- * @param[in] parent           to check for child in.
- * @param[in] attr             number to look for.
- * @return
- *     - The child attribute on success.
- *     - NULL if the child attribute does not exist.
  */
-inline fr_dict_attr_t const *fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
+inline fr_dict_attr_t *dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
 {
        fr_dict_attr_t const *bin;
 
@@ -2002,9 +2039,7 @@ inline fr_dict_attr_t const *fr_dict_attr_child_by_num(fr_dict_attr_t const *par
         *      We return the child of the referenced attribute, and
         *      not of the "group" attribute.
         */
-       if (parent->type == FR_TYPE_GROUP) {
-               parent = parent->ref;
-       }
+       if (parent->type == FR_TYPE_GROUP) parent = parent->ref;
 
        /*
         *      Child arrays may be trimmed back to save memory.
@@ -2015,13 +2050,32 @@ inline fr_dict_attr_t const *fr_dict_attr_child_by_num(fr_dict_attr_t const *par
        bin = parent->children[attr & 0xff];
        for (;;) {
                if (!bin) return NULL;
-               if (bin->attr == attr) return bin;
+               if (bin->attr == attr) {
+                       fr_dict_attr_t *out;
+
+                       memcpy(&out, &bin, sizeof(bin));
+
+                       return out;
+               }
                bin = bin->next;
        }
 
        return NULL;
 }
 
+/** Check if a child attribute exists in a parent using an attribute number
+ *
+ * @param[in] parent           to check for child in.
+ * @param[in] attr             number to look for.
+ * @return
+ *     - The child attribute on success.
+ *     - NULL if the child attribute does not exist.
+ */
+fr_dict_attr_t const *fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
+{
+       return dict_attr_child_by_num(parent, attr);
+}
+
 /** Lookup the structure representing an enum value in a #fr_dict_attr_t
  *
  * @param[in] da               to search in.
@@ -2037,7 +2091,7 @@ fr_dict_enum_t *fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t c
 
        if (!da) return NULL;
 
-       dict = fr_dict_by_da(da);
+       dict = dict_by_da(da);
        if (!dict) {
                fr_strerror_printf("Attributes \"%s\" not present in any dictionaries", da->name);
                return NULL;
@@ -2083,7 +2137,7 @@ char const *fr_dict_enum_name_by_value(fr_dict_attr_t const *da, fr_value_box_t
 
        if (!da) return NULL;
 
-       dict = fr_dict_by_da(da);
+       dict = dict_by_da(da);
        if (!dict) {
                fr_strerror_printf("Attributes \"%s\" not present in any dictionaries", da->name);
                return NULL;
@@ -2109,7 +2163,7 @@ fr_dict_enum_t *fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name,
 
        if (!name) return NULL;
 
-       dict = fr_dict_by_da(da);
+       dict = dict_by_da(da);
        if (!dict) {
                fr_strerror_printf("Attributes \"%s\" not present in any dictionaries", da->name);
                return NULL;
@@ -2145,7 +2199,7 @@ int dict_dlopen(fr_dict_t *dict, char const *name)
         *      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);
+       dict->dl = dl_by_name(dict_gctx->dict_loader, module_name, dict, false);
 
        talloc_free(module_name);
        return 0;
@@ -2161,13 +2215,13 @@ static int _dict_free_autoref(UNUSED void *ctx, void *data)
 
 static int _dict_free(fr_dict_t *dict)
 {
-       if (dict == fr_dict_internal) fr_dict_internal = NULL;
+       if (dict == dict_gctx->internal) dict_gctx->internal = NULL;
 
-       if (!fr_cond_assert(!dict->in_protocol_by_name || fr_hash_table_delete(protocol_by_name, dict))) {
+       if (!fr_cond_assert(!dict->in_protocol_by_name || fr_hash_table_delete(dict_gctx->protocol_by_name, dict))) {
                fr_strerror_printf("Failed removing dictionary from protocol hash \"%s\"", dict->root->name);
                return -1;
        }
-       if (!fr_cond_assert(!dict->in_protocol_by_num || fr_hash_table_delete(protocol_by_num, dict))) {
+       if (!fr_cond_assert(!dict->in_protocol_by_num || fr_hash_table_delete(dict_gctx->protocol_by_num, dict))) {
                fr_strerror_printf("Failed removing dictionary from protocol number_hash \"%s\"", dict->root->name);
                return -1;
        }
@@ -2480,36 +2534,39 @@ static int dict_onload_func(dl_t const *dl, void *symbol, UNUSED void *user_ctx)
  */
 int fr_dict_global_init(TALLOC_CTX *ctx, char const *dict_dir)
 {
-       TALLOC_FREE(dict_ctx);
-       dict_ctx = ctx;
+       dict_gctx_t *new_ctx = talloc_zero(ctx, dict_gctx_t);
 
-       if (!protocol_by_name) {
-               protocol_by_name = fr_hash_table_create(dict_ctx, dict_protocol_name_hash, dict_protocol_name_cmp, NULL);
-               if (!protocol_by_name) {
-                       fr_strerror_printf("Failed initializing protocol_by_name hash");
-                       return -1;
-               }
+       if (!dict_dir) {
+               fr_strerror_printf("No dictionary location provided");
+               return -1;
        }
 
-       if (!protocol_by_num) {
-               protocol_by_num = fr_hash_table_create(dict_ctx, dict_protocol_num_hash, dict_protocol_num_cmp, NULL);
-               if (!protocol_by_num) {
-                       fr_strerror_printf("Failed initializing protocol_by_num hash");
-                       return -1;
-               }
+       new_ctx->protocol_by_name = fr_hash_table_create(new_ctx, dict_protocol_name_hash, dict_protocol_name_cmp, NULL);
+       if (!new_ctx->protocol_by_name) {
+               fr_strerror_printf("Failed initializing protocol_by_name hash");
+       error:
+               talloc_free(new_ctx);
+               return -1;
        }
 
-       talloc_free(dict_dir_default);          /* Free previous value */
-       dict_dir_default = talloc_strdup(dict_ctx, dict_dir);
-
-       dict_loader = dl_loader_init(ctx, NULL, NULL, false, false);
-       if (!dict_loader) return -1;
+       new_ctx->protocol_by_num = fr_hash_table_create(new_ctx, dict_protocol_num_hash, dict_protocol_num_cmp, NULL);
+       if (!new_ctx->protocol_by_num) {
+               fr_strerror_printf("Failed initializing protocol_by_num hash");
+               goto error;
+       }
 
-       if (dl_symbol_init_cb_register(dict_loader, 0, "dict_protocol", dict_onload_func, NULL) < 0) {
-               return -1;
+       new_ctx->dict_dir_default = talloc_strdup(new_ctx, dict_dir);
+       if (!new_ctx->dict_dir_default) {
+               fr_strerror_printf("Out of Memory");
+               goto error;
        }
 
-       dict_initialised = true;
+       new_ctx->dict_loader = dl_loader_init(new_ctx, NULL, NULL, false, false);
+       if (!new_ctx->dict_loader) goto error;
+
+       if (dl_symbol_init_cb_register(new_ctx->dict_loader, 0, "dict_protocol", dict_onload_func, NULL) < 0) goto error;
+
+       dict_gctx = new_ctx;
 
        return 0;
 }
@@ -2521,15 +2578,84 @@ int fr_dict_global_init(TALLOC_CTX *ctx, char const *dict_dir)
  *     - 0 on success.
  *     - -1 on failure.
  */
-int fr_dict_dir_set(char const *dict_dir)
+int fr_dict_global_dir_set(char const *dict_dir)
 {
-       talloc_free(dict_dir_default);          /* Free previous value */
-       dict_dir_default = talloc_strdup(dict_ctx, dict_dir);
-       if (!dict_dir_default) return -1;
+       talloc_free(dict_gctx->dict_dir_default);               /* Free previous value */
+       dict_gctx->dict_dir_default = talloc_strdup(dict_gctx, dict_dir);
+       if (!dict_gctx->dict_dir_default) return -1;
 
        return 0;
 }
 
+char const *fr_dict_global_dir(void)
+{
+       return dict_gctx->dict_dir_default;
+}
+
+/** Mark all dictionaries and the global dictionary ctx as read only
+ *
+ * Any attempts to add new attributes will now fail.
+ */
+void fr_dict_global_read_only(void)
+{
+       fr_hash_iter_t  iter;
+       fr_dict_t       *dict;
+
+       /*
+        *      Set everything to read only
+        */
+       for (dict = fr_hash_table_iter_init(dict_gctx->protocol_by_num, &iter);
+            dict;
+            dict = fr_hash_table_iter_next(dict_gctx->protocol_by_num, &iter)) {
+               talloc_set_memlimit(dict, talloc_get_size(dict));
+               dict->read_only = true;
+       }
+
+       talloc_set_memlimit(dict_gctx, talloc_get_size(dict_gctx));
+       dict_gctx->read_only = true;
+}
+
+/** Coerce to non-const
+ *
+ */
+fr_dict_t *fr_dict_unconst(fr_dict_t const *dict)
+{
+       fr_dict_t *mutable;
+
+       if (unlikely(dict->read_only)) {
+               fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
+               return -1;
+       }
+
+       memcpy(&mutable, &dict, sizeof(dict));
+       return mutable;
+}
+
+/** Coerce to non-const
+ *
+ */
+fr_dict_attr_t *fr_dict_attr_unconst(fr_dict_attr_t const *da)
+{
+       fr_dict_attr_t *mutable;
+       fr_dict_t *dict;
+
+       dict = dict_by_da(da);
+       if (unlikely(dict->read_only)) {
+               fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
+               return -1;
+       }
+
+       memcpy(&mutable, &da, sizeof(da));
+       return mutable;
+}
+
+fr_dict_t const *fr_dict_internal(void)
+{
+       if (!dict_gctx) return NULL;
+
+       return dict_gctx->internal;
+}
+
 /*
  *     [a-zA-Z0-9_-:.]+
  */
@@ -2683,14 +2809,3 @@ fr_dict_attr_t const *fr_dict_attr_iterate_children(fr_dict_attr_t const *parent
 
        return NULL;
 }
-
-/** Coerce to non-const
- *
- */
-fr_dict_t *fr_dict_unconst(fr_dict_t const *dict)
-{
-       fr_dict_t *mutable;
-
-       memcpy(&mutable, &dict, sizeof(dict));
-       return mutable;
-}
index cfb775a3e9354ad19c7515fb13ba0f2c155ee43c..6d9a67e813b85b47419d99a03e794f689726d004 100644 (file)
@@ -154,11 +154,11 @@ VALUE_PAIR *fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int
        fr_dict_attr_t const *parent;
 
        if (vendor == 0) {
-               da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal), attr);
+               da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), attr);
                goto alloc;
        }
 
-       parent = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal), FR_VENDOR_SPECIFIC);
+       parent = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_VENDOR_SPECIFIC);
        if (!parent) return NULL;
 
        parent = fr_dict_attr_child_by_num(parent, vendor);
@@ -176,7 +176,7 @@ alloc:
                /*
                 *      Ensure that the DA is parented by the VP.
                 */
-               da = fr_dict_unknown_afrom_fields(vp, fr_dict_root(fr_dict_internal), vendor, attr);
+               da = fr_dict_unknown_afrom_fields(vp, fr_dict_root(fr_dict_internal()), vendor, attr);
                if (!da) {
                        talloc_free(vp);
                        return NULL;
index 53ff84daf3e0f2dad3114b386418e6dc8efe1a60..447ed4f240298301de510a6894c632be495343ea 100644 (file)
@@ -118,7 +118,7 @@ fr_dict_attr_autoload_t proto_detail_dict_attr[] = {
 static int dictionary_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule)
 {
        char const              *dict_str = cf_pair_value(cf_item_to_pair(ci));
-       fr_dict_t               *dict;
+       fr_dict_t const         *dict;
 
        dict = fr_dict_by_protocol_name(dict_str);
        if (!dict) {
@@ -126,7 +126,7 @@ static int dictionary_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *pare
                return -1;
        }
 
-       *(fr_dict_t **) out = dict;
+       *(fr_dict_t **) out = fr_dict_unconst(dict);
 
        return 0;
 }
index fe497d47ed1c13c62019ed7d60191e5f70aea185..c0fe5f8eb9145d8d45e786925a439d5a335a3abd 100644 (file)
@@ -250,7 +250,7 @@ static int fr_dict_enum_from_name_number(fr_dict_attr_t const *da, fr_table_num_
 
        for (p = table; p->name; p++) {
                value.vb_int32 = p->value;
-               if (fr_dict_enum_add_name(da, p->name, &value, true, false) < 0) return -1;
+               if (fr_dict_enum_add_name(fr_dict_attr_unconst(da), p->name, &value, true, false) < 0) return -1;
        }
 
        return 0;
index 89ae47b95e4edb7b6dd8f701c0b54b91c82b6338..1d4c0295b1acf0909911a4b25f2e8be7afb6a015 100644 (file)
@@ -201,7 +201,7 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
        inst->name = cf_section_name2(conf);
        if (!inst->name) inst->name = cf_section_name1(conf);
 
-       if (fr_dict_enum_add_name_next(attr_auth_type, inst->name) < 0) {
+       if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(attr_auth_type), inst->name) < 0) {
                PERROR("Failed adding %s alias", attr_auth_type->name);
                return -1;
        }
index 722e3c494a743b39cb94784b969548e525b4972b..e68c5f0a5f42c3f39c386dc65c79ffd59784fd99 100644 (file)
@@ -69,7 +69,7 @@ static ssize_t xlat_dict_attr_by_oid(TALLOC_CTX *ctx, char **out, UNUSED size_t
        fr_dict_attr_t const    *da;
        ssize_t         ret;
 
-       ret = fr_dict_attr_by_oid(fr_dict_internal, &parent, &attr, fmt);
+       ret = fr_dict_attr_by_oid(fr_dict_internal(), &parent, &attr, fmt);
        if (ret <= 0) {
                REMARKER(fmt, -(ret), "%s", fr_strerror());
                return ret;
index f6db40f84e6f3551f89b564c5cc7408e3e3b33fa..2eedae643c0fe62683aa6f0ebc5099c1aab30cde 100644 (file)
@@ -585,7 +585,7 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
        if (!name) name = cf_section_name1(conf);
        inst->name = name;
 
-       if (fr_dict_enum_add_name_next(attr_auth_type, inst->name) < 0) {
+       if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(attr_auth_type), inst->name) < 0) {
                PERROR("Failed adding %s alias", attr_auth_type->name);
                return -1;
        }
index 7fe9602f1f57b6ede6b5375735d61202a8f87bf3..1753b8362dd8e52d93d8078c6e7cdcd49996d4c8 100644 (file)
@@ -996,7 +996,7 @@ static int mod_bootstrap(void *instance, CONF_SECTION *cs)
        inst->name = cf_section_name2(cs);
        if (!inst->name) inst->name = "eap";
 
-       if (fr_dict_enum_add_name_next(attr_auth_type, inst->name) < 0) {
+       if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(attr_auth_type), inst->name) < 0) {
                PERROR("Failed adding %s alias", inst->name);
                return -1;
        }
index ba49bfd60f53c522c65df174841c9713ddce62f4..ba7a3dfeb974e5cc43a34b9048a27aad74785dbc 100644 (file)
@@ -86,7 +86,7 @@ static int auth_type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *paren
 {
        char const      *auth_type = cf_pair_value(cf_item_to_pair(ci));
 
-       if (fr_dict_enum_add_name_next(attr_auth_type, auth_type) < 0) {
+       if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(attr_auth_type), auth_type) < 0) {
                cf_log_err(ci, "Failed adding %s alias", attr_auth_type->name);
                return -1;
        }
index a76ab5bc453867843ca008d771ae06b1a4a88142..32cae852801ad117b0c3cc5e6a49e63fff1d6486 100644 (file)
@@ -134,7 +134,7 @@ static int auth_type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *paren
 {
        char const      *auth_type = cf_pair_value(cf_item_to_pair(ci));
 
-       if (fr_dict_enum_add_name_next(attr_auth_type, auth_type) < 0) {
+       if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(attr_auth_type), auth_type) < 0) {
                cf_log_err(ci, "Failed adding %s alias", attr_auth_type->name);
                return -1;
        }
index 45cb3a4afddb8d8f8f9f8e0389431e81e23ecef6..67bb9427c46b75d3320600d0825785b2951e6dd0 100644 (file)
@@ -622,7 +622,7 @@ FR_CODE eap_ttls_process(REQUEST *request, eap_session_t *eap_session, tls_sessi
         *      Add the tunneled attributes to the request request.
         */
        fr_cursor_init(&cursor, &request->packet->vps);
-       if (eap_ttls_decode_pair(request->packet, &cursor, fr_dict_root(fr_dict_internal),
+       if (eap_ttls_decode_pair(request->packet, &cursor, fr_dict_root(fr_dict_internal()),
                                 data, data_len, tls_session->ssl) < 0) {
                RPEDEBUG("Decoding TTLS TLVs failed");
                code = FR_CODE_ACCESS_REJECT;
index 2456f5a30eec9fce1eaf85643f2a0d463ae983be..504ee80c3014d1c35b58f60006bcb64353931074 100644 (file)
@@ -2188,7 +2188,7 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
        if (!name) name = cf_section_name1(conf);
        inst->name = name;
 
-       if (fr_dict_enum_add_name_next(attr_auth_type, inst->name) < 0) {
+       if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(attr_auth_type), inst->name) < 0) {
                PERROR("Failed adding %s alias", attr_auth_type->name);
                return -1;
        }
index f8e727d5aaa0ddbb5ff9b484fcc5283394a82898..330f9914cd3e9846ebe72d89799dd135737169e5 100644 (file)
@@ -517,7 +517,7 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
        inst->name = cf_section_name2(conf);
        if (!inst->name) inst->name = cf_section_name1(conf);
 
-       if (fr_dict_enum_add_name_next(attr_auth_type, inst->name) < 0) {
+       if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(attr_auth_type), inst->name) < 0) {
                PERROR("Failed adding %s alias", attr_auth_type->name);
                return -1;
        }
index 1a7857692380cc17aa52df1c719d4a986327765d..3686dd55d8c02d5299804b2dad13e819c4196c2b 100644 (file)
@@ -922,7 +922,7 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
        if (!name) name = cf_section_name1(conf);
        inst->name = name;
 
-       if (fr_dict_enum_add_name_next(attr_auth_type, inst->name) < 0) {
+       if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(attr_auth_type), inst->name) < 0) {
                PERROR("Failed adding %s alias", attr_auth_type->name);
                return -1;
        }
index 117c449503c7455776e5fba97bd340d6f9247bb4..4492a6800a3660382a6fca64d2bb9c3e1ee741b9 100644 (file)
@@ -335,7 +335,7 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
        inst->name = cf_section_name2(conf);
        if (!inst->name) inst->name = cf_section_name1(conf);
 
-       if (fr_dict_enum_add_name_next(attr_auth_type, inst->name) < 0) {
+       if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(attr_auth_type), inst->name) < 0) {
                PERROR("Failed adding %s alias", inst->name);
                return -1;
        }
index 9c78ee989d9809f50092241ab5f75bc984cf3f46..7b04541c9a51e04de51e583e0b65f29b449e1aeb 100644 (file)
@@ -165,7 +165,7 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
        }
 #endif
 
-       if (fr_dict_enum_add_name_next(attr_auth_type, inst->name) < 0) {
+       if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(attr_auth_type), inst->name) < 0) {
                PERROR("Failed adding %s alias", inst->name);
                return -1;
        }
index 170f7e0b5afb9d00845ca0b78c21e1e106738705..1af8914c1e85479bf41b8f1d77bf9a937c0260a9 100644 (file)
@@ -556,7 +556,8 @@ int fr_dhcpv4_global_init(void)
                }
                value.vb_uint8 = i;
 
-               if (fr_dict_enum_add_name(attr_dhcp_parameter_request_list, attr->name, &value, true, false) < 0) {
+               if (fr_dict_enum_add_name(fr_dict_attr_unconst(attr_dhcp_parameter_request_list),
+                                         attr->name, &value, true, false) < 0) {
                        return -1;
                }
        }
index 6a86875444ac0afde266616e62c7ba2308610c07..feec96c4eafe885d4673c72fe55ea0abea34b0de 100644 (file)
@@ -466,7 +466,8 @@ int fr_dhcpv6_global_init(void)
 
                value.vb_uint16 = child->attr;
 
-               if (fr_dict_enum_add_name(attr_option_request, child->name, &value, true, false) < 0) {
+               if (fr_dict_enum_add_name(fr_dict_attr_unconst(attr_option_request),
+                                         child->name, &value, true, false) < 0) {
                        fr_dict_autofree(libfreeradius_dhcpv6_dict);
                        return -1;
                }