27RCSID(
"$Id: 9cf6caf5d7624d4f27e3888024d5b83ff036d110 $")
31#include <freeradius-devel/util/debug.h>
32#include <freeradius-devel/server/rcode.h>
34#define LOG_PREFIX "rlm_ldap groups"
120 if (!
inst->group.obj_name_attr) {
121 REDEBUG(
"Told to convert group names to DNs but missing 'group.name_attribute' directive");
125 REDEBUG(
"Missing group base_dn");
129 RDEBUG2(
"Converting group name(s) to group DN(s)");
135 MEM(fr_sbuff_init_talloc(group_ctx, &sbuff, &sbuff_ctx, 256, SIZE_MAX));
167 unsigned int entry_cnt;
173 switch (query->
ret) {
179 RDEBUG2(
"Tried to resolve group name(s) to DNs but got no results");
188 if (entry_cnt > group_ctx->
name_cnt) {
189 REDEBUG(
"Number of DNs exceeds number of names, group and/or dn should be more restrictive");
195 if (entry_cnt < group_ctx->name_cnt) {
196 RWDEBUG(
"Got partial mapping of group names (%i) to DNs (%i), membership information may be incomplete",
202 ldap_get_option(query->
ldap_conn->
handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
203 REDEBUG(
"Failed retrieving entry: %s", ldap_err2string(ldap_errno));
212 ldap_get_option(query->
ldap_conn->
handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
213 REDEBUG(
"Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
220 RDEBUG2(
"Got group DN \"%s\"", dn);
253 if (!
inst->group.obj_name_attr) {
254 REDEBUG(
"Told to resolve group DN to name but missing 'group.name_attribute' directive");
258 RDEBUG2(
"Resolving group DN \"%s\" to group name", *group_ctx->
dn);
261 LDAP_SCOPE_BASE, NULL, group_ctx->
attrs, NULL, NULL);
285 switch (query->
ret) {
291 REDEBUG(
"Group DN \"%s\" did not resolve to an object", *group_ctx->
dn);
302 ldap_get_option(query->
ldap_conn->
handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
303 REDEBUG(
"Failed retrieving entry: %s", ldap_err2string(ldap_errno));
309 REDEBUG(
"No %s attributes found in object",
inst->group.obj_name_attr);
317 RDEBUG2(
"Group DN \"%s\" resolves to name \"%pV\"", *group_ctx->
dn, &
vp->data);
347 RDEBUG2(
"Adding cacheable user object memberships");
381 switch (p_result->
rcode) {
395 if (*group_ctx->
dn) {
443 LDAPMessage *entry = autz_ctx->
entry;
447 struct berval *
value;
451 int is_dn, iter_err = 0, name2dn = 0, dn2name = 0;
452 size_t count = 0, strings_len = 0;
454 inst->group.profile_attr_suspend,
465 RPERROR(
"Failed parsing user object");
469 RDEBUG2(
"No cacheable group memberships found in user object");
491 group_ctx->
ttrunk = ttrunk;
519 if (want_profiles && is_dn) {
523 if (
inst->group.cacheable_dn) {
537 REDEBUG(
"Too many groups require name to DN resolution");
547 if (
inst->group.cacheable_name) {
561 REDEBUG(
"Too many groups require DN to name resolution");
570 RPERROR(
"Failed parsing user object");
581 group_ctx->
attrs[0] =
inst->group.obj_name_attr;
618 group_ctx->
attrs[0] =
inst->group.obj_name_attr;
620 group_ctx->
base_dn->vb_strvalue,
inst->group.obj_scope,
621 filter->vb_strvalue, group_ctx->
attrs, NULL, NULL);
658 inst->group.profile_attr_suspend,
661 switch (query->
ret) {
667 RDEBUG2(
"No cacheable group memberships found in group objects");
678 ldap_get_option(query->
ldap_conn->
handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
679 REDEBUG(
"Failed retrieving entry: %s", ldap_err2string(ldap_errno));
694 RDEBUG2(
"Adding cacheable group object memberships");
696 if (
inst->group.cacheable_dn || want_profiles) {
699 ldap_get_option(query->
ldap_conn->
handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
700 REDEBUG(
"Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
710 if (
inst->group.cacheable_dn) {
721 if (
inst->group.cacheable_name) {
725 inst->group.obj_name_attr) <= 0)
continue;
754 if (!
inst->group.obj_membership_filter) {
755 RDEBUG2(
"Skipping caching group objects as directive 'group.membership_filter' is not set");
760 REDEBUG(
"Missing group base_dn");
768 group_ctx->
uctx = autz_ctx;
795 char const *attrs[2];
813 switch (query->
ret) {
819 RDEBUG2(
"No profiles found in group objects");
831 RPERROR(
"Failed parsing profiles from group objects");
858 inst->group.profile_attr_suspend,
868 RWDEBUG(
"Skipping group profiles, no naming context contains every group DN");
872 dn_attr =
inst->dn_attr;
878 group_ctx->
attrs[0] = profile_attr;
897 base, LDAP_SCOPE_SUB, group_ctx->
filter, group_ctx->
attrs, NULL, NULL);
914 switch (query->
ret) {
918 LDAPMessage *entry = NULL;
970 char const *filters[] = { name_filter,
inst->group.obj_filter,
inst->group.obj_membership_filter };
973 if (!
inst->group.obj_name_attr) {
974 REDEBUG(
"Told to search for group by name, but missing 'group.name_attribute' "
993 .always_escape =
false,
1000 snprintf(name_filter,
sizeof(name_filter),
"(%s=%s)",
1001 inst->group.obj_name_attr,
xlat_ctx->group->vb_strvalue);
1036 if (!
inst->group.obj_name_attr) {
1037 REDEBUG(
"Told to resolve group DN to name but missing 'group.name_attribute' directive");
1072 LDAP_SCOPE_BASE, NULL,
xlat_ctx->attrs, NULL, NULL);
1088 bool value_is_dn =
false;
1090 char *value_name = NULL;
1096 if (!group_ctx->
values) {
1099 ldap_get_option(query->
ldap_conn->
handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
1100 REDEBUG(
"Failed retrieving entry: %s", ldap_err2string(ldap_errno));
1105 if (!group_ctx->
values) {
1106 RDEBUG2(
"User object contains no group membership information in attribute \"%s\"",
1107 inst->group.userobj_membership_attr);
1115 group_ctx->
count = ldap_count_values_len(group_ctx->
values);
1122 if (group_ctx->
query) {
1124 struct berval name_value;
1132 REDEBUG(
"Group DN \"%pV\" did not resolve to an object",
1143 REDEBUG(
"Failed retrieving entry: %s", ldap_err2string(ldap_errno));
1148 inst->group.obj_name_attr) <= 0) {
1149 REDEBUG(
"No %s attributes found in object",
inst->group.obj_name_attr);
1176 (memcmp(group->vb_strvalue, value_name, group->vb_length) == 0)) {
1177 RDEBUG2(
"User found in group \"%pV\". Comparison between membership: name "
1178 "(resolved from DN \"%pV\"), check: name", group,
1184 TALLOC_FREE(value_name);
1192 RDEBUG2(
"Processing %s value \"%pV\" as a %s",
inst->group.userobj_membership_attr,
1194 value_is_dn ?
"DN" :
"group name");
1199 if (!
xlat_ctx->group_is_dn && !value_is_dn) {
1200 if ((group->vb_length ==
value->bv_len) &&
1201 (memcmp(
value->bv_val, group->vb_strvalue,
value->bv_len) == 0)) {
1202 RDEBUG2(
"User found in group \"%pV\". Comparison between membership: name, check: name",
1213 if (
xlat_ctx->group_is_dn && value_is_dn) {
1215 RDEBUG2(
"User found in group DN \"%pV\". "
1216 "Comparison between membership: dn, check: dn", group);
1227 if (!value_is_dn &&
xlat_ctx->group_is_dn) {
1233 group_ctx->
lookup_dn = group->vb_strvalue;
1249 RDEBUG2(
"User found in group \"%pV\". Comparison between membership: "
1250 "name, check: name (resolved from DN \"%pV\")",
1262 if (value_is_dn && !
xlat_ctx->group_is_dn) {
1291 if (group_ctx->
values) ldap_value_free_len(group_ctx->
values);
1312 .
attrs = {
inst->group.obj_name_attr, NULL }
1315 RDEBUG2(
"Checking user object's %s attributes",
inst->group.userobj_membership_attr);
1363 RDEBUG2(
"User found. Matched cached membership");
1370 RDEBUG2(
"Cached membership not found");
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
#define USES_APPLE_DEPRECATED_API
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
#define unlang_function_push_with_result(_result_p, _request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack that produces a result.
#define unlang_function_repeat_set(_request, _repeat)
Set a new repeat function for an existing function frame.
fr_ldap_query_t * query
Current query performing group lookup.
static unlang_action_t ldap_check_userobj_start(UNUSED unlang_result_t *p_result, request_t *request, void *uctx)
Initiate a user lookup to check membership.
unlang_action_t rlm_ldap_cacheable_groupobj(unlang_result_t *p_result, request_t *request, ldap_autz_ctx_t *autz_ctx)
Convert group membership information into attributes.
static char const * null_attrs[]
char const * attrs[2]
For retrieving the group name.
static unlang_action_t ldap_cacheable_groupobj_start(unlang_result_t *p_result, request_t *request, void *uctx)
Initiate an LDAP search for group membership looking at the group objects.
static unlang_action_t ldap_group_name2dn_start(unlang_result_t *p_result, request_t *request, void *uctx)
Convert multiple group names into a DNs.
char const * attrs[2]
For retrieving the profile attribute.
ldap_group_xlat_ctx_t * xlat_ctx
Xlat context being evaluated.
int count
How many entries there are in values.
unlang_action_t rlm_ldap_check_groupobj_dynamic(unlang_result_t *p_result, request_t *request, ldap_group_xlat_ctx_t *xlat_ctx)
Initiate an LDAP search to determine group membership, querying group objects.
void * uctx
Optional context for use in results parsing.
static int userobj_dyn_free(ldap_group_userobj_dyn_ctx_t *group_ctx)
Ensure retrieved LDAP values are cleared up.
char * group_name[LDAP_MAX_CACHEABLE+1]
List of group names which need resolving.
char * group_dn[LDAP_MAX_CACHEABLE+1]
List of group DNs which need resolving.
struct berval ** values
Values of the membership attribute to check.
static unlang_action_t ldap_check_userobj_resume(unlang_result_t *p_result, request_t *request, void *uctx)
Process the results of evaluating a user object when checking group membership.
unlang_action_t rlm_ldap_cacheable_userobj(unlang_result_t *p_result, request_t *request, ldap_autz_ctx_t *autz_ctx, char const *attr)
Convert group membership information into attributes.
static unlang_action_t ldap_cacheable_userobj_resolve(unlang_result_t *p_result, request_t *request, void *uctx)
Initiate DN to name and name to DN group lookups.
tmpl_t * filter_tmpl
Tmpl to expand into LDAP filter.
char const * attrs[2]
For retrieving the group name.
rlm_ldap_t const * inst
Module instance.
unlang_action_t rlm_ldap_check_userobj_dynamic(unlang_result_t *p_result, request_t *request, ldap_group_xlat_ctx_t *xlat_ctx)
Query the LDAP directory to check if a user object is a member of a group.
fr_value_box_list_t expanded_filter
Values produced by expanding filter xlat.
fr_value_box_t * base_dn
The base DN to search for groups in.
fr_ldap_thread_trunk_t * ttrunk
Trunk on which to perform additional queries.
fr_pair_list_t groups
Temporary list to hold pairs.
static unlang_action_t ldap_cacheable_groupobj_resume(unlang_result_t *p_result, request_t *request, void *uctx)
Process the results of a group object lookup.
fr_ldap_thread_trunk_t * ttrunk
Trunk on which to perform additional queries.
char ** dn
Current DN being resolved.
static unlang_action_t ldap_cacheable_userobj_store(unlang_result_t *p_result, request_t *request, ldap_group_userobj_ctx_t *group_ctx)
Move user object group attributes to the control list.
static unlang_action_t ldap_group_name2dn_resume(unlang_result_t *p_result, request_t *request, void *uctx)
Process the results of looking up group DNs from names.
char const * attrs[2]
For resolving name from DN.
char const * filter
Filter matching profile bearing group objects.
static unlang_action_t ldap_group_dn2name_resume(unlang_result_t *p_result, request_t *request, void *uctx)
Process the results of a group DN -> name lookup.
TALLOC_CTX * list_ctx
In which to allocate pairs.
bool resolving_value
Is the current query resolving a DN from values.
unsigned int name_cnt
How many names need resolving.
static unlang_action_t ldap_dn2name_start(unlang_result_t *p_result, request_t *request, void *uctx)
Initiate resolving a group DN to its name.
static void ldap_group_userobj_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
Cancel a pending group lookup query.
static unlang_action_t ldap_group_profile_resume(unlang_result_t *p_result, request_t *request, void *uctx)
Harvest profile DNs from the group objects returned by the profile search.
static void ldap_group_groupobj_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
Cancel a pending group object lookup.
static unlang_action_t ldap_check_groupobj_resume(unlang_result_t *p_result, request_t *request, void *uctx)
Process the results of a group object lookup.
fr_value_box_t * base_dn
The base DN to search for groups in.
static void ldap_dn2name_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
Cancel an in-progress DN to name lookup.
unlang_action_t rlm_ldap_group_profiles(unlang_result_t *p_result, request_t *request, ldap_autz_ctx_t *autz_ctx)
Search for profile DNs in the group objects the user is a member of.
unlang_action_t rlm_ldap_check_cached(unlang_result_t *p_result, rlm_ldap_t const *inst, request_t *request, fr_value_box_t const *check)
Check group membership attributes to see if a user is a member.
static unlang_action_t ldap_group_dn2name_start(unlang_result_t *p_result, request_t *request, void *uctx)
Initiate an LDAP search to turn a group DN into it's name.
fr_ldap_query_t * query
Current query performing group resolution.
ldap_autz_ctx_t * autz_ctx
Authorization context profile DNs are harvested into.
char const * profile_attr
Attribute holding profile DNs.
char const * lookup_dn
The DN currently being looked up, when resolving DN to name.
fr_ldap_query_t * query
Current query retrieving the group objects.
int value_no
The current entry in values being processed.
rlm_ldap_t const * inst
Module instance.
char * group_name
Result of resolving the provided group DN as to a name.
fr_ldap_query_t * query
Current query doing a DN to name resolution.
Context to use when looking up group membership using group objects.
Context used when searching for profiles in the user's group objects.
Context to use when resolving group membership from the user object.
Context to use when evaluating group membership from the user object in an xlat.
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
struct berval * fr_ldap_value_iter_init(int *err, fr_ldap_value_iter_t *iter, LDAP *handle, LDAPMessage *entry, char const *attr)
Start an in place iteration over an attribute's values in an entry.
size_t fr_ldap_util_normalise_dn(char *out, char const *in)
Normalise escape sequences in a DN.
char const * fr_ldap_directory_common_base_find(fr_ldap_directory_t const *directory, char const *const *dn_list)
Find the naming context which contains a set of DNs.
int fr_ldap_filter_to_tmpl(TALLOC_CTX *ctx, tmpl_rules_t const *t_rules, char const **sub, size_t sublen, tmpl_t **out))
Combine filters and tokenize to a tmpl.
#define LDAP_MAX_FILTER_STR_LEN
Maximum length of an xlat expanded filter.
int fr_ldap_entry_value_find(struct berval *out, LDAP *handle, LDAPMessage *entry, char const *attr)
Find an attribute in an entry, returning its first value referenced in place.
int fr_ldap_filter_box_escape(fr_value_box_t *vb, UNUSED void *uctx)
Escape a value box for use as an RFC 4515 filter assertion value.
void fr_ldap_value_iter_done(fr_ldap_value_iter_t *iter)
Release value iteration state.
bool fr_ldap_util_is_dn(char const *in, size_t inlen)
Check whether a string looks like a DN.
struct berval * fr_ldap_value_iter_next(int *err, fr_ldap_value_iter_t *iter)
Return the next value of the iterated attribute.
LDAP * handle
libldap handle.
fr_ldap_result_code_t ret
Result code.
#define LDAP_MAX_CACHEABLE
Maximum number of groups we retrieve from the server for a given user which need resolving from name ...
trunk_request_t * treq
Trunk request this query is associated with.
#define LDAP_FILTER_SAFE_FOR
Marks a value box as already escaped for use as a filter assertion value.
int fr_ldap_result_values_len(size_t *num, size_t *strings_len, LDAP *handle, LDAPMessage *result, char const *attr)
Sum the lengths of an attribute's values across every entry of a result.
fr_slen_t fr_ldap_filter_escape(fr_sbuff_t *out, fr_sbuff_t *in)
Escape a value for use as an RFC 4515 filter assertion value.
char * fr_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced string.
talloc_str_list_t * fr_ldap_str_list_afrom_result(TALLOC_CTX *ctx, LDAP *handle, LDAPMessage *result, char const *attr, size_t extra)
Copy an attribute's values from every entry of a result into a string list.
fr_ldap_connection_t * ldap_conn
LDAP connection this query is running on.
@ LDAP_RESULT_SUCCESS
Successfully got LDAP results.
@ LDAP_RESULT_NO_RESULT
No results returned.
@ LDAP_RESULT_BAD_DN
The requested DN does not exist.
static int fr_ldap_berval_strncasecmp(struct berval *value, char const *str, size_t strlen)
Compare a berval with a C string of a known length using case insensitive comparison.
LDAPMessage * result
Head of LDAP results list.
fr_ldap_directory_t * directory
The type of directory we're connected to.
char const * dn_attr
Attribute to match an entry's DN in a search filter.
char * fr_ldap_filter_afrom_dn_list(TALLOC_CTX *ctx, char const *dn_attr, char const *filter, char const *const *dn_list)
Build a filter matching a set of objects by DN.
Thread LDAP trunk structure.
State of an in place iteration over an attribute's values.
LDAP * fr_ldap_handle_thread_local(void)
Get a thread local dummy LDAP handle.
unlang_action_t fr_ldap_trunk_search(TALLOC_CTX *ctx, fr_ldap_query_t **out, request_t *request, fr_ldap_thread_trunk_t *ttrunk, char const *base_dn, int scope, char const *filter, char const *const *attrs, LDAPControl **serverctrls, LDAPControl **clientctrls)
Run an async search LDAP query on a trunk connection.
#define REXDENT()
Exdent (unindent) R* messages by one level.
#define RINDENT()
Indent R* messages by one level.
@ FR_TYPE_STRING
String of printable characters.
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
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_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
#define RDEBUG_ENABLED2()
#define RETURN_UNLANG_INVALID
#define RETURN_UNLANG_RCODE(_rcode)
#define RETURN_UNLANG_NOTFOUND
#define RETURN_UNLANG_FAIL
#define RETURN_UNLANG_REJECT
rlm_rcode_t
Return codes indicating the result of the module call.
@ 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_NOTFOUND
User not found.
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
fr_dict_attr_t const * request_attr_request
fr_dict_attr_t const * request_attr_control
LDAP authorization and authentication module headers.
static char const * rlm_ldap_profile_attr_select(char const *attr, char const *attr_suspend, ldap_access_state_t access_state)
Return the profile attribute matching the user's access state.
ldap_autz_call_env_t * call_env
fr_ldap_thread_trunk_t * ttrunk
tmpl_t * group_filter
tmpl to expand as group membership filter.
fr_value_box_t group_base
Base DN in which to search for groups.
ldap_access_state_t access_state
What state a user's account is in.
talloc_str_list_t * group_profile_dn_list
Profile DNs found in the user's group objects.
struct rlm_ldap_t::@196 group
talloc_str_list_t * group_dn_list
DNs of the group objects the user is a member of.
Holds state of in progress async authorization.
Holds state of in progress group membership check xlat.
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
#define fr_sbuff_buff(_sbuff_or_marker)
#define FR_SBUFF_IN_STR(_start)
#define fr_sbuff_in_strcpy_literal(_sbuff, _str)
#define fr_sbuff_in_char(_sbuff,...)
Talloc sbuff extension structure.
#define pair_append_control(_attr, _da)
Allocate and append a fr_pair_t to the control list.
fr_pair_list_t * tmpl_list_head(request_t *request, fr_dict_attr_t const *list)
Resolve attribute fr_pair_list_t value to an attribute list.
TALLOC_CTX * tmpl_list_ctx(request_t *request, fr_dict_attr_t const *list)
Return the correct TALLOC_CTX to alloc fr_pair_t in, for a list.
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
struct tmpl_rules_s tmpl_rules_t
Optional arguments passed to vp_tmpl functions.
fr_signal_t
Signals that can be generated/processed by request signal handlers.
@ FR_SIGNAL_CANCEL
Request has been cancelled.
static char buff[sizeof("18446744073709551615")+3]
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
eap_aka_sim_process_conf_t * inst
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Stores an attribute, a value and various bits of other data.
int talloc_str_list_realloc(talloc_str_list_t *list, size_t extra)
Extend a string list to hold additional strings.
talloc_str_list_t * talloc_str_list_alloc(TALLOC_CTX *ctx, size_t num, size_t strings_len)
Allocate a list to hold num strings of strings_len total length.
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
char const * talloc_str_list_append(talloc_str_list_t *list, char const *str, size_t len)
Append a copy of a string to a string list.
static int talloc_const_free(void const *ptr)
Free const'd memory.
char const ** strings
NULL terminated array of strings.
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
void check(const char *name, int index, const struct info *all, int want_lineno, const char *want_function, const char *want_file, int *failed)
const char * base(const char *p)
int unlang_tmpl_push(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out, request_t *request, tmpl_t const *tmpl, unlang_tmpl_args_t *args, bool top_frame)
Push a tmpl onto the stack for evaluation.
@ TMPL_ESCAPE_PRE_CONCAT
Pre-concatenation escaping is useful for DSLs where elements of the expansion are static,...
void trunk_request_signal_cancel(trunk_request_t *treq)
Cancel a trunk request.
#define fr_pair_dcursor_by_da_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes matching the specified fr_dict_attr_t.
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.
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.
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
int fr_value_box_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b)
Compare two attributes using an operator.
#define fr_box_strvalue_buffer(_val)
#define fr_box_strvalue_len(_val, _len)
#define fr_box_strvalue(_val)
static TALLOC_CTX * xlat_ctx