{
fr_dict_t *dict;
fr_dict_attr_t const *da;
- char *p;
+ char const *name;
ssize_t slen;
- da = fr_dict_attr_by_oid(NULL, fr_dict_root(*dict_def), ref);
- if (da) return da;
-
/*
- * The attribute doesn't exist, and the reference
- * isn't in a "PROTO.ATTR" format, die.
+ * Ref to attribute in existing dictionary. The dictionary MUST be loaded by $INCLUDEs.
*/
- p = strchr(ref, '.');
+ if (ref[0] != '.') {
+ da = fr_dict_attr_by_oid(NULL, fr_dict_root(*dict_def), ref);
+ if (da) return da;
+
+ fr_strerror_printf("Invalid attribute reference '%s' at %s[%d]", ref,
+ fr_cwd_strip(filename), line);
+ return NULL;
+ }
+
+ name = ref + 2; /* already checked when we insert it */
/*
- * Get / skip protocol name.
+ * Reference to foreign protocol. Get the protocol name.
*/
- slen = dict_by_protocol_substr(NULL,
- &dict, &FR_SBUFF_IN(ref, strlen(ref)),
- *dict_def);
+ slen = dict_by_protocol_substr(NULL, &dict, &FR_SBUFF_IN(name, strlen(name)), NULL);
if (slen <= 0) {
- fr_dict_t *other;
+ char *p;
+ p = strchr(name, '.');
if (p) *p = '\0';
- /*
- * Can't load the dictionary we're loading.
- */
- if (dict == *dict_def) {
- fr_strerror_printf("Cannot reference parent dictionary %s from within the same dictionary", fr_dict_root(dict)->name);
- return NULL;
- }
-
- if (fr_dict_protocol_afrom_file(&other, ref, NULL, filename) < 0) {
+ if (fr_dict_protocol_afrom_file(&dict, name, NULL, filename) < 0) {
+ fr_strerror_printf("Unknown protocol '%s' at %s[%d]", name,
+ fr_cwd_strip(filename), line);
return NULL;
}
- if (p) *p = '.';
-
/*
- * Grab the protocol name again
+ * The reference is to the root of the foreign protocol, we're done.
*/
- dict = other;
if (!p) {
- *dict_def = other;
- return other->root;
+ *dict_def = dict;
+ return dict->root;
}
- slen = p - ref;
- }
-
- if (slen < 0) {
- invalid_reference:
- fr_strerror_printf("Invalid attribute reference '%s' at %s[%d]",
- ref,
- fr_cwd_strip(filename), line);
- return NULL;
- }
-
- /*
- * No known dictionary, so we're asked to just
- * use the whole string. Which we did above. So
- * either it's a bad ref, OR it's a ref to a
- * dictionary which doesn't exist.
- */
- if (slen == 0) goto invalid_reference;
-
- /*
- * Just a bare reference to the protocol. Use the root.
- */
- if (!ref[slen]) {
- *dict_def = dict;
- return fr_dict_root(dict);
+ name = p + 1;
+ } else {
+ /*
+ * The foreign dictionary was loaded by someone
+ * else, try to resolve the attribute.
+ */
+ name += slen + 1;
}
/*
* Look up the attribute.
*/
- da = fr_dict_attr_by_oid(NULL, fr_dict_root(dict), ref + slen + 1);
+ da = fr_dict_attr_by_oid(NULL, fr_dict_root(dict), name);
if (!da) {
- fr_strerror_printf("No such attribute '%s' in reference at %s[%d]",
- ref + slen + 1, fr_cwd_strip(filename), line);
+ fr_strerror_printf("No such attribute '%s' in protocol '%s' at %s[%d]",
+ name, dict->root->name, fr_cwd_strip(filename), line);
return NULL;
}
*/
static int dict_process_ref(dict_tokenize_ctx_t *ctx, fr_dict_attr_t const *parent, fr_dict_attr_t const *da, char *ref)
{
+ fr_dict_t *dict;
+ ssize_t slen;
+ char const *name;
+
/*
- * Groups can refer to other dictionaries, or other attributes.
+ * It's a "clone" thing.
*/
- if (da->type == FR_TYPE_GROUP) {
+ if (da->type != FR_TYPE_GROUP) {
+ if (!ref) return 0;
+
+ if (dict_fixup_clone(&ctx->fixup, CURRENT_FRAME(ctx)->filename, CURRENT_FRAME(ctx)->line,
+ fr_dict_attr_unconst(parent), fr_dict_attr_unconst(da),
+ ref, talloc_array_length(ref) - 1) < 0) {
+ fail:
+ talloc_free(ref);
+ return -1;
+ }
+
+ talloc_free(ref);
+ return 0;
+ }
+
+ /*
+ * No reference, just point it to the root of the current dictionary.
+ */
+ if (!ref) {
fr_dict_attr_t *self;
- fr_dict_t *dict;
- char *p;
- ssize_t slen;
- memcpy(&self, &da, sizeof(self)); /* const issues */
+ dict = ctx->dict;
+ da = ctx->dict->root;
- /*
- * No qualifiers, just point it to the root of the current dictionary.
- */
- if (!ref) {
- dict = ctx->dict;
- da = ctx->dict->root;
- goto check;
- }
+set:
+ talloc_free(ref);
- /*
- * Else we find the reference.
- */
+ self = UNCONST(fr_dict_attr_t *, da);
+ self->dict = dict;
+
+ dict_attr_ref_set(self, da);
+ return 0;
+ }
+
+ /*
+ * Else refs refer to attributes in the current dictionary.
+ */
+ if (ref[0] != '.') {
da = fr_dict_attr_by_oid(NULL, parent, ref);
if (da) {
dict = ctx->dict;
- goto check;
- }
-
- /*
- * The attribute doesn't exist, and the reference
- * is FOO, it might be just a ref to a
- * dictionary.
- */
- p = strchr(ref, '.');
- if (!p) goto fixup;
-
- /*
- * Get / skip protocol name.
- */
- slen = dict_by_protocol_substr(NULL, &dict, &FR_SBUFF_IN(ref, strlen(ref)), ctx->dict);
- if (slen < 0) {
- talloc_free(ref);
- return -1;
+ goto set;
}
/*
- * No known dictionary, so we're asked to just
- * use the whole string. Which we did above. So
- * either it's a bad ref, OR it's a ref to a
- * dictionary which hasn't yet been loaded.
- *
- * Save the fixup for later, when we've hopefully
- * loaded the dictionary.
+ * The attribute doesn't exist (yet) save a reference to it.
*/
- if (slen == 0) {
- fixup:
- if (dict_fixup_group(&ctx->fixup, CURRENT_FRAME(ctx)->filename, CURRENT_FRAME(ctx)->line,
- self, ref, talloc_array_length(ref) - 1) < 0) {
- oom:
- talloc_free(ref);
- return -1;
- }
- talloc_free(ref);
-
- return 0;
-
- } else if (ref[slen] == '\0') {
- da = dict->root;
- goto check;
+ add_fixup:
+ if (dict_fixup_group(&ctx->fixup, CURRENT_FRAME(ctx)->filename, CURRENT_FRAME(ctx)->line,
+ UNCONST(fr_dict_attr_t *, da), ref, talloc_array_length(ref) - 1) < 0) goto fail;
+
+ talloc_free(ref);
+ return 0;
+ }
- } else {
- /*
- * Look up the attribute.
- */
- da = fr_dict_attr_by_oid(NULL, parent, ref + slen);
- if (!da) {
- fr_strerror_printf("protocol loaded, but no attribute '%s'", ref + slen);
- talloc_free(ref);
- return -1;
- }
+ if (ref[1] != '.') {
+ fr_strerror_const("Invalid reference");
+ goto fail;
+ }
- check:
- talloc_free(ref);
+ name = ref + 2;
- if (da->type != FR_TYPE_TLV) {
- fr_strerror_const("References MUST be to an ATTRIBUTE of type 'tlv'");
- return -1;
- }
+ /*
+ * Get / skip protocol name.
+ */
+ slen = dict_by_protocol_substr(NULL, &dict, &FR_SBUFF_IN(name, strlen(name)), ctx->dict);
+ if (slen <= 0) goto add_fixup;
- if (fr_dict_attr_ref(da)) {
- fr_strerror_const("References MUST NOT refer to an ATTRIBUTE which also has 'ref=...'");
- return -1;
- }
+ if (strncmp(name, ctx->dict->root->name, slen) == 0) {
+ fr_strerror_const("Cannot reference the current protocol dictionary");
+ goto fail;
+ }
- self->dict = dict;
+ /*
+ * It's a reference to the root of the foreign dictionary.
+ */
+ if (name[slen] == '\0') {
+ da = dict->root;
+ goto set;
+ }
- dict_attr_ref_set(self, da);
- }
+ /*
+ * Look up the attribute.
+ */
+ da = fr_dict_attr_by_oid(NULL, dict->root, name + slen);
+ if (!da) {
+ fr_strerror_printf("protocol '%s' is loaded, but there is no such attribute '%s'",
+ dict->root->name, name + slen);
+ goto fail;
}
/*
- * It's a "clone" thing.
+ * Refs must satisfy certain properties.
*/
- if (ref) {
- if (dict_fixup_clone(&ctx->fixup, CURRENT_FRAME(ctx)->filename, CURRENT_FRAME(ctx)->line,
- fr_dict_attr_unconst(parent), fr_dict_attr_unconst(da),
- ref, talloc_array_length(ref) - 1) < 0) goto oom;
- talloc_free(ref);
+ if (da->type != FR_TYPE_TLV) {
+ fr_strerror_const("References MUST be to an ATTRIBUTE of type 'tlv'");
+ goto fail;
}
- return 0;
+ if (fr_dict_attr_ref(da)) {
+ fr_strerror_const("References MUST NOT refer to an ATTRIBUTE which also has 'ref=...'");
+ goto fail;
+ }
+
+ goto set;
}
/*