From: Alan T. DeKok Date: Thu, 25 Jan 2024 22:08:33 +0000 (-0500) Subject: Make foreign dictionary references work. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fde8d11208ab874e2978f3946d1733c112ec7c1d;p=thirdparty%2Ffreeradius-server.git Make foreign dictionary references work. --- diff --git a/src/lib/util/dict_fixup.c b/src/lib/util/dict_fixup.c index 5224d520c18..03bff81355f 100644 --- a/src/lib/util/dict_fixup.c +++ b/src/lib/util/dict_fixup.c @@ -229,86 +229,63 @@ static fr_dict_attr_t const *dict_find_or_load_reference(fr_dict_t **dict_def, c { 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; } diff --git a/src/lib/util/dict_tokenize.c b/src/lib/util/dict_tokenize.c index 965d74bd876..779089c050c 100644 --- a/src/lib/util/dict_tokenize.c +++ b/src/lib/util/dict_tokenize.c @@ -779,118 +779,118 @@ static int dict_read_process_alias(dict_tokenize_ctx_t *ctx, char **argv, int ar */ 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; } /*