#include <freeradius-devel/build.h>
#include <freeradius-devel/missing.h>
#include <freeradius-devel/util/dl.h>
+#include <freeradius-devel/util/sbuff.h>
#include <freeradius-devel/util/table.h>
#include <freeradius-devel/util/types.h>
FR_DICT_ATTR_PROTOCOL_NOTFOUND = -2, //!< Protocol couldn't be found.
FR_DICT_ATTR_PARSE_ERROR = -3, //!< Attribute string couldn't be parsed
FR_DICT_ATTR_OOM = -4, //!< Memory allocation error.
- FR_DICT_ATTR_EINVAL = -5 //!< Invalid arguments.
+ FR_DICT_ATTR_NOT_DESCENDENT = -5, //!< Attribute is not a descendent of the parent
+ ///< attribute.
+ FR_DICT_ATTR_NOT_ANCESTOR = -6, //!< Attribute is not an ancestor of the child
+ ///< attribute.
+ FR_DICT_ATTR_NO_CHILDREN = -7, //!< Child lookup in attribute with no children.
+ FR_DICT_ATTR_EINVAL = -8 //!< Invalid arguments.
} fr_dict_attr_err_t;
typedef bool (*fr_dict_attr_valid_func_t)(fr_dict_t *dict, fr_dict_attr_t const *parent,
/** Characters that are allowed in dictionary attribute names
*
*/
-extern bool const fr_dict_attr_allowed_chars[UINT8_MAX];
+extern bool const fr_dict_attr_allowed_chars[UINT8_MAX + 1];
extern bool const fr_dict_non_data_types[FR_TYPE_MAX + 1];
/** @name Programatically create dictionary attributes and values
*/
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);
+ssize_t fr_dict_by_protocol_substr(fr_dict_attr_err_t *err,
+ fr_dict_t const **out, fr_sbuff_t *name, fr_dict_t const *dict_def);
fr_dict_t const *fr_dict_by_protocol_name(char const *name);
fr_dict_attr_t const *fr_dict_vendor_attr_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen);
ssize_t fr_dict_attr_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
- fr_dict_t const *dict, char const *name) CC_HINT(nonnull(2,4));
+ fr_dict_t const *dict, fr_sbuff_t *name) CC_HINT(nonnull(2,4));
fr_dict_attr_t const *fr_dict_attr_by_name(fr_dict_t const *dict, char const *attr);
ssize_t fr_dict_attr_by_qualified_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
fr_dict_t const *dict_def,
- char const *attr, bool fallback);
+ fr_sbuff_t *name, bool fallback);
fr_dict_attr_err_t fr_dict_attr_by_qualified_name(fr_dict_attr_t const **out,
fr_dict_t const *dict_def, char const *attr, bool fallback);
fr_dict_attr_t const *fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr);
+ssize_t fr_dict_attr_child_by_name_substr(fr_dict_attr_err_t *err,
+ fr_dict_attr_t const **out, fr_dict_attr_t const *parent,
+ fr_sbuff_t *name, bool is_direct_decendent);
+
fr_dict_enum_t *fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value);
char const *fr_dict_enum_name_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value);
/** Characters allowed in dictionary names
*
*/
-bool const fr_dict_attr_allowed_chars[UINT8_MAX] = {
+bool const fr_dict_attr_allowed_chars[UINT8_MAX + 1] = {
['-'] = true, ['/'] = true, ['_'] = true,
['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true,
['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true,
return dict->root;
}
-ssize_t dict_by_protocol_substr(fr_dict_t **out, char const *name, fr_dict_t const *dict_def)
+ssize_t dict_by_protocol_substr(fr_dict_attr_err_t *err,
+ fr_dict_t **out, fr_sbuff_t *name, fr_dict_t const *dict_def)
{
fr_dict_attr_t root;
fr_dict_t *dict;
- char const *p;
size_t len;
+ char buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1 + 1]; /* +1 \0 +1 for "too long" */
+ fr_sbuff_t our_name = FR_SBUFF_NO_ADVANCE(name);
- if (!dict_gctx || !name || !*name || !out) return 0;
+ if (!dict_gctx || !name || !fr_sbuff_remaining(name) || !out) return 0;
memset(&root, 0, sizeof(root));
* Advance p until we get something that's not part of
* the dictionary attribute name.
*/
- for (p = name; fr_dict_attr_allowed_chars[(uint8_t)*p] && (*p != '.'); p++);
-
- /*
- * If what we stopped at wasn't a '.', then there
- * can't be a protocol name in this string.
- */
- if (*p != '.') {
- memcpy(out, &dict_def, sizeof(*out));
+ len = fr_sbuff_strncpy_allowed(buffer, sizeof(buffer),
+ &our_name, SIZE_MAX,
+ fr_dict_attr_allowed_chars);
+ if (len == 0) {
+ fr_strerror_printf("Zero length attribute name");
+ if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
return 0;
}
-
- len = p - name;
if (len > FR_DICT_ATTR_MAX_NAME_LEN) {
fr_strerror_printf("Attribute name too long");
+ if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
return -(FR_DICT_ATTR_MAX_NAME_LEN);
}
- root.name = talloc_bstrndup(NULL, name, len);
- if (!root.name) {
- fr_strerror_printf("Out of memory");
- *out = NULL;
+ /*
+ * If what we stopped at wasn't a '.', then there
+ * can't be a protocol name in this string.
+ */
+ if (*(our_name.p) != '.') {
+ memcpy(out, &dict_def, sizeof(*out));
return 0;
}
+
+ root.name = buffer;
dict = fr_hash_table_finddata(dict_gctx->protocol_by_name, &(fr_dict_t){ .root = &root });
- talloc_const_free(root.name);
if (!dict) {
- fr_strerror_printf("Unknown protocol '%.*s'", (int) len, name);
+ fr_strerror_printf("Unknown protocol '%s'", root.name);
*out = NULL;
return 0;
}
*out = dict;
- return p - name;
+ return (size_t)fr_sbuff_set(name, &our_name);
}
/** Look up a protocol name embedded in another string
*
+ * @param[out] err Parsing error.
* @param[out] out the resolve dictionary or NULL if the dictionary
* couldn't be resolved.
* @param[in] name string start.
* - <= 0 on error and (*out == NULL) (offset as negative integer)
* - > 0 on success (number of bytes parsed).
*/
-ssize_t fr_dict_by_protocol_substr(fr_dict_t const **out, char const *name, fr_dict_t const *dict_def)
+ssize_t fr_dict_by_protocol_substr(fr_dict_attr_err_t *err, fr_dict_t const **out, fr_sbuff_t *name, fr_dict_t const *dict_def)
{
ssize_t slen;
fr_dict_t *dict = NULL;
- slen = dict_by_protocol_substr(&dict, name, dict_def);
+ slen = dict_by_protocol_substr(err, &dict, name, dict_def);
*out = dict;
return slen;
* - The number of bytes of name consumed on success.
*/
ssize_t fr_dict_attr_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
- fr_dict_t const *dict, char const *name)
+ fr_dict_t const *dict, fr_sbuff_t *name)
{
fr_dict_attr_t const *da;
- char const *p;
size_t len;
- char buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1];
-
+ char buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1 + 1]; /* +1 \0 +1 for "too long" */
+ fr_sbuff_t our_name = FR_SBUFF_NO_ADVANCE(name);
*out = NULL;
INTERNAL_IF_NULL(dict, 0);
- if (!*name) {
- zero_length_name:
+ len = fr_sbuff_strncpy_allowed(buffer, sizeof(buffer),
+ &our_name, SIZE_MAX,
+ fr_dict_attr_allowed_chars);
+ if (len == 0) {
fr_strerror_printf("Zero length attribute name");
if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
return 0;
}
-
- /*
- * Advance p until we get something that's not part of
- * the dictionary attribute name.
- */
- for (p = name; fr_dict_attr_allowed_chars[(uint8_t)*p]; p++);
-
- len = p - name;
- if (len == 0) goto zero_length_name;
-
if (len > FR_DICT_ATTR_MAX_NAME_LEN) {
fr_strerror_printf("Attribute name too long");
if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
return -(FR_DICT_ATTR_MAX_NAME_LEN);
}
- memcpy(buffer, name, len);
- buffer[len] = '\0';
-
da = fr_hash_table_finddata(dict->attributes_by_name, &(fr_dict_attr_t){ .name = buffer });
if (!da) {
if (err) *err = FR_DICT_ATTR_NOTFOUND;
- fr_strerror_printf("Unknown attribute '%.*s'", (int) len, name);
+ fr_strerror_printf("Unknown attribute '%s'", buffer);
return 0;
}
*out = da;
if (err) *err = FR_DICT_ATTR_OK;
- return p - name;
+ return (size_t)fr_sbuff_set(name, &our_name);
}
/* Internal version of fr_dict_attr_by_name
* - The number of bytes of name consumed on success.
*/
ssize_t fr_dict_attr_by_qualified_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
- fr_dict_t const *dict_def, char const *name, bool fallback)
+ fr_dict_t const *dict_def, fr_sbuff_t *name, bool fallback)
{
fr_dict_t *dict = NULL;
fr_dict_t *dict_iter = NULL;
- char const *p = name;
ssize_t slen;
fr_dict_attr_err_t aerr = FR_DICT_ATTR_OK;
bool internal = false;
fr_hash_iter_t iter;
-
+ fr_sbuff_t our_name = FR_SBUFF_NO_ADVANCE(name);
*out = NULL;
+ fr_sbuff_trim_start(&our_name); /* So we can figure out the amount we advanced */
+
INTERNAL_IF_NULL(dict_def, -1);
/*
* Figure out if we should use the default dictionary
* or if the string was qualified.
*/
- slen = dict_by_protocol_substr(&dict, p, dict_def);
+ slen = dict_by_protocol_substr(err, &dict, &our_name, dict_def);
if (slen < 0) {
- if (err) *err = FR_DICT_ATTR_PROTOCOL_NOTFOUND;
return 0;
/*
* Has dictionary qualifier, can't fallback
*/
} else if (slen > 0) {
- p += slen;
-
/*
* Next thing SHOULD be a '.'
*/
- if (*p++ != '.') {
+ if (fr_sbuff_next_char(&our_name) != '.') {
if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
return 0;
}
}
again:
- slen = fr_dict_attr_by_name_substr(&aerr, out, dict, p);
-
+ /*
+ * We rely on the fact the sbuff is only
+ * advanced on success.
+ */
+ fr_dict_attr_by_name_substr(&aerr, out, dict, &our_name);
switch (aerr) {
case FR_DICT_ATTR_OK:
break;
fail:
if (err) *err = aerr;
- return -((p - name) + slen);
+ FR_SBUFF_ERROR_RETURN(&our_name);
/*
* Other error codes are the same
*/
default:
if (err) *err = aerr;
- return -((p - name) + slen);
+ FR_SBUFF_ERROR_RETURN(&our_name);
}
- p += slen;
-
/*
* If we're returning a success code indication,
* ensure we populated out
if (err) *err = FR_DICT_ATTR_OK;
- return p - name;
+ return (size_t)fr_sbuff_set(name, &our_name);
}
/** Locate a qualified #fr_dict_attr_t by its name and a dictionary qualifier
*
* @param[out] out Dictionary found attribute.
* @param[in] dict_def Default dictionary for non-qualified dictionaries.
- * @param[in] attr Dictionary/Attribute name.
+ * @param[in] name Dictionary/Attribute name.
* @param[in] fallback If true, fallback to the internal dictionary.
* @return an #fr_dict_attr_err_t value.
*/
fr_dict_attr_err_t fr_dict_attr_by_qualified_name(fr_dict_attr_t const **out, fr_dict_t const *dict_def,
- char const *attr, bool fallback)
+ char const *name, bool fallback)
{
ssize_t slen;
fr_dict_attr_err_t err = FR_DICT_ATTR_PARSE_ERROR;
+ fr_sbuff_t our_name;
+
+ fr_sbuff_parse_init(&our_name, name, strlen(name));
- slen = fr_dict_attr_by_qualified_name_substr(&err, out, dict_def, attr, fallback);
+ slen = fr_dict_attr_by_qualified_name_substr(&err, out, dict_def, &our_name, fallback);
if (slen <= 0) return err;
- if ((size_t)slen != strlen(attr)) {
- fr_strerror_printf("Trailing garbage after attr string \"%s\"", attr);
+ if ((size_t)slen != fr_sbuff_len(&our_name)) {
+ fr_strerror_printf("Trailing garbage after attr string \"%s\"", name);
return FR_DICT_ATTR_PARSE_ERROR;
}
return dict_attr_child_by_num(parent, attr);
}
+
+/** Look up an attribute by name in the dictionary that contains the parent
+ *
+ */
+ssize_t fr_dict_attr_child_by_name_substr(fr_dict_attr_err_t *err,
+ fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *name,
+ bool is_direct_decendent)
+{
+ ssize_t slen;
+
+ DA_VERIFY(parent);
+
+ if (!parent->children) {
+ if (err) *err = FR_DICT_ATTR_NO_CHILDREN;
+ return 0;
+ }
+
+ /*
+ * We return the child of the referenced attribute, and
+ * not of the "group" attribute.
+ */
+ if (parent->type == FR_TYPE_GROUP) parent = parent->ref;
+
+ slen = fr_dict_attr_by_name_substr(err, out, fr_dict_by_da(parent), name);
+ if (slen <= 0) return slen;
+
+ if (is_direct_decendent) {
+ if ((*out)->parent != parent) {
+ not_decendent:
+ if (err) *err = FR_DICT_ATTR_NOT_DESCENDENT;
+ *out = NULL;
+ return 0;
+ }
+ } else if (!fr_dict_parent_common(parent, *out, true)) goto not_decendent;
+
+ return slen;
+}
+
/** Lookup the structure representing an enum value in a #fr_dict_attr_t
*
* @param[in] da to search in.