25RCSID(
"$Id: d65889d5a62669af28fdabaa9d1b7b2ca2b29b8b $")
27#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
29#include <freeradius-devel/server/virtual_servers.h>
31#include <freeradius-devel/server/cf_file.h>
32#include <freeradius-devel/server/main_config.h>
33#include <freeradius-devel/server/map_proc.h>
34#include <freeradius-devel/server/modpriv.h>
35#include <freeradius-devel/server/module_rlm.h>
37#include <freeradius-devel/server/tmpl.h>
38#include <freeradius-devel/server/cf_util.h>
39#include <freeradius-devel/util/time.h>
40#include <freeradius-devel/util/dict.h>
60#define UNLANG_IGNORE ((unlang_t *) -1)
110static inline CC_HINT(always_inline)
123 memset(&dst->actions.retry, 0,
sizeof(dst->actions.retry)); \
126#define UPDATE_CTX2 compile_copy_context(&unlang_ctx2, unlang_ctx)
149#define ATTR_RULES_VERIFY(_rules) if (unlang_attr_rules_verify(_rules) < 0) return NULL;
151#define RULES_VERIFY(_rules) do { if (unlang_rules_verify(_rules) < 0) return NULL; } while (0)
196 cf_log_err(map->
ci,
"Invalid operator \"%s\" in nested map section. "
197 "Only '=' is allowed",
216 if (!map_list_empty(&map->
child)) {
221 cf_log_err(map->
ci,
"Sublists can only be assigned to a known attribute");
230 for (child = map_list_next(&map->
child, NULL);
232 child = map_list_next(&map->
child, child)) {
252 while ((map = map_list_next(&gext->
map, map))) {
285 while ((map = map_list_next(&gext->
map, map))) {
292 if (!gext->
vpt)
return true;
305 for (c = instruction; c != NULL; c = c->
next) {
334 while ((map = map_list_next(&gext->
map, map))) {
349 while ((map = map_list_next(&edit->
maps, map))) {
350 if (!map->
rhs)
continue;
413 cf_log_warn(cp,
"Please change attribute reference to '&%s %s ...'",
418 cf_log_warn(cp,
"Please change attribute reference to '... %s &%s'",
423 switch (map->
lhs->type) {
430 cf_log_err(map->
ci,
"Left side of map must be an attribute "
431 "or an xlat (that expands to an attribute), not a %s",
436 switch (map->
rhs->type) {
446 cf_log_err(map->
ci,
"Right side of map must be an attribute, literal, xlat or exec, got type %s",
452 cf_log_err(map->
ci,
"Invalid operator \"%s\" in map section. "
453 "Only assignment or filter operators are allowed",
479 cf_log_warn(cp,
"Please change attribute reference to '&%s %s ...'",
484 cf_log_warn(cp,
"Please change attribute reference to '... %s &%s'",
493 switch (map->
rhs->type) {
510 WARN(
"%s[%d] Wildcard deletion MUST use '!* ANY'",
514 TALLOC_FREE(map->
rhs);
532 cf_log_err(map->
ci,
"Can't copy list into an attribute");
537 cf_log_err(map->
ci,
"Invalid operator \"%s\" in update section. "
538 "Only assignment or filter operators are allowed",
544 cf_log_warn(cp,
"Please use the 'filter' keyword for attribute filtering");
578 cf_log_perr(map->
ci,
"Cannot convert RHS value (%s) to LHS attribute type (%s)",
589 cf_log_err(map->
ci,
"Cannot determine what update action to perform");
701 quoted_str = talloc_array(g,
char, quoted_len);
727 char const *tmpl_str;
741 .type_name =
"unlang_map_t"
753 cf_log_err(cs,
"'map' sections require a 'modules' section");
759 cf_log_err(cs,
"Failed to find map processor '%s'", name2);
784 &
FR_SBUFF_IN(tmpl_str, talloc_array_length(tmpl_str) - 1),
811 cf_log_err(cs,
"Invalid third argument for map");
819 map_list_init(&gext->
map);
821 if (rcode < 0)
return NULL;
822 if (map_list_empty(&gext->
map)) {
823 cf_log_err(cs,
"'map' sections cannot be empty");
834 cf_log_err(cs,
"Failed instantiating map function '%s'", name2);
867 if (child) *child = cs;
886 if (!original)
return 0;
897 if (*attr ==
'&') attr++;
898 cf_log_err(original,
"%s %s %s --> %s %s { %s %s %s }",
907 cf_log_err(original,
"--> %s %s { %s %s %s }",
924 char list_buffer[32];
925 char value_buffer[256];
926 char attr_buffer[256];
936 if (!group)
return NULL;
945 if (*name2 ==
'&') name2++;
946 snprintf(list_buffer,
sizeof(list_buffer),
"&%s", name2);
962 char const *attr, *
value, *end;
965 cf_log_err(ci,
"Cannot specify subsections for 'update'");
982 if (*attr ==
'&') attr++;
984 end = strchr(attr,
'.');
985 if (!end) end = attr + strlen(attr);
1013 (strchr(
value,
'.') == NULL) && (strchr(
value,
'[') != NULL)) {
1014 char const *p = strchr(
value,
'[');
1016 cf_log_err(cp,
"Cannot do array assignments for lists. Just use '%s %s %.*s'",
1030 snprintf(attr_buffer,
sizeof(attr_buffer),
"&%s", attr);
1034 p = strchr(attr_buffer,
'.');
1056 if (strchr(attr,
'[') == NULL) {
1057 snprintf(value_buffer,
sizeof(value_buffer),
"&%s[*]", attr);
1059 snprintf(value_buffer,
sizeof(value_buffer),
"&%s", attr);
1093 if (
snprintf(value_buffer,
sizeof(value_buffer),
"%s.%s", list, attr) < 0) {
1094 cf_log_err(cp,
"RHS of update too long to convert to edit automatically");
1103 if (!attr)
goto list_op;
1106 if (rcode < 0)
break;
1108 snprintf(attr_buffer,
sizeof(attr_buffer),
"&%s", attr);
1120 cf_log_err(cp,
"Invalid operator for list assignment");
1125 if (rcode < 0)
break;
1127 if (strchr(attr,
'[') != 0) {
1128 cf_log_err(cp,
"Cannot do filtering with array indexes");
1132 snprintf(attr_buffer,
sizeof(attr_buffer),
"&%s", attr);
1164 cf_log_err(cp,
"Unsupported operator - cannot auto-convert to edit section");
1193 .type_name =
"unlang_map_t"
1197 cf_log_err(cs,
"The use of 'update' sections is forbidden by the server configuration");
1218 if (!g)
return NULL;
1225 map_list_init(&gext->
map);
1227 if (rcode < 0)
return NULL;
1228 if (map_list_empty(&gext->
map)) {
1229 cf_log_err(cs,
"'update' sections cannot be empty");
1251#define T(_x) [T_OP_ ## _x] = true
1279 map_t *parent_map = ctx;
1282#ifdef STATIC_ANALYZER
1283 if (!parent_map)
return -1;
1290 cf_log_err(cp,
"Invalid operator '%s' for right-hand side list. It must be a comparison operator",
fr_tokens[map->
op]);
1295 cf_log_err(cp,
"Invalid operator '%s' for right-hand side list. It must be '='",
fr_tokens[map->
op]);
1311 cf_log_warn(cp,
"Please change attribute reference to '&%s %s ...'",
1316 cf_log_warn(cp,
"Please change attribute reference to '... %s &%s'",
1321 switch (map->
lhs->type) {
1325 (da->parent !=
parent)) {
1327 cf_log_err(cp,
"Invalid location for %s - it is not a child of %s",
1338 cf_log_err(map->
ci,
"Left side of map must be an attribute "
1339 "or an xlat (that expands to an attribute), not a %s",
1346 switch (map->
rhs->type) {
1356 cf_log_err(map->
ci,
"Right side of map must be an attribute, literal, xlat or exec, got type %s",
1405 if (!edit)
return NULL;
1415 map_list_init(&edit->
maps);
1425 map_list_init(&map->
child);
1461 !((parent_da->type ==
FR_TYPE_GROUP) && parent_da->flags.internal)) {
1462 t_rules.
attr.namespace = parent_da;
1473 for (child = map_list_head(&map->
child); child != NULL; child = map_list_next(&map->
child, child)) {
1477 cf_log_err(child->
ci,
"Cannot use array references and values when deleting from a list");
1485 cf_log_err(child->
ci,
"List deletion must operate directly on the final child");
1493 cf_log_err(child->
ci,
"List deletion cannot operate on lists");
1507 cf_log_err(cs,
"Cannot use operator '%s' for assigning empty list to '%s' data type.",
1523 map_list_insert_tail(&edit->
maps, map);
1549 if (!edit)
return NULL;
1559 map_list_init(&edit->
maps);
1573 if (
map_afrom_cp(edit, &map, map_list_tail(&edit->
maps), cp, &t_rules, NULL,
true) < 0) {
1588 cf_log_err(cp,
"Invalid array reference in %s", map->
lhs->name);
1594 cf_log_err(cp,
"Cannot delete local variable %s", map->
rhs->name);
1610 map_list_insert_tail(&edit->
maps, map);
1628 char const *attr, *
value;
1652 cf_log_err(cp,
"Local variables cannot be used here");
1665 if (!var)
return -1;
1685 t_rules->
attr.namespace = NULL;
1696 cf_log_err(cp,
"Invalid data type '%s'", attr);
1714 char const *attr, *
value;
1718 if (!
value)
return 0;
1732 else if (strspn(
value,
"0123456789")==strlen(
value)) {
1733 action = atoi(
value);
1736 cf_log_err(cp,
"Priorities MUST be between 1 and 64.");
1752 "Unknown module rcode '%s'.",
1756 actions->
actions[rcode] = action;
1782 cf_log_err(csi,
"Invalid subsection in 'retry' configuration.");
1793 cf_log_err(csi,
"Retry configuration must specify a value");
1801 if (strcmp(
name,
"initial_rtx_time") == 0) {
1804 cf_log_err(csi,
"Failed parsing '%s = %s' - %s",
1809 }
else if (strcmp(
name,
"max_rtx_time") == 0) {
1813 cf_log_err(csi,
"Invalid value for 'max_rtx_time = %s' - value must be positive",
1818 }
else if (strcmp(
name,
"max_rtx_count") == 0) {
1819 unsigned long v = strtoul(
value, 0, 0);
1822 cf_log_err(csi,
"Invalid value for 'max_rtx_count = %s' - value must be between 0 and 65536",
1829 }
else if (strcmp(
name,
"max_rtx_duration") == 0) {
1833 cf_log_err(csi,
"Invalid value for 'max_rtx_duration = %s' - value must be positive",
1839 cf_log_err(csi,
"Invalid item '%s' in 'retry' configuration.",
name);
1850 bool disallow_retry_action =
false;
1877 cf_log_err(csi,
"Invalid subsection. Expected 'action = value'");
1889 if (strcmp(
name,
"retry") == 0) {
1910 cf_log_err(csi,
"initial_rtx_time MUST be non-zero for modules which support retries.");
1915 cf_log_err(csi,
"initial_rtx_time MUST be zero, as only max_rtx_count and max_rtx_duration are used.");
1920 disallow_retry_action =
true;
1932 cf_log_err(csi,
"Cannot use a '%s = retry' action for a module which has its own retries",
1937 if (disallow_retry_action) {
1938 cf_log_err(csi,
"max_rtx_count and max_rtx_duration cannot both be zero when using '%s = retry'",
1946 cf_log_err(csi,
"Cannot use a '%s = retry' action without a 'retry { ... }' section.",
1966 if (!g)
return NULL;
2004 cf_log_err(ci,
"'actions' MUST be the last block in a section");
2009 cf_log_err(ci,
"Invalid name for 'actions' section");
2051 bool was_if =
false;
2052 char const *skip_else = NULL;
2065 t_rules = *unlang_ctx_in->
rules;
2078 char const *
name = NULL;
2106 if (strcmp(
name,
"actions") == 0) {
2118 if ((strcmp(
name,
"else") == 0) || (strcmp(
name,
"elsif") == 0)) {
2124 cf_log_err(ci,
"Invalid location for '%s'. There is no preceding "
2125 "'if' or 'elsif' statement",
name);
2146 "'%s' being always being taken.",
2203 cf_log_err(ci,
"Asked to compile unknown conf type");
2215 switch (single->
type) {
2270 cf_log_warn(ci,
"Skipping remaining instructions due to '%s'",
2294 char const *name1, *name2;
2303 if (!g)
return NULL;
2321 }
else if (!name2) {
2337 .type_name =
"unlang_group_t",
2349 {
L(
"foreach"), 1 },
2353 {
L(
"load-balance"), 1 },
2354 {
L(
"redundant"), 1 },
2355 {
L(
"redundant-load-balance"), 1 },
2357 {
L(
"timeout"), 1 },
2358 {
L(
"transaction"), 1 },
2377 if (strcmp(
name,
"actions") == 0)
continue;
2382 if (*
name ==
'&')
continue;
2387 cf_log_err(ci,
"Invalid keyword in 'transaction'");
2406 if (*
name ==
'&')
continue;
2415 cf_log_err(ci,
"Invalid module reference in 'transaction'");
2436 .type_name =
"unlang_transaction_t",
2440 cf_log_err(cs,
"Unexpected argument to 'transaction' section");
2462 if (!g)
return NULL;
2492 .type_name =
"unlang_try_t",
2499 cf_log_err(cs,
"'try' sections cannot be empty");
2504 cf_log_err(cs,
"Unexpected argument to 'try' section");
2510 cf_log_err(cs,
"'try' sections must be followed by a 'catch'");
2515 if (!g)
return NULL;
2553 .type_name =
"unlang_catch_t",
2557 if (!g)
return NULL;
2598static int8_t
case_cmp(
void const *one,
void const *two)
2627 char const *name1, *name2;
2643 .type_name =
"unlang_switch_t",
2657 cf_log_err(cs,
"You must specify a variable to switch over for 'switch'");
2664 if (!g)
return NULL;
2711 cf_log_err(cs,
"Cannot use list for 'switch' statement");
2716 cf_log_err(cs,
"Cannot use regular expression for 'switch' statement");
2721 cf_log_err(cs,
"Cannot use constant data for 'switch' statement");
2742 cf_log_err(cs,
"Invalid data type '%s' used for 'switch' statement",
2753 cf_log_err(cs,
"Failed initializing internal data structures");
2771 cf_log_err(subci,
"\"switch\" sections can only have \"case\" subsections");
2778 if (strcmp(name1,
"case") != 0) {
2782 if (strcmp(name1,
"default") == 0) {
2784 cf_log_err(subci,
"\"default\" sections cannot have a match argument");
2787 goto handle_default;
2790 cf_log_err(subci,
"\"switch\" sections can only have \"case\" subsections");
2798 cf_log_err(subci,
"Cannot have two 'default' case statements");
2807 if (!single)
goto error;
2816 if (!case_gext->
vpt) {
2825 cf_log_err(subci,
"Failed inserting 'case' statement. Is there a duplicate?");
2856 .type_name =
"unlang_case_t",
2867 cf_log_err(cs,
"\"case\" statements may only appear within a \"switch\" section");
2902 if (da->flags.has_value) t_rules.
enumv = da;
2922 cf_log_err(cs,
"arguments to 'case' statements MUST NOT be attribute references.");
2927 cf_log_err(cs,
"arguments to 'case' statements MUST be static data.");
2957 case_gext->
vpt = talloc_steal(case_gext,
vpt);
2983 .type_name =
"unlang_timeout_t",
2991 cf_log_err(cs,
"You must specify a time value for 'timeout'");
2998 if (!g)
return NULL;
3006 cf_log_err(cs,
"Failed parsing time delta %s - %s",
3042 cf_log_err(cs,
"Cannot use list as argument for 'timeout' statement");
3047 cf_log_err(cs,
"Cannot use regular expression as argument for 'timeout' statement");
3064 if (!c)
return NULL;
3090 .type_name =
"unlang_limit_t",
3098 cf_log_err(cs,
"You must specify a value for 'limit'");
3105 if (!g)
return NULL;
3140 cf_log_err(cs,
"Cannot use list as argument for 'limit' statement");
3145 cf_log_err(cs,
"Cannot use regular expression as argument for 'limit' statement");
3154 limit = box.vb_uint32;
3170 if (!c)
return NULL;
3174 gext->
limit = limit;
3185 char const *type_name, *variable_name;
3190 char const *key_name;
3205 .type_name =
"unlang_foreach_t",
3232 if (!g)
return NULL;
3244 cf_log_err(cs,
"Data being looped over in 'foreach' must be an attribute reference or dynamic expansion, not a string");
3268 cf_log_warn(cs,
"Attribute reference should be updated to use %s[*]",
vpt->name);
3273 cf_log_err(cs,
"MUST NOT use instance selectors in 'foreach'");
3278 cf_log_err(cs,
"Invalid contents in 'foreach (...)', it must be an attribute reference or a dynamic expansion");
3285 c->
name =
"foreach";
3300 unlang_ctx2.
rules = &t_rules;
3321 cf_log_err(cs,
"Dynamic expansions MUST specify a data type for the variable");
3327 cf_log_err(cs,
"Dynamic expansions MUST specify a non-structural data type for the variable");
3366 cf_log_err(cs,
"Incompatible data types in foreach variable (%s), and reference %s being looped over (%s)",
3381 if (!var)
goto fail;
3384 if (!var->
dict)
goto fail;
3393 t_rules.
attr.namespace = NULL;
3424 .type_name =
"unlang_group_t",
3427 for (
foreach =
parent;
foreach != NULL;
foreach =
foreach->parent) {
3441 cf_log_err(ci,
"'break' can only be used in a 'foreach' section");
3457 .type_name =
"unlang_group_t",
3460 for (subrequest =
parent;
3462 subrequest = subrequest->
parent) {
3467 cf_log_err(ci,
"'detach' can only be used inside of a 'subrequest' section.");
3476 cf_log_err(ci,
"'detach' cannot be used as the last entry in a section, as there is nothing more to do");
3488 .type_name =
"unlang_group_t",
3582 .allow_unresolved =
true,
3583 .allow_unknown =
true
3587 fr_sbuff_parse_rules_t p_rules = { };
3629 if (!c)
return NULL;
3647 .type_name =
"unlang_cond_t",
3660 .type_name =
"unlang_cond_t",
3675 .type_name =
"unlang_group_t"
3679 cf_log_err(cs,
"'else' cannot have a condition");
3715 if ((strcmp(name1,
"else") == 0) ||
3716 (strcmp(name1,
"elsif") == 0)) {
3717 cf_log_err(ci,
"%s sections cannot contain a \"%s\" statement",
3748 .type_name =
"unlang_group_t"
3758 if (!c)
return NULL;
3795 if (!c)
return NULL;
3843 switch (gext->
vpt->type) {
3845 cf_log_err(cs,
"Invalid type in '%s': data will not result in a load-balance key", name2);
3867 .type_name =
"unlang_load_balance_t"
3876 static unlang_ext_t const redundant_load_balance_ext = {
3879 .type_name =
"unlang_load_balance_t"
3895 bool detach =
false;
3900 .type_name =
"unlang_parallel_t"
3913 if (strcmp(name2,
"empty") == 0) {
3916 }
else if (strcmp(name2,
"detach") == 0) {
3920 cf_log_err(cs,
"Invalid argument '%s'", name2);
3935 if (!c)
return NULL;
3939 gext->
clone = clone;
3964 char *
namespace = NULL;
3968 tmpl_t *
vpt = NULL, *src_vpt = NULL, *dst_vpt = NULL;
3973 .type_name =
"unlang_subrequest_t",
3990 goto get_packet_type;
3994 cf_log_err(cs,
"The arguments to 'subrequest' must be a name or an attribute reference");
4001 if ((name2[0] ==
':') && (name2[1] ==
':')) {
4004 goto get_packet_type;
4012 if ((name2[0] ==
'&') ||
4017 &
FR_SBUFF_IN(name2, talloc_array_length(name2) - 1),
4020 cf_log_perr(cs,
"Invalid argument to 'subrequest', failed parsing packet-type");
4036 cf_log_err(cs,
"Invalid data type for attribute %s. "
4037 "Must be an integer type or string", name2 + 1);
4044 goto get_packet_type;
4054 cf_log_err(cs,
"Invalid syntax in namespace::enum");
4058 MEM(
namespace = talloc_strdup(
parent, name2));
4060 p =
namespace + (p - name2);
4069 cf_log_err(cs,
"Unknown namespace '%s'",
namespace);
4075 goto get_packet_type;
4083 p = strchr(name2,
'.');
4094 MEM(
namespace = talloc_strdup(
parent, name2));
4096 p =
namespace + (p - name2);
4104 cf_log_err(cs,
"Unknown namespace '%s'",
namespace);
4110 WARN(
"Deprecated syntax 'subrequest %s ...'", name2);
4111 WARN(
" please switch to 'subrequest %s::%s ...",
namespace,
packet_name);
4144 cf_log_err(cs,
"No such value '%s' for attribute 'Packet-Type' in namespace '%s'",
4159 char const *dst, *src;
4169 cf_log_perr(cs,
"Invalid argument to 'subrequest', failed parsing src");
4174 cf_log_err(cs,
"Invalid argument to 'subrequest' src must be an attr or list, got %s",
4188 cf_log_perr(cs,
"Invalid argument to 'subrequest', failed parsing dst");
4193 cf_log_err(cs,
"Invalid argument to 'subrequest' dst must be an "
4194 "attr or list, got %s",
4228 unlang_ctx2.
rules = &t_rules;
4234 if (!c)
return NULL;
4249 talloc_steal(gext, dict_ref);
4251 if (
vpt) gext->
vpt = talloc_steal(gext,
vpt);
4256 gext->
src = src_vpt;
4257 gext->
dst = dst_vpt;
4281 .type_name =
"unlang_call_t",
4286 cf_log_err(cs,
"You MUST specify a server name for 'call <server> { ... }'");
4292 cf_log_err(cs,
"The arguments to 'call' cannot be a quoted string or a dynamic value");
4298 cf_log_err(cs,
"Unknown virtual server '%s'", server);
4309 cf_log_err(cs,
"Cannot call virtual server '%s', failed retrieving its namespace",
4315 cf_log_err(cs,
"Cannot call server %s with namespace '%s' from namespaces '%s' - they have incompatible protocols",
4322 cf_log_err(cs,
"Cannot call server %s with namespace '%s' - it has no Packet-Type attribute",
4328 if (!c)
return NULL;
4362 .type_name =
"unlang_caller_t",
4367 cf_log_err(cs,
"You MUST specify a protocol name for 'caller <protocol> { ... }'");
4373 cf_log_err(cs,
"The argument to 'caller' cannot be a quoted string or a dynamic value");
4389 memcpy(&parent_rules,
unlang_ctx->rules,
sizeof(parent_rules));
4390 memcpy(&t_rules,
unlang_ctx->rules,
sizeof(t_rules));
4392 t_rules.
parent = &parent_rules;
4398 memcpy(&unlang_ctx2,
unlang_ctx,
sizeof(unlang_ctx2));
4399 unlang_ctx2.
rules = &t_rules;
4423 talloc_steal(gext, dict_ref);
4444 .type_name =
"unlang_group_t",
4450 .type_name =
"unlang_group_t",
4468 cf_log_err(subcs,
"Unexpected second name in policy");
4487 policy ? &policy_ext : &group_ext);
4489 if (!c)
return NULL;
4523 UNUSED char const *real_name,
char const *virtual_name,
char const *method_name,
4544 if (subcs)
goto check_for_loop;
4552 if (!cs)
return NULL;
4563 if (!subcs)
return NULL;
4565 goto check_for_loop;
4582 if (!subcs)
return NULL;
4611 &(
section_name_t){ .name1 = unlang_ctx->section_name1, .name2 = unlang_ctx->section_name2 },
4646 "but no inst_size set",
4656 .type = CALL_ENV_CTX_TYPE_MODULE,
4658 .asked = &m->mmc.asked
4730 cf_log_err(ci,
"Local variable '%s' cannot be a list reference.",
name);
4742 cf_log_err(ci,
"Local variable '%s' cannot be an unlang keyword.",
name);
4755 cf_log_err(ci,
"Local variable '%s' cannot be an existing protocol name.",
name);
4766 cf_log_err(ci,
"Local variable '%s' duplicates a dictionary attribute.",
name);
4815 char const *
name, *p;
4817 char const *realname;
4822 bool ignore_notfound =
false;
4834 if (!c)
return NULL;
4846 cf_log_err(ci,
"Instruction \"%s\" number %u has conflict with previous one.",
4859 cf_log_err(ci,
"Syntax error after keyword '%s' - unexpected '{'",
name);
4864 goto check_for_module;
4879 cf_log_err(ci,
"Entry is not a reference to a module");
4888 if ((
name[0] ==
'%') ||
4891 goto allocate_number;
4897 goto allocate_number;
4904 cf_log_err(ci,
"Syntax error after keyword '%s' - expected '{'",
name);
4908 goto check_for_module;
4910 cf_log_err(ci,
"Asked to compile unknown conf type");
4948 p = strrchr(
name,
'.');
4969 goto allocate_number;
4977 cf_log_err(ci,
"Failed compiling \"%s\" as a module or policy as no modules are enabled",
name);
4978 cf_log_err(ci,
"Please verify that modules { ... } section is present in the server configuration");
4987 if (*realname ==
'-') {
4988 ignore_notfound =
true;
5000 if (c)
goto allocate_number;
5002 if (ignore_notfound) {
5003 cf_log_warn(ci,
"Ignoring \"%s\" as the \"%s\" module is not enabled, "
5004 "or the method does not exist",
name, realname);
5027 char const *name1, *name2;
5032 .type_name =
"unlang_group_t",
5048 if (!name2) name2 =
"";
5050 cf_log_debug(cs,
"Compiling policies in - %s %s {...}", name1, name2);
5056 memset(&my_rules, 0,
sizeof(my_rules));
5065 .actions = *actions,
5079 if (instruction) *instruction = c;
5247 t->tracking.running_total =
fr_time_delta_add(t->tracking.running_total, frame->tracking.running_total);
5248 t->tracking.waiting_total =
fr_time_delta_add(t->tracking.waiting_total, frame->tracking.waiting_total);
5259 if (!instruction || !instruction->
number)
return;
5288 fr_log(log,
L_DBG,
file,
line,
"count=%" PRIu64
" cpu_time=%" PRId64
" yielded_time=%" PRId64 ,
5294 for (child = g->
children; child != NULL; child = child->
next) {
5295 unlang_perf_dump(log, child,
depth + 1);
5308void unlang_perf_virtual_server(
fr_log_t *log,
char const *
name)
5332 char const *name1, *name2;
5339 if (!instruction)
continue;
5353 unlang_perf_dump(log, instruction, 2);
static int const char char buffer[256]
#define L(_str)
Helper for initialising arrays of string literals.
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
static int invalid_type(fr_type_t type)
call_env_t * call_env_alloc(TALLOC_CTX *ctx, char const *name, call_env_method_t const *call_env_method, tmpl_rules_t const *t_rules, CONF_SECTION *cs, call_env_ctx_t const *cec)
Given a call_env_method, parse all call_env_pair_t in the context of a specific call to an xlat or mo...
size_t inst_size
Size of per call env.
CONF_SECTION * server_cs
Config section of the virtual server being executed.
fr_dict_attr_t const * attr_packet_type
Attribute used to specify packet type and sections run in the server_cs.
static unlang_call_t * unlang_group_to_call(unlang_group_t *g)
Cast a group structure to the call keyword extension.
Entry point into a proto_ module.
static unlang_caller_t * unlang_group_to_caller(unlang_group_t *g)
Cast a group structure to the caller keyword extension.
Declarations for the "catch" keyword.
static unlang_catch_t * unlang_group_to_catch(unlang_group_t *g)
Cast a group structure to the transaction keyword extension.
bool catching[RLM_MODULE_NUMCODES]
CONF_ITEM * cf_reference_item(CONF_SECTION const *parent_cs, CONF_SECTION const *outer_cs, char const *ptr)
Internal data that is associated with a configuration section.
Common header for all CONF_* types.
Configuration AVP similar to a fr_pair_t.
A section grouping multiple CONF_PAIR.
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
fr_token_t cf_pair_attr_quote(CONF_PAIR const *pair)
Return the value (lhs) quoting of a pair.
fr_token_t cf_section_argv_quote(CONF_SECTION const *cs, int argc)
Return the quoting for one of the variadic arguments.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
CONF_SECTION * cf_section_next(CONF_SECTION const *cs, CONF_SECTION const *curr)
Return the next child that's a CONF_SECTION.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
void cf_section_add_name2_quote(CONF_SECTION *cs, fr_token_t token)
Set the quoting of the name2 identifier.
bool cf_item_is_data(CONF_ITEM const *ci)
Determine if CONF_ITEM is CONF_DATA.
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
char const * cf_section_argv(CONF_SECTION const *cs, int argc)
Return variadic argument at the specified index.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
Return the quoting of the name2 identifier.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
#define cf_log_err(_cf, _fmt,...)
#define cf_item_insert_after(_parent, _prev, _child)
#define cf_data_add(_cf, _data, _name, _free)
#define cf_data_find(_cf, _type, _name)
#define cf_log_debug_prefix(_cf, _fmt,...)
#define cf_lineno_set(_ci, _lineno)
#define cf_data_remove(_cf, _type, _name)
Remove an item from a parent by type and name.
#define cf_section_free_children(_x)
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
#define cf_item_remove(_parent, _child)
#define cf_log_perr(_cf, _fmt,...)
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
#define CF_TO_ITEM(_cf)
Auto cast from the input type to CONF_ITEM (which is the base type)
#define cf_filename_set(_ci, _filename)
#define cf_log_warn(_cf, _fmt,...)
#define cf_log_debug(_cf, _fmt,...)
#define cf_item_next(_ci, _curr)
static int compile_action_pair(unlang_mod_actions_t *actions, CONF_PAIR *cp)
static unlang_t * compile_elsif(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static unlang_t * compile_item(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM *ci)
bool unlang_compile_is_keyword(const char *name)
Check if name is an unlang keyword.
void unlang_compile_init(TALLOC_CTX *ctx)
static unlang_t * compile_function(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM *ci, CONF_SECTION *subcs, bool policy)
static void unlang_dump(unlang_t *instruction, int depth)
static unlang_t * compile_module(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM *ci, char const *name)
#define RULES_VERIFY(_rules)
tmpl_rules_t const * rules
static unlang_t * compile_empty(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_SECTION *cs, unlang_ext_t const *ext)
bool unlang_compile_actions(unlang_mod_actions_t *actions, CONF_SECTION *action_cs, bool module_retry)
static unlang_t * compile_redundant_load_balance(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static unlang_t * compile_call(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static unlang_t * compile_section(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_SECTION *cs, unlang_ext_t const *ext)
static unlang_t * compile_update_to_edit(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_SECTION *cs)
static int compile_map_name(unlang_group_t *g)
static fr_table_ptr_sorted_t unlang_pair_keywords[]
static unlang_t * compile_load_balance_subsection(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_SECTION *cs, unlang_ext_t const *ext)
static unlang_t * compile_caller(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static unlang_t * compile_break(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
int unlang_thread_instantiate(TALLOC_CTX *ctx)
Create thread-specific data structures for unlang.
static unlang_t * compile_redundant(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static uint32_t case_hash(void const *data)
bool tmpl_require_enum_prefix
static char const unlang_spaces[]
static bool transaction_ok(CONF_SECTION *cs)
Limit the operations which can appear in a transaction.
static unlang_t * compile_else(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static int edit_pair_alloc(CONF_SECTION *cs, CONF_PAIR *original, char const *attr, fr_token_t op, char const *value, fr_token_t list_op)
static unlang_t * compile_children(unlang_group_t *g, unlang_compile_t *unlang_ctx_in, bool set_action_defaults)
static unlang_t * compile_case(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static int compile_variable(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_PAIR *cp, tmpl_rules_t *t_rules)
Compile a variable definition.
static unlang_t * compile_subrequest(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static int8_t instruction_cmp(void const *one, void const *two)
static bool validate_limited_subsection(CONF_SECTION *cs, char const *name)
int unlang_fixup_update(map_t *map, void *ctx)
Validate and fixup a map that's part of an update section.
static bool compile_retry_section(unlang_mod_actions_t *actions, CONF_ITEM *ci)
static int catch_argv(CONF_SECTION *cs, unlang_catch_t *ca, char const *name)
static unlang_t * compile_catch(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static unlang_t * compile_return(unlang_t *parent, unlang_compile_t *unlang_ctx, UNUSED CONF_ITEM const *ci)
static unlang_t * compile_limit(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
char const * section_name2
static const bool edit_list_sub_op[T_TOKEN_LAST]
size_t mod_rcode_table_len
static int define_local_variable(CONF_ITEM *ci, unlang_variable_t *var, tmpl_rules_t *t_rules, fr_type_t type, char const *name, fr_dict_attr_t const *ref)
static unlang_t * compile_update(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static unlang_t * compile_if(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static bool pass2_fixup_map_rhs(unlang_group_t *g, tmpl_rules_t const *rules)
static CONF_SECTION * virtual_module_find_cs(CONF_ITEM *ci, UNUSED char const *real_name, char const *virtual_name, char const *method_name, bool *policy)
Load a named module from the virtual module list, or from the "policy" subsection.
static void compile_action_defaults(unlang_t *c, unlang_compile_t *unlang_ctx)
static unlang_t * compile_group(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static void compile_copy_context(unlang_compile_t *dst, unlang_compile_t const *src)
static unlang_t * compile_parallel(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static const fr_sbuff_term_t if_terminals
static bool pass2_fixup_update(unlang_group_t *g, tmpl_rules_t const *rules)
static unlang_t * compile_if_subsection(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_SECTION *cs, unlang_ext_t const *ext)
static unsigned int unlang_number
static bool pass2_fixup_tmpl(UNUSED TALLOC_CTX *ctx, tmpl_t **vpt_p, CONF_ITEM const *ci, fr_dict_t const *dict)
static unlang_t * compile_foreach(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static int unlang_fixup_map(map_t *map, UNUSED void *ctx)
Validate and fixup a map that's part of an map section.
static int case_to_key(uint8_t **out, size_t *outlen, void const *data)
virtual_server_t const * vs
Virtual server we're compiling in the context of.
static unlang_t * compile_transaction(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static unlang_t * compile_timeout(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static unlang_t * compile_detach(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static int transaction_keywords_len
static fr_rb_tree_t * unlang_instruction_tree
static unlang_group_t * group_allocate(unlang_t *parent, CONF_SECTION *cs, unlang_ext_t const *ext)
static unlang_t * compile_switch(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static int unlang_section_keywords_len
unlang_t *(* unlang_op_compile_t)(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
int dict_attr_acopy_children(fr_dict_t *dict, fr_dict_attr_t *dst, fr_dict_attr_t const *src)
Copy the children of an existing attribute.
static unlang_t * compile_try(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static fr_table_num_sorted_t transaction_keywords[]
fr_table_num_sorted_t const mod_rcode_table[]
static unlang_t * compile_edit_section(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_SECTION *cs)
Compile one edit section.
static unlang_t * compile_load_balance(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static int edit_section_alloc(CONF_SECTION *parent, CONF_SECTION **child, char const *name1, fr_token_t op)
static int unlang_pair_keywords_len
static int unlang_attr_rules_verify(tmpl_attr_rules_t const *rules)
static fr_table_ptr_sorted_t unlang_section_keywords[]
static int8_t case_cmp(void const *one, void const *two)
void * unlang_thread_instance(unlang_t const *instruction)
Get the thread-instance data for an instruction.
static int unlang_fixup_edit(map_t *map, void *ctx)
Validate and fixup a map that's part of an edit section.
int unlang_compile(virtual_server_t const *vs, CONF_SECTION *cs, unlang_mod_actions_t const *actions, tmpl_rules_t const *rules, void **instruction)
Compile an unlang section for a virtual server.
static _Thread_local unlang_thread_t * unlang_thread_array
static unlang_t * compile_map(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
static bool pass2_fixup_map(map_t *map, tmpl_rules_t const *rules, fr_dict_attr_t const *parent)
Fixup ONE map (recursively)
char const * section_name1
unlang_mod_actions_t actions
static unlang_t * compile_tmpl(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM *ci)
static bool compile_action_subsection(unlang_t *c, CONF_SECTION *cs, CONF_SECTION *subcs)
static unlang_t * compile_edit_pair(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_PAIR *cp)
Compile one edit pair.
static int unlang_rules_verify(tmpl_rules_t const *rules)
static unlang_cond_t * unlang_group_to_cond(unlang_group_t *g)
Cast a group structure to the cond keyword extension.
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_fatal_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
static fr_dict_attr_t const * attr_packet_type
#define fr_dict_autoload_talloc(_ctx, _dict_out, _proto)
int fr_dict_attr_acopy_local(fr_dict_attr_t const *dst, fr_dict_attr_t const *src)
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
bool fr_dict_compatible(fr_dict_t const *dict1, fr_dict_t const *dict2)
See if two dictionaries have the same end parent.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
unsigned int internal
Internal attribute, should not be received in protocol packets, should not be encoded.
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
fr_dict_t const * fr_dict_internal(void)
fr_dict_t const * fr_dict_by_protocol_name(char const *name)
Lookup a protocol by its name.
int fr_dict_attr_add(fr_dict_t *dict, fr_dict_attr_t const *parent, char const *name, unsigned int attr, fr_type_t type, fr_dict_attr_flags_t const *flags))
Add an attribute to the dictionary.
fr_dict_t * fr_dict_protocol_alloc(fr_dict_t const *parent)
Allocate a new local dictionary.
Values of the encryption flags.
Value of an enumerated attribute.
Structure used to managed the lifetime of a dictionary.
map_list_t maps
Head of the map list.
static unlang_t * unlang_edit_to_generic(unlang_edit_t const *p)
static unlang_edit_t * unlang_generic_to_edit(unlang_t const *p)
Cast a generic structure to the edit extension.
static unlang_foreach_t * unlang_group_to_foreach(unlang_group_t *g)
Cast a group structure to the foreach keyword extension.
fr_dict_attr_t const * value
value variable in the foreach loop
fr_dict_attr_t const * key
key variable for the foreach loop
uint32_t(* fr_hash_t)(void const *)
fr_htrie_t * fr_htrie_alloc(TALLOC_CTX *ctx, fr_htrie_type_t type, fr_hash_t hash_data, fr_cmp_t cmp_data, fr_trie_key_t get_key, fr_free_t free_data)
An abstraction over our internal hashes, rb trees, and prefix tries.
static fr_htrie_type_t fr_htrie_hint(fr_type_t type)
static bool fr_htrie_insert(fr_htrie_t *ht, void const *data)
Insert data into a htrie.
static void * fr_htrie_find(fr_htrie_t *ht, void const *data)
Find data in a htrie.
#define DEBUG_ENABLED4
True if global debug level 1-3 messages are enabled.
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
int map_afrom_cs_edit(TALLOC_CTX *ctx, map_list_t *out, CONF_SECTION *cs, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules, map_validate_t validate, void *uctx, unsigned int max)
Convert a config section into an attribute map for editing.
int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *input_rhs_rules, bool edit)
Convert CONFIG_PAIR (which may contain refs) to map_t.
int map_afrom_cs(TALLOC_CTX *ctx, map_list_t *out, CONF_SECTION *cs, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules, map_validate_t validate, void *uctx, unsigned int max)
Convert a config section into an attribute map.
int map_list_afrom_cs(TALLOC_CTX *ctx, map_list_t *out, CONF_SECTION *cs, tmpl_rules_t const *t_rules, map_validate_t validate, void *uctx, unsigned int max)
Convert a config section into a list of { a, b, c, d, ... }.
ssize_t map_print(fr_sbuff_t *out, map_t const *map)
Print a map to a string.
unlang_op_t unlang_ops[UNLANG_TYPE_MAX]
Different operations the interpreter can execute.
static TALLOC_CTX * unlang_ctx
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
@ L_DBG
Only displayed when debugging is enabled.
static unlang_limit_t * unlang_group_to_limit(unlang_group_t *g)
Cast a group structure to the limit keyword extension.
static unlang_load_balance_t * unlang_group_to_load_balance(unlang_group_t *g)
Cast a group structure to the load_balance keyword extension.
bool main_config_migrate_option_get(char const *name)
map_proc_inst_t * proc_inst
static unlang_map_t * unlang_group_to_map(unlang_group_t *g)
Cast a group structure to the map keyword extension.
map_list_t map
Head of the map list.
map_proc_t * map_proc_find(char const *name)
Find a map processor by name.
map_proc_inst_t * map_proc_instantiate(TALLOC_CTX *ctx, map_proc_t const *proc, CONF_SECTION *cs, tmpl_t const *src, map_list_t const *maps)
Create a new map proc instance.
fr_value_box_safe_for_t map_proc_literals_safe_for(map_proc_t const *proc)
Map processor registration.
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_GROUP
A grouping of other attributes.
static uint8_t depth(fr_minmax_heap_index_t i)
int8_t(* fr_cmp_t)(void const *a, void const *b)
int strcasecmp(char *s1, char *s2)
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
Declarations for the unlang module interface.
static unlang_t * unlang_module_to_generic(unlang_module_t *p)
static unlang_module_t * unlang_generic_to_module(unlang_t const *p)
module_method_call_t mmc
Everything needed to call a module method.
unlang_t self
Common fields in all unlang_t tree nodes.
call_env_t const * call_env
The per call parsed call environment.
A call to a module method.
fr_slen_t module_rlm_by_name_and_method(TALLOC_CTX *ctx, module_method_call_t *mmc_out, virtual_server_t const *vs, section_name_t const *section, fr_sbuff_t *name, tmpl_rules_t const *t_rules)
Find an existing module instance and verify it implements the specified method.
CONF_SECTION * module_rlm_virtual_by_name(char const *asked_name)
module_instance_t * mi
The process modules also push module calls onto the stack for execution.
module_method_binding_t mmb
Method we're calling.
Declarations for the unlang "parallel" keyword.
static unlang_parallel_t * unlang_group_to_parallel(unlang_group_t *g)
Cast a group structure to the parallel keyword extension.
bool detach
are we creating the child detached
size_t fr_snprint(char *out, size_t outlen, char const *in, ssize_t inlen, char quote)
Escape any non printable or non-UTF8 characters in the input string.
size_t fr_snprint_len(char const *in, ssize_t inlen, char quote)
Find the length of the buffer required to fully escape a string with fr_prints.
static const char * packet_name[]
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
#define fr_rb_alloc(_ctx, _data_cmp, _data_free)
Allocs a red black tree.
Iterator structure for in-order traversal of an rbtree.
The main red black tree structure.
@ RLM_MODULE_INVALID
The module considers the request invalid.
@ RLM_MODULE_OK
The module is OK, continue.
@ RLM_MODULE_FAIL
Module failed, don't reply.
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
@ RLM_MODULE_REJECT
Immediately reject the request.
@ RLM_MODULE_NOTFOUND
User not found.
@ RLM_MODULE_UPDATED
OK (pairs modified).
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
fr_dict_attr_t const * request_attr_request
static const call_env_method_t method_env
#define FR_SBUFF_IN(_start, _len_or_end)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
#define FR_SBUFF_OUT(_start, _len_or_end)
Set of terminal elements.
char const * name
Instance name e.g. user_database.
@ MODULE_TYPE_RETRY
can handle retries
module_flags_t flags
Flags that control how a module starts up and how a module is called.
CONF_SECTION * conf
Module's instance configuration.
unlang_mod_actions_t actions
default actions and retries.
call_env_method_t const * method_env
Method specific call_env.
module_t * exported
Public module structure.
static int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
Return the last attribute reference's attribute number.
#define tmpl_contains_xlat(vpt)
#define TMPL_VERIFY(_vpt)
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
#define tmpl_is_xlat(vpt)
#define tmpl_is_attr_unresolved(vpt)
static bool tmpl_attr_tail_is_unspecified(tmpl_t const *vpt)
Return true if the last attribute reference is "unspecified".
int tmpl_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules))
Attempt to resolve functions and attributes in xlats and attribute references.
#define tmpl_value(_tmpl)
fr_table_num_sorted_t const tmpl_request_ref_table[]
Map keywords to tmpl_request_ref_t values.
tmpl_t * tmpl_alloc(TALLOC_CTX *ctx, tmpl_type_t type, fr_token_t quote, char const *name, ssize_t len)
Create a new heap allocated tmpl_t.
#define tmpl_contains_regex(vpt)
fr_value_box_safe_for_t literals_safe_for
safe_for value assigned to literal values in xlats, execs, and data.
#define tmpl_is_attr(vpt)
fr_dict_attr_t const * enumv
Enumeration attribute used to resolve enum values.
tmpl_rules_t const * parent
for parent / child relationships
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
#define tmpl_rules_cast(_tmpl)
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, char const *name, tmpl_rules_t const *rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
@ TMPL_TYPE_ATTR_UNRESOLVED
An attribute reference that we couldn't resolve but looked valid.
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
@ TMPL_TYPE_NULL
Has no value.
@ TMPL_TYPE_EXEC
Callout to an external script or program.
@ TMPL_TYPE_DATA
Value in native boxed format.
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
@ TMPL_TYPE_XLAT_UNRESOLVED
A xlat expansion with unresolved xlat functions or attribute references.
@ TMPL_TYPE_EXEC_UNRESOLVED
An exec with unresolved xlat function or attribute references.
static bool tmpl_attr_tail_da_is_leaf(tmpl_t const *vpt)
Return true if the the last attribute reference is a leaf attribute.
#define tmpl_contains_attr(vpt)
ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Convert an arbitrary string into a tmpl_t.
bool at_runtime
Produce an ephemeral/runtime tmpl.
static bool tmpl_is_list(tmpl_t const *vpt)
ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, fr_sbuff_t *name, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
int tmpl_cast_in_place(tmpl_t *vpt, fr_type_t type, fr_dict_attr_t const *enumv))
Convert tmpl_t of type TMPL_TYPE_DATA_UNRESOLVED or TMPL_TYPE_DATA to TMPL_TYPE_DATA of type specifie...
#define tmpl_is_data(vpt)
fr_dict_t const * dict_def
Alternative default dictionary to use if vpt->rules->dict_def is NULL.
#define TMPL_POOL_DEF_HEADERS
Define manipulation functions for the attribute reference list.
static size_t tmpl_attr_num_elements(tmpl_t const *vpt)
The number of attribute references contained within a tmpl.
#define tmpl_value_type(_tmpl)
void tmpl_attr_rewrite_leaf_num(tmpl_t *vpt, int16_t num)
Rewrite the leaf's instance number.
#define tmpl_is_data_unresolved(vpt)
fr_type_t cast
Whether there was an explicit cast.
#define TMPL_POOL_DEF_LEN
How many additional bytes to allocate in a pool for a tmpl_t.
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
#define tmpl_is_null(vpt)
struct tmpl_res_rules_s tmpl_res_rules_t
static char const * tmpl_list_name(fr_dict_attr_t const *list, char const *def)
Return the name of a tmpl list or def if list not provided.
@ REQUEST_UNKNOWN
Unknown request.
struct tmpl_rules_s tmpl_rules_t
#define tmpl_is_regex_xlat_unresolved(vpt)
void tmpl_set_dict_def(tmpl_t *vpt, fr_dict_t const *dict)
Change the default dictionary in the tmpl's resolution rules.
fr_slen_t tmpl_attr_list_from_substr(fr_dict_attr_t const **da_p, fr_sbuff_t *in)
Parse one a single list reference.
int tmpl_cast_set(tmpl_t *vpt, fr_type_t type)
Set a cast for a tmpl.
fr_type_t tmpl_expanded_type(tmpl_t const *vpt)
Return the native data type of the expression.
Similar to tmpl_rules_t, but used to specify parameters that may change during subsequent resolution ...
Optional arguments passed to vp_tmpl functions.
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
fr_aka_sim_id_type_t type
#define fr_time()
Allow us to arbitrarily manipulate time.
size_t strlcpy(char *dst, char const *src, size_t siz)
fr_token_t op
The operator that controls insertion of the dst attribute.
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
map_list_t child
parent map, for nested ones
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
CONF_ITEM * ci
Config item that the map was created from.
Define entry and head types for tmpl request references.
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
uint8_t allow_foreign
Allow arguments not found in dict_def.
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
uint8_t allow_wildcard
Allow the special case of .
uint8_t allow_unknown
Allow unknown attributes i.e.
static unlang_subrequest_t * unlang_group_to_subrequest(unlang_group_t *g)
Cast a group structure to the subrequest keyword extension.
tmpl_t * vpt
Value to expand to find the value to place into the packet-type attribute.
fr_dict_attr_t const * attr_packet_type
Packet-type attribute in the subrequest protocol.
tmpl_t * src
Pairs to copy into the subrequest request list.
fr_dict_t const * dict
Dictionary of the subrequest protocol.
tmpl_t * dst
Where to copy pairs from the reply list in the subrequest to.
fr_dict_enum_value_t const * type_enum
Static enumeration value for attr_packet_type.
static unlang_switch_t * unlang_group_to_switch(unlang_group_t *g)
Cast a group structure to the switch keyword extension.
static unlang_case_t * unlang_group_to_case(unlang_group_t *g)
Cast a group structure to the case keyword extension.
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
#define fr_table_value_by_substr(_table, _name, _name_len, _def)
Convert a partial string to a value using an ordered or sorted table.
An element in a lexicographically sorted array of name to num mappings.
An element in a lexicographically sorted array of name to ptr mappings.
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
fr_slen_t fr_time_delta_from_str(fr_time_delta_t *out, char const *in, size_t inlen, fr_time_res_t hint)
Create fr_time_delta_t from a string.
static fr_time_delta_t fr_time_delta_add(fr_time_delta_t a, fr_time_delta_t b)
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
#define fr_time_delta_ispos(_a)
A time delta, a difference in time measured in nanoseconds.
@ FR_TIME_TRACKING_YIELDED
We're currently tracking time in the yielded state.
static void fr_time_tracking_yield(fr_time_tracking_t *tt, fr_time_t now)
Transition to the yielded state, recording the time we just spent running.
static void fr_time_tracking_end(fr_time_delta_t *predicted, fr_time_tracking_t *tt, fr_time_t now)
End time tracking for this entity.
static void fr_time_tracking_start(fr_time_tracking_t *parent, fr_time_tracking_t *tt, fr_time_t now)
Start time tracking for a tracked entity.
static void fr_time_tracking_resume(fr_time_tracking_t *tt, fr_time_t now)
Track that a request resumed.
static unlang_timeout_t * unlang_group_to_timeout(unlang_group_t *g)
Cast a group structure to the timeout keyword extension.
const bool fr_assignment_op[T_TOKEN_LAST]
const bool fr_list_assignment_op[T_TOKEN_LAST]
fr_table_num_ordered_t const fr_tokens_table[]
char const * fr_tokens[T_TOKEN_LAST]
const bool fr_comparison_op[T_TOKEN_LAST]
const bool fr_binary_op[T_TOKEN_LAST]
Declarations for unlang transactions.
int(* fr_trie_key_t)(uint8_t **out, size_t *outlen, void const *data)
Declaration for unlang try.
tmpl_res_rules_t const * tr_rules
tmpl resolution rules.
static fr_slen_t e_rules bool xlat_is_truthy(xlat_exp_head_t const *head, bool *out)
Allow callers to see if an xlat is truthy.
int xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules)
Walk over an xlat tree recursively, resolving any unresolved functions or references.
fr_slen_t xlat_tokenize_condition(TALLOC_CTX *ctx, xlat_exp_head_t **head, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
#define unlang_frame_perf_resume(_x)
unlang_t * next
Next node (executed on UNLANG_ACTION_EXECUTE_NEXT et al).
char const * debug_name
Printed in log messages when the node is executed.
char const * type_name
Talloc type name.
void * state
Stack frame specialisations.
unlang_mod_actions_t actions
Priorities, etc. for the various return codes.
unlang_t * parent
Previous node.
char const * thread_inst_type
fr_dict_attr_t const * root
the root of our dictionary
#define unlang_frame_perf_init(_x)
bool closed
whether or not this section is closed to new statements
static unlang_t * unlang_group_to_generic(unlang_group_t const *p)
unlang_t ** tail
pointer to the tail which gets updated
static unlang_t * unlang_tmpl_to_generic(unlang_tmpl_t const *p)
CONF_ITEM * ci
used to generate this item
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
unsigned int number
unique node number
char const * name
Unknown...
@ UNLANG_TYPE_SWITCH
Switch section.
@ UNLANG_TYPE_TRANSACTION
transactions for editing lists
@ UNLANG_TYPE_SUBREQUEST
create a child subrequest
@ UNLANG_TYPE_UPDATE
Update block.
@ UNLANG_TYPE_ELSIF
!Condition && Condition.
@ UNLANG_TYPE_ELSE
!Condition.
@ UNLANG_TYPE_LOAD_BALANCE
Load balance section.
@ UNLANG_TYPE_DETACH
detach a child
@ UNLANG_TYPE_GROUP
Grouping section.
@ UNLANG_TYPE_POLICY
Policy section.
@ UNLANG_TYPE_TMPL
asynchronously expand a tmpl_t
@ UNLANG_TYPE_CASE
Case section (within a UNLANG_TYPE_SWITCH).
@ UNLANG_TYPE_LIMIT
limit number of requests in a section
@ UNLANG_TYPE_BREAK
Break statement (within a UNLANG_TYPE_FOREACH).
@ UNLANG_TYPE_TRY
try / catch blocks
@ UNLANG_TYPE_CALL
call another virtual server
@ UNLANG_TYPE_RETURN
Return statement.
@ UNLANG_TYPE_REDUNDANT
exactly like group, but with different default return codes
@ UNLANG_TYPE_IF
Condition.
@ UNLANG_TYPE_XLAT
Represents one level of an xlat expansion.
@ UNLANG_TYPE_NULL
unlang type not set.
@ UNLANG_TYPE_MAP
Mapping section (like UNLANG_TYPE_UPDATE, but uses values from a map_proc_t call).
@ UNLANG_TYPE_CALLER
conditionally check parent dictionary type
@ UNLANG_TYPE_TIMEOUT
time-based timeouts.
@ UNLANG_TYPE_MODULE
Module method.
@ UNLANG_TYPE_REDUNDANT_LOAD_BALANCE
Redundant load balance section.
@ UNLANG_TYPE_CATCH
catch a previous try
@ UNLANG_TYPE_FUNCTION
Internal call to a function or submodule.
@ UNLANG_TYPE_EDIT
edit VPs in place. After 20 years!
@ UNLANG_TYPE_FOREACH
Foreach section.
@ UNLANG_TYPE_PARALLEL
execute statements in parallel
unlang_t const * instruction
The unlang node we're evaluating.
bool debug_braces
Whether the operation needs to print braces in debug mode.
size_t len
Total length of the unlang_group_t + specialisation struct.
unlang_type_t type
Keyword.
unlang_variable_t * variables
rarely used, so we don't usually need it
unlang_t const * instruction
instruction which we're executing
char const * name
Name of the operation.
#define unlang_frame_perf_yield(_x)
size_t pool_len
How much additional space to allocate for extensions.
unsigned pool_headers
How much additional space to allocate for chunk headers.
#define unlang_frame_perf_cleanup(_x)
int max_attr
1..N local attributes have been defined
unlang_thread_instantiate_t thread_instantiate
per-thread instantiation function
fr_dict_t * dict
our dictionary
unlang_type_t type
The specialisation of this node.
unlang_t * children
Children beneath this group.
void * thread_inst
thread-specific instance data
Describes how to allocate an unlang_group_t with additional memory keyword specific data.
Generic representation of a grouping.
A node in a graph of unlang_op_t (s) that we execute.
Our interpreter stack, as distinct from the C stack.
fr_time_delta_t irt
Initial transmission time.
fr_time_delta_t mrt
Maximum retransmission time.
uint32_t mrc
Maximum retransmission count.
fr_time_delta_t mrd
Maximum retransmission duration.
char const * fr_strerror(void)
Get the last library error.
#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_is_structural(_x)
#define fr_type_is_numeric(_x)
#define FR_TYPE_INTEGER_EXCEPT_BOOL
#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.
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
int fr_value_box_to_key(uint8_t **out, size_t *outlen, fr_value_box_t const *value)
Get a key from a value box.
static size_t char ** out
fr_dict_t const * virtual_server_dict_by_name(char const *virtual_server)
Return the namespace for the named virtual server.
virtual_server_t const * virtual_server_find(char const *name)
Return virtual server matching the specified name.
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.
static bool is_truthy(xlat_exp_t *node, bool *out)