Skip to content

Commit

Permalink
rearrange call env structures to make them more like conf_parser_t
Browse files Browse the repository at this point in the history
  • Loading branch information
arr2036 committed Nov 25, 2023
1 parent 11d493f commit a84044b
Show file tree
Hide file tree
Showing 13 changed files with 267 additions and 239 deletions.
46 changes: 23 additions & 23 deletions src/lib/unlang/call_env.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ call_env_result_t call_env_value_parse(TALLOC_CTX *ctx, request_t *request, void

vb = fr_value_box_list_head(tmpl_expanded);
if (!vb) {
if (!env->rule->pair.nullable) {
if (!call_env_nullable(env->rule->flags)) {
RPEDEBUG("Failed to evaluate required module option %s = %s", env->rule->name, env->tmpl->name);
return CALL_ENV_MISSING;
}
Expand All @@ -56,14 +56,14 @@ call_env_result_t call_env_value_parse(TALLOC_CTX *ctx, request_t *request, void
/*
* Concatenate multiple boxes if needed
*/
if (env->rule->pair.concat &&
fr_value_box_list_concat_in_place(vb, vb, tmpl_expanded, env->rule->type,
if (call_env_concat(env->rule->flags) &&
fr_value_box_list_concat_in_place(vb, vb, tmpl_expanded, env->rule->pair.cast_type,
FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0 ) {
RPEDEBUG("Failed concatenating values for %s", env->rule->name);
return CALL_ENV_INVALID;
}

if (env->rule->pair.single && (fr_value_box_list_num_elements(tmpl_expanded) > 1)) {
if (call_env_single(env->rule->flags) && (fr_value_box_list_num_elements(tmpl_expanded) > 1)) {
RPEDEBUG("%d values found for %s. Only one is allowed",
fr_value_box_list_num_elements(tmpl_expanded), env->rule->name);
return CALL_ENV_INVALID;
Expand Down Expand Up @@ -121,7 +121,7 @@ static unlang_action_t call_env_expand_start(UNUSED rlm_rcode_t *p_result, UNUSE
/*
* If we only need the tmpl, just set the pointer and move the next.
*/
out = (void **)((uint8_t *)*call_env_rctx->data + env->rule->pair.tmpl_offset);
out = (void **)((uint8_t *)*call_env_rctx->data + env->rule->parsed_offset);
*out = env->tmpl;
}

Expand All @@ -137,8 +137,8 @@ static unlang_action_t call_env_expand_start(UNUSED rlm_rcode_t *p_result, UNUSE
/*
* Multi pair options should allocate boxes in the context of the array
*/
if (env->rule->pair.multi) {
out = (void **)((uint8_t *)(*call_env_rctx->data) + env->rule->offset);
if (call_env_multi(env->rule->flags)) {
out = (void **)((uint8_t *)(*call_env_rctx->data) + env->rule->pair.result_offset);

/*
* For multi pair options, allocate the array before expanding the first entry.
Expand Down Expand Up @@ -177,19 +177,19 @@ static unlang_action_t call_env_expand_repeat(UNUSED rlm_rcode_t *p_result, UNUS
/*
* Find the location of the output
*/
out = ((uint8_t*)(*call_env_rctx->data)) + env->rule->offset;
out = ((uint8_t*)(*call_env_rctx->data)) + env->rule->pair.result_offset;

/*
* If this is a multi pair option, the output is an array.
* Find the correct offset in the array
*/
if (env->rule->pair.multi) {
if (call_env_multi(env->rule->flags)) {
void *array = *(void **)out;
out = ((uint8_t *)array) + env->rule->pair.size * env->multi_index;
}

tmpl_only:
if (env->rule->pair.tmpl_offset >= 0) tmpl_out = ((uint8_t *)*call_env_rctx->data) + env->rule->pair.tmpl_offset;
if (env->rule->parsed_offset >= 0) tmpl_out = ((uint8_t *)*call_env_rctx->data) + env->rule->parsed_offset;

result = call_env_value_parse(*call_env_rctx->data, request, out, tmpl_out, env, &call_env_rctx->tmpl_expanded);
if (result != CALL_ENV_SUCCESS) {
Expand Down Expand Up @@ -257,11 +257,11 @@ static int call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *parsed, char
fr_type_t type;

while (call_env->name) {
if (call_env->flags & CONF_FLAG_SUBSECTION) {
if (call_env_is_subsection(call_env->flags)) {
CONF_SECTION const *subcs;
subcs = cf_section_find(cs, call_env->name, call_env->section.ident2);
if (!subcs) {
if (!call_env->section.required) goto next;
if (!call_env_required(call_env->flags)) goto next;
cf_log_err(cs, "Module %s missing required section %s", name, call_env->name);
return -1;
}
Expand All @@ -272,8 +272,8 @@ static int call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *parsed, char

cp = cf_pair_find(cs, call_env->name);

if (!cp && !call_env->dflt) {
if (!call_env->pair.required) goto next;
if (!cp && !call_env->pair.dflt) {
if (!call_env_required(call_env->flags)) goto next;

cf_log_err(cs, "Module %s missing required option %s", name, call_env->name);
return -1;
Expand All @@ -283,7 +283,7 @@ static int call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *parsed, char
* Check for additional conf pairs and error
* if there is one and multi is not allowed.
*/
if (!call_env->pair.multi && ((next = cf_pair_find_next(cs, cp, call_env->name)))) {
if (!call_env_multi(call_env->flags) && ((next = cf_pair_find_next(cs, cp, call_env->name)))) {
cf_log_err(cf_pair_to_item(next), "Invalid duplicate configuration item '%s'", call_env->name);
return -1;
}
Expand All @@ -301,14 +301,14 @@ static int call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *parsed, char
if (cp) {
value = cf_pair_value(cp);
len = talloc_array_length(value) - 1;
quote = call_env->pair.force_quote ? call_env->dflt_quote : cf_pair_value_quote(cp);
quote = call_env_force_quote(call_env->flags) ? call_env->pair.dflt_quote : cf_pair_value_quote(cp);
} else {
value = call_env->dflt;
value = call_env->pair.dflt;
len = strlen(value);
quote = call_env->dflt_quote;
quote = call_env->pair.dflt_quote;
}

type = call_env->type;
type = call_env->pair.cast_type;
if (tmpl_afrom_substr(call_env_parsed, &call_env_parsed->tmpl, &FR_SBUFF_IN(value, len),
quote, NULL, &(tmpl_rules_t){
.cast = (type == FR_TYPE_VOID ? FR_TYPE_NULL : type),
Expand All @@ -330,7 +330,7 @@ static int call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *parsed, char
case TMPL_TYPE_DATA:
case TMPL_TYPE_EXEC:
case TMPL_TYPE_XLAT:
if (call_env->type & CONF_FLAG_ATTRIBUTE) {
if (call_env_attribute(call_env->flags)) {
cf_log_perr(cp, "'%s' expands to %s - attribute reference required", value,
fr_table_str_by_value(tmpl_type_table, call_env_parsed->tmpl->type,
"<INVALID>"));
Expand Down Expand Up @@ -375,7 +375,7 @@ static size_t call_env_count(size_t *names_len, CONF_SECTION const *cs, call_env
*names_len = 0;

while (call_env->name) {
if (call_env->flags & CONF_FLAG_SUBSECTION) {
if (call_env_is_subsection(call_env->flags)) {
CONF_SECTION const *subcs;
subcs = cf_section_find(cs, call_env->name, call_env->section.ident2);
if (!subcs) goto next;
Expand All @@ -389,9 +389,9 @@ static size_t call_env_count(size_t *names_len, CONF_SECTION const *cs, call_env
pair_count++;
*names_len += talloc_array_length(cf_pair_value(cp));
}
if (!pair_count && call_env->dflt) {
if (!pair_count && call_env->pair.dflt) {
pair_count = 1;
*names_len += strlen(call_env->dflt);
*names_len += strlen(call_env->pair.dflt);
}
tmpl_count += pair_count;
next:
Expand Down
163 changes: 100 additions & 63 deletions src/lib/unlang/call_env.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,59 @@ typedef enum {
CALL_ENV_TYPE_VALUE_BOX = 1,
CALL_ENV_TYPE_VALUE_BOX_LIST,
CALL_ENV_TYPE_TMPL_ONLY
} call_env_dest_t;
} call_env_dst_t;

DIAG_OFF(attributes)
typedef enum CC_HINT(flag_enum) {
CALL_ENV_FLAG_NONE = 0,
CALL_ENV_FLAG_REQUIRED = 1, //!< Tmpl must produce output or section is required.
CALL_ENV_FLAG_CONCAT = (1 << 1), //!< If the tmpl produced multiple boxes they should be concatenated.
CALL_ENV_FLAG_SINGLE = (1 << 2), //!< If the tmpl produces more than one box this is an error.
CALL_ENV_FLAG_MULTI = (1 << 3), //!< Multiple instances of the conf pairs are allowed. Resulting
///< boxes are stored in an array - one entry per conf pair.
CALL_ENV_FLAG_NULLABLE = (1 << 4), //!< Tmpl expansions are allowed to produce no output.
CALL_ENV_FLAG_FORCE_QUOTE = (1 << 5), //!< Force quote method when parsing tmpl. This is for corner cases
///< where tmpls should always be parsed with a particular quoting
///< regardless of how they are in the config file. E.g. the `program`
///< option of `rlm_exec` should always be parsed as T_BACK_QUOTED_STRING.
CALL_ENV_FLAG_ATTRIBUTE = (1 << 6), //!< Tmpl must contain an attribute reference.
CALL_ENV_FLAG_SUBSECTION = (1 << 7) //!< This is a subsection.
} call_env_flags_t;
DIAG_ON(attributes)


/** @name #conf_parser_t flags checks
*
* @{
*/
/** Evaluates to true if flags are valid for a pair
*
* @param[in] _flags to evaluate
*/
#define call_env_pair_flags(_flags) (((_flags) & (CALL_ENV_FLAG_SUBSECTION)) == 0)

/** Evaluates to true if flags are valid for a subsection
*
* @param[in] _flags to evaluate
*/
#define call_env_subsection_flags(_flags) (((_flags) & (CALL_ENV_FLAG_CONCAT | CALL_ENV_FLAG_SINGLE | CALL_ENV_FLAG_MULTI | CALL_ENV_FLAG_NULLABLE | CALL_ENV_FLAG_FORCE_QUOTE | CALL_ENV_FLAG_ATTRIBUTE)) == 0)

#define call_env_required(_flags) ((_flags) & CALL_ENV_FLAG_REQUIRED)

#define call_env_concat(_flags) ((_flags) & CALL_ENV_FLAG_CONCAT)

#define call_env_single(_flags) ((_flags) & CALL_ENV_FLAG_SINGLE)

#define call_env_multi(_flags) ((_flags) & CALL_ENV_FLAG_MULTI)

#define call_env_nullable(_flags) ((_flags) & CALL_ENV_FLAG_NULLABLE)

#define call_env_force_quote(_flags) ((_flags) & CALL_ENV_FLAG_FORCE_QUOTE)

#define call_env_attribute(_flags) ((_flags) & CALL_ENV_FLAG_ATTRIBUTE)

#define call_env_is_subsection(_flags) ((_flags) & CALL_ENV_FLAG_SUBSECTION)
/** @} */

/** Per method call config
*
Expand All @@ -65,37 +117,29 @@ typedef enum {
* and use the appropriate dictionaries for where the module is in use.
*/
struct call_env_parser_s {
char const *name; //!< Of conf pair to pass to tmpl_tokenizer.
char const *dflt; //!< Default string to pass to the tmpl_tokenizer if no CONF_PAIR found.
fr_token_t dflt_quote; //!< Default quoting for the default string.
char const *name; //!< Of conf pair to pass to tmpl_tokenizer.
call_env_flags_t flags; //!< Flags controlling parser behaviour.

fr_type_t type; //!< To cast boxes to. Also contains flags controlling parser behaviour.
conf_parser_flags_t flags; //!< Flags controlling parser behaviour.

size_t offset; //!< Where to write results in the output structure when the tmpls are evaluated.
ssize_t parsed_offset; //!< Where to write the result of the parsing phase.
///< This is usually a tmpl_t, but could be other things when a callback
///< function is used to parse the CONF_SECTION or CONF_PAIR.

union {
struct {
bool required; //!< Tmpl must produce output
bool concat; //!< If the tmpl produced multiple boxes they should be concatenated.
bool single; //!< If the tmpl produces more than one box this is an error.
bool multi; //!< Multiple instances of the conf pairs are allowed. Resulting
///< boxes are stored in an array - one entry per conf pair.
bool nullable; //!< Tmpl expansions are allowed to produce no output.
bool force_quote; //!< Force quote method when parsing tmpl. This is for corner cases
///< where tmpls should always be parsed with a particular quoting
///< regardless of how they are in the config file. E.g. the `program`
///< option of `rlm_exec` should always be parsed as T_BACK_QUOTED_STRING.
call_env_dest_t type; //!< Type of structure boxes will be written to.
size_t size; //!< Size of structure boxes will be written to.
char const *type_name; //!< Name of structure type boxes will be written to.
ssize_t tmpl_offset; //!< Where to write pointer to tmpl in the output structure. Optional.
fr_type_t cast_type; //!< To cast boxes to. Also contains flags controlling parser behaviour.

call_env_dst_t type; //!< Type of structure boxes will be written to.
size_t size; //!< Size of structure boxes will be written to.
char const *type_name; //!< Name of structure type boxes will be written to.
size_t result_offset; //!< Where to write the result of evaluating the tmpl_t produced in the parsing phase.

char const *dflt; //!< Default string to pass to the tmpl_tokenizer if no CONF_PAIR found.
fr_token_t dflt_quote; //!< Quoting for the default string.
} pair;

struct {
char const *ident2; //!< Second identifier for a section
call_env_parser_t const *subcs; //!< Nested definitions for subsection.
bool required; //!< Section is required.
} section;
};
};
Expand Down Expand Up @@ -137,20 +181,20 @@ struct call_env_s {
*/
#define FR_CALL_ENV_SINGLE(_s, _f, _c) \
_Generic((((_s *)NULL)->_f), \
fr_value_box_t : __builtin_choose_expr(_c, false, true), \
fr_value_box_t * : __builtin_choose_expr(_c, false, true), \
fr_value_box_list_t : false, \
fr_value_box_list_t * : false \
fr_value_box_t : __builtin_choose_expr(_c, CALL_ENV_FLAG_NONE, CALL_ENV_FLAG_SINGLE), \
fr_value_box_t * : __builtin_choose_expr(_c, CALL_ENV_FLAG_NONE, CALL_ENV_FLAG_SINGLE), \
fr_value_box_list_t : CALL_ENV_FLAG_NONE, \
fr_value_box_list_t * : CALL_ENV_FLAG_SINGLE \
)

/** Derive whether multi conf pairs are allowed from target field type.
*/
#define FR_CALL_ENV_MULTI(_s, _f) \
_Generic((((_s *)NULL)->_f), \
fr_value_box_t : false, \
fr_value_box_t * : true, \
fr_value_box_list_t : false, \
fr_value_box_list_t * : true \
fr_value_box_t : CALL_ENV_FLAG_NONE, \
fr_value_box_t * : CALL_ENV_FLAG_MULTI, \
fr_value_box_list_t : CALL_ENV_FLAG_NONE, \
fr_value_box_list_t * : CALL_ENV_FLAG_MULTI \
)

/** Only FR_TYPE_STRING and FR_TYPE_OCTETS can be concatenated.
Expand Down Expand Up @@ -186,64 +230,57 @@ _Generic((((_s *)NULL)->_f), \
fr_value_box_list_t * : "fr_value_box_list_t" \
)

#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field, _dflt, _dflt_quote, _required, _nullable, _concat) \
typedef void _mismatch_flags; //!< Dummy type used to indicate bad flags.

#define CALL_ENV_FLAGS(_cast_type, _flags, _struct, _field) \
(FR_CALL_ENV_CONCAT((_flags & CALL_ENV_FLAG_CONCAT), _cast_type) | \
FR_CALL_ENV_SINGLE(_struct, _field, (_flags & CALL_ENV_FLAG_CONCAT)) | \
FR_CALL_ENV_MULTI(_struct, _field) |\
((_flags) & ~CALL_ENV_FLAG_CONCAT)) \

#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field) \
.name = _name, \
.type = _cast_type, \
.offset = offsetof(_struct, _field), \
.dflt = _dflt, \
.dflt_quote = _dflt_quote, \
.flags = CALL_ENV_FLAGS(_cast_type, _flags, _struct, _field), \
.parsed_offset = -1, \
.pair = { \
.required = _required, \
.concat = FR_CALL_ENV_CONCAT(_concat, _cast_type), \
.single = FR_CALL_ENV_SINGLE(_struct, _field, _concat), \
.multi = FR_CALL_ENV_MULTI(_struct, _field), \
.nullable = _nullable, \
.cast_type = _cast_type, \
.type = FR_CALL_ENV_DST_TYPE(_struct, _field), \
.size = FR_CALL_ENV_DST_SIZE(_struct, _field), \
.type_name = FR_CALL_ENV_DST_TYPE_NAME(_struct, _field), \
.tmpl_offset = -1 \
.result_offset = offsetof(_struct, _field), \
}

/** Version of the above which sets optional field for pointer to tmpl
*/
#define FR_CALL_ENV_TMPL_OFFSET(_name, _cast_type, _flags, _struct, _field, _tmpl_field, _dflt, _dflt_quote, _required, _nullable, _concat) \
#define FR_CALL_ENV_TMPL_OFFSET(_name, _cast_type, _flags, _struct, _field, _tmpl_field) \
.name = _name, \
.type = _cast_type, \
.offset = offsetof(_struct, _field), \
.dflt = _dflt, \
.dflt_quote = _dflt_quote, \
.flags = CALL_ENV_FLAGS(_cast_type, _flags, _struct, _field), \
.parsed_offset = offsetof(_struct, _tmpl_field), \
.pair = { \
.required = _required, \
.concat = FR_CALL_ENV_CONCAT(_concat, _cast_type), \
.single = FR_CALL_ENV_SINGLE(_struct, _field, _concat), \
.multi = FR_CALL_ENV_MULTI(_struct, _field), \
.nullable = _nullable, \
.cast_type = _cast_type, \
.type = FR_CALL_ENV_DST_TYPE(_struct, _field), \
.size = FR_CALL_ENV_DST_SIZE(_struct, _field), \
.type_name = FR_CALL_ENV_DST_TYPE_NAME(_struct, _field), \
.tmpl_offset = offsetof(_struct, _tmpl_field) \
.result_offset = offsetof(_struct, _field), \
}

/** Version of the above which only sets the field for a pointer to the tmpl
*/
#define FR_CALL_ENV_TMPL_ONLY_OFFSET(_name, _cast_type, _flags, _struct, _tmpl_field, _dflt, _dflt_quote, _required) \
#define FR_CALL_ENV_TMPL_ONLY_OFFSET(_name, _cast_type, _flags, _struct, _tmpl_field) \
.name = _name, \
.type = _cast_type, \
.dflt = _dflt, \
.dflt_quote = _dflt_quote, \
.flags = _flags, \
.parsed_offset = offsetof(_struct, _tmpl_field), \
.pair = { \
.required = _required, \
.type = CALL_ENV_TYPE_TMPL_ONLY, \
.tmpl_offset = offsetof(_struct, _tmpl_field) \
.cast_type = _cast_type, \
.type = CALL_ENV_TYPE_TMPL_ONLY \
}

#define FR_CALL_ENV_SUBSECTION(_name, _ident2, _subcs, _required ) \
#define FR_CALL_ENV_SUBSECTION(_name, _ident2, _flags, _subcs ) \
.name = _name, \
.flags = CONF_FLAG_SUBSECTION, \
.flags = CALL_ENV_FLAG_SUBSECTION | (_flags), \
.section = { \
.ident2 = _ident2, \
.subcs = _subcs, \
.required = _required \
}

unlang_action_t call_env_expand(TALLOC_CTX *ctx, request_t *request, call_env_result_t *result, void **env_data, call_env_t const *call_env);
Expand Down
3 changes: 1 addition & 2 deletions src/modules/rlm_cache/rlm_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ typedef struct {
static const call_env_method_t cache_method_env = {
FR_CALL_ENV_METHOD_OUT(cache_call_env_t),
.env = (call_env_parser_t[]) {
{ FR_CALL_ENV_OFFSET("key", FR_TYPE_STRING, 0, cache_call_env_t, key,
NULL, T_INVALID, true, false, true) },
{ FR_CALL_ENV_OFFSET("key", FR_TYPE_STRING, CALL_ENV_FLAG_REQUIRED | CALL_ENV_FLAG_CONCAT, cache_call_env_t, key) },
CALL_ENV_TERMINATOR
}
};
Expand Down
Loading

0 comments on commit a84044b

Please sign in to comment.