*/
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.
*/
/** 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
*/
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));
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);
}
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, ".");
}
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));
}
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;
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);
}
}
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);
}
(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);
}
}
}
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));
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;
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",
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;
* 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;
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;
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);
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");
}
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;
* 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;
}
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));
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;
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;
* 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);
* 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,
#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
*/
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);
/** @} */
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);
/** @} */
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
*
/** @} */
-/** @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
#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); \
* 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
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;
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
}
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
}
-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.");
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)) {
* 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
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;
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;
/*
* 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);
* *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;
/*
* 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
* 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;
*/
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");
* 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;
/*
* 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;
*/
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;
}
/*
* 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;
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
* 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) {
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);
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;
/*
* 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);
* 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;
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;
}
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;
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;
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 */
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;
}
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);
/*
* 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);
* 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));
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 */
{
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;
}
/*
* 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;
}
talloc_free(dict_path);
*out = dict;
- if (!fr_dict_internal) fr_dict_internal = dict;
+ if (!dict_gctx->internal) dict_gctx->internal = dict;
return 0;
}
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;
}
* 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;
}
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);
}
/*
* 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;
/*
* 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;
{
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;
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;
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;
* 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;
# 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 },
};
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] = {
return n;
}
-
/** Add a protocol to the global protocol table
*
* Inserts a protocol into the global protocol table. Uses the root attributes
{
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;
}
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;
}
return 0;
}
-
/** Add an attribute to the dictionary
*
* @param[in] dict of protocol context we're operating in.
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.
*/
* - 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;
return -1;
}
- dict = fr_dict_by_da(da);
+ dict = dict_by_da(da);
enumv = talloc_zero(dict->pool, fr_dict_enum_t);
if (!enumv) {
/** 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
* - > 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;
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);
*/
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;
}
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));
*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) {
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;
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
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;
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.
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);
}
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;
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.
*/
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
*/
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;
}
}
/*
* 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;
*/
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,
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;
* 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.
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.
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;
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;
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;
* 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;
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;
}
*/
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;
}
* - 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_-:.]+
*/
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;
-}
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);
/*
* 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;
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) {
return -1;
}
- *(fr_dict_t **) out = dict;
+ *(fr_dict_t **) out = fr_dict_unconst(dict);
return 0;
}
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;
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;
}
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;
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;
}
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;
}
{
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;
}
{
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;
}
* 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;
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;
}
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;
}
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;
}
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;
}
}
#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;
}
}
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;
}
}
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;
}