23RCSID(
"$Id: bd1d2a2c4335bee45c4f5c5ea4c2e5a44012efc2 $")
27#include <freeradius-devel/util/dict.h>
28#include <freeradius-devel/util/pair.h>
29#include <freeradius-devel/util/pair_legacy.h>
30#include <freeradius-devel/util/proto.h>
31#include <freeradius-devel/util/regex.h>
32#include <freeradius-devel/util/syserror.h>
33#include <freeradius-devel/util/sbuff.h>
34#include <freeradius-devel/util/value.h>
36#include <freeradius-devel/protocol/radius/rfc2865.h>
37#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
110 fr_sbuff_parse_rules_t
const *rules;
139 size_t exec_out_buff_len = 0;
141 char *exec_out = NULL;
145 if (!
conf->allow_exec) {
172 exec_out_len = getline(&exec_out, &exec_out_buff_len, fp);
173 if ((exec_out_len < 0) || (exec_out == NULL)) {
203 }
else if (ret != 0) {
208 }
else if (WIFSIGNALED(ret)) {
222 if (exec_out_len > 0 && exec_out[exec_out_len - 1] ==
'\n') exec_out[--exec_out_len] =
'\0';
223 if (exec_out_len > 0 && exec_out[exec_out_len - 1] ==
'\r') exec_out[--exec_out_len] =
'\0';
237 return slen - (quote != 0);
330 bool raw, was_unknown;
331 bool was_relative =
false;
371 fr_strerror_const(
"Attribute comparisons can only be used when the destination list is empty");
378#define CLEAN_DA_STACK do { if (was_unknown) { \
379 for (i = 1; i < da_stack.depth; i++) { \
380 fr_dict_attr_unknown_free(&da_stack.da[i]); \
407 append = !was_relative;
408 was_relative =
false;
428 }
else if (relative->
da->flags.is_root) {
429 fr_strerror_const(
"The '.Attribute' syntax cannot be used at the root of a dictionary");
436 fr_strerror_printf(
"The '.Attribute' syntax cannot be used with parent %s of data type 'group'",
452 if (relative->
da->flags.is_unknown) {
461 if (raw && relative->
da->flags.internal) {
469 fr_sbuff_marker(&lhs_m, &our_in);
485 if (!components)
goto done;
487 fr_sbuff_marker(&op_m, &our_in);
522 fr_strerror_printf(
"The '.Attribute' syntax cannot be used along with the '%s' operator",
545 static const bool invalid[
UINT8_MAX + 1] = {
546 [
'!'] =
true, [
'#'] =
true, [
'$'] =
true, [
'*'] =
true,
547 [
'+'] =
true, [
'-'] =
true, [
'/'] =
true, [
'<'] =
true,
548 [
'='] =
true, [
'>'] =
true, [
'?'] =
true, [
'|'] =
true,
552 if (c && invalid[c]) {
580 fr_sbuff_marker(&rhs_m, &our_in);
610 fr_sbuff_marker(&rhs_m, &our_in);
630 for (i = 1; i <= components; i++, da_stack.
depth++) {
644 fr_sbuff_marker(&lhs_m, &our_in);
676 if ((i == 1) && (relative->
da->dict == relative->
internal) && relative->
dict) {
687 fr_strerror_printf(
"Internal attribute '%s' of data type '%s' cannot contain protocol attributes",
746 da_stack.
da[da_stack.
depth - 1]->name);
755 fr_strerror_printf(
"Cannot create 'raw' children in attribute %s of data type 'group'",
756 da_stack.
da[da_stack.
depth - 1]->name);
771 if (i < components) {
790 unknown_type = raw_type;
794 if (!da_unknown)
goto error;
814 if (da->parent !=
parent) {
823 diff = da->depth - ref->depth;
838 for (j = da_stack.
depth + diff; j >= da_stack.
depth; j--) {
843 for (j = da_stack.
depth; j <= da_stack.
depth + diff; j++) {
850 da_stack.
depth += diff;
879 if (i < components) {
891 fr_strerror_printf(
"Please remove the reference to key field '%s' from the input string",
900 }
else if (raw && !da->flags.is_unknown) {
915 fr_strerror_printf(
"Cannot create raw attribute %s which changes data type from %s to %s",
922 if (!da_unknown)
goto error;
928 da_stack.
da[da_stack.
depth] = da;
934 if (da_stack.
depth <= 1) {
939 if (da_stack.
depth <= components) {
961 da_stack.
da[da_stack.
depth - 1]->name);
968 if (components == 1) append = (op !=
T_OP_EQ);
975 if ((relative->
da->flags.allow_flat) && (da_stack.
depth > 2)) {
976 da_stack.
da[1] = da_stack.
da[da_stack.
depth - 1];
986 for (i = 1; i < da_stack.
depth; i++) {
1008 if (!
vp->
da->flags.internal)
break;
1011 if (
vp && (
vp->
da->attr > da->attr)) {
1027 my.list = &
vp->vp_group;
1039 if (
vp)
goto update_relative;
1050 da_stack.
vp[i] =
vp;
1054 my.list = &
vp->vp_group;
1064 if (!
vp)
goto error;
1068 da_stack.
vp[i] =
vp;
1099 my.end_of_list =
true;
1111 if (slen < 0)
goto error;
1126 if (slen <= 0)
goto error;
1220 relative->
list = &
vp->vp_group;
1237 if (remaining > 20) remaining = 20;
1284 .allow_compare =
true,
1285 .allow_exec = allow_exec
1289 while (fgets(buf,
sizeof(buf), fp) != NULL) {
1294 if ((buf[0] ==
'\n') || (buf[0] ==
'\r')) {
1305 if (buf[0] ==
'#')
continue;
1326#ifdef WITH_VERIFY_PTR
1327 fr_pair_list_verify(__FILE__, __LINE__, ctx, &tmp_list,
true);
1407 if (!found)
goto do_add;
1416 if (!found)
goto do_add;
static int const char char buffer[256]
#define L(_str)
Helper for initialising arrays of string literals.
fr_dict_t const * fr_dict_by_da(fr_dict_attr_t const *da)
Attempt to locate the protocol dictionary containing an attribute.
fr_dict_attr_t const * fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
Find a common ancestor that two TLV type attributes share.
static fr_dict_attr_t * fr_dict_attr_unknown_afrom_oid(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, fr_sbuff_t *in, fr_type_t type)
bool const fr_dict_attr_allowed_chars[UINT8_MAX+1]
Characters allowed in a single dictionary attribute name.
fr_dict_attr_t * fr_dict_attr_unknown_alloc(TALLOC_CTX *ctx, fr_dict_attr_t const *da, fr_type_t type))
Allocate an unknown DA.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
fr_dict_t const * fr_dict_internal(void)
static bool fr_dict_attr_is_top_level(fr_dict_attr_t const *da)
Return true if this attribute is parented directly off the dictionary root.
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
fr_dict_attr_err_t
Errors returned by attribute lookup functions.
@ FR_DICT_ATTR_OK
No error.
fr_slen_t fr_dict_oid_component(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *in, fr_sbuff_term_t const *tt))
Parse an OID component, resolving it to a defined attribute.
#define fr_dict_attr_is_key_field(_da)
static fr_dict_attr_t const * fr_dict_attr_ref(fr_dict_attr_t const *da)
Return the reference associated with a group type attribute.
void fr_bio_shutdown & my
size_t fr_sbuff_out_unescape_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
int fr_pair_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and append)
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
int fr_pair_delete_by_da(fr_pair_list_t *list, fr_dict_attr_t const *da)
Delete matching pairs from the specified list.
fr_pair_t * fr_pair_parent(fr_pair_t const *vp)
Return a pointer to the parent pair.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
int fr_pair_prepend(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the start of the list.
fr_pair_t * fr_pair_find_last_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the last pair with a matching da.
static ssize_t fr_pair_value_from_substr(fr_pair_parse_t const *conf, fr_pair_t *vp, fr_sbuff_t *in)
static fr_sbuff_parse_rules_t const bareword_unquoted
static fr_table_num_sorted_t const pair_assignment_op_table[]
fr_slen_t fr_pair_list_afrom_substr(fr_pair_parse_t const *root, fr_pair_parse_t *relative, fr_sbuff_t *in)
Parse a fr_pair_list_t from a substring.
int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone, bool allow_exec)
Read valuepairs from the fp up to End-Of-File.
void fr_pair_list_move_op(fr_pair_list_t *to, fr_pair_list_t *from, fr_token_t op)
Move pairs from source list to destination list respecting operator.
static size_t pair_comparison_op_table_len
fr_pair_t * vp[FR_DICT_MAX_TLV_STACK]
which VP we have created or found
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK]
parent for parsing
static fr_table_num_sorted_t const pair_comparison_op_table[]
static fr_sbuff_term_t const bareword_terminals
static ssize_t pair_assignment_op_table_len
Our version of a DA stack.
bool allow_crlf
allow CRLF, and treat like comma
bool allow_zeros
allow '\0' as end of attribute
fr_dict_t const * dict
the protocol dictionary we use
char last_char
last character we read - ',', ' ', or 0 for EOF
fr_pair_list_t * list
list where output is placed
bool end_of_list
do we expect an end of list '}' character?
bool allow_compare
allow comparison operators
fr_dict_attr_t const * da
root da to start parsing from
fr_dict_t const * internal
a cached pointer to the internal dictionary
#define WIFEXITED(stat_val)
#define WEXITSTATUS(stat_val)
size_t fr_sbuff_adv_past_allowed(fr_sbuff_t *sbuff, size_t len, bool const allowed[static UINT8_MAX+1], fr_sbuff_term_t const *tt)
Wind position past characters in the allowed set.
bool const sbuff_char_line_endings[UINT8_MAX+1]
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_out_by_longest_prefix(_match_len, _out, _table, _sbuff, _def)
#define fr_sbuff_is_str_literal(_sbuff, _str)
#define fr_sbuff_set(_dst, _src)
#define fr_sbuff_diff(_a, _b)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_current(_sbuff_or_marker)
#define fr_sbuff_char(_sbuff_or_marker, _eob)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
#define fr_sbuff_extend(_sbuff_or_marker)
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define fr_sbuff_is_digit(_sbuff_or_marker)
#define FR_SBUFF_IN_STR(_start)
#define fr_sbuff_error(_sbuff_or_marker)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_adv_past_blank(_sbuff, _len, _tt)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_remaining(_sbuff_or_marker)
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Set of terminal elements.
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
An element in a lexicographically sorted array of name to num mappings.
char const * fr_tokens[T_TOKEN_LAST]
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
fr_pair_t * fr_pair_list_tail(fr_pair_list_t const *list)
Get the tail of a valuepair list.
fr_pair_t * fr_pair_remove(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list without freeing.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
void fr_pair_list_prepend(fr_pair_list_t *dst, fr_pair_list_t *src)
Move a list of fr_pair_t from a temporary list to the head of a destination list.
fr_pair_t * fr_pair_list_prev(fr_pair_list_t const *list, fr_pair_t const *item))
Get the previous item in a valuepair list before a specific entry.
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
#define FR_TYPE_STRUCTURAL_EXCEPT_GROUP
#define fr_type_is_structural(_x)
#define fr_type_is_leaf(_x)
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
fr_sbuff_parse_rules_t const value_parse_rules_single_quoted
fr_sbuff_unescape_rules_t fr_value_unescape_backtick
fr_sbuff_parse_rules_t const value_parse_rules_double_quoted
ssize_t fr_value_box_from_substr(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules)
Convert string value to a fr_value_box_t type.
#define fr_box_strvalue_len(_val, _len)
static size_t char ** out