27RCSID(
"$Id: 0234f583648b9044aa8c75662b8cf77e91e7203b $")
29#define _TMPL_PRIVATE 1
31#include <freeradius-devel/server/exec.h>
32#include <freeradius-devel/server/exec_legacy.h>
33#include <freeradius-devel/server/tmpl.h>
34#include <freeradius-devel/server/tmpl_dcursor.h>
35#include <freeradius-devel/server/client.h>
36#include <freeradius-devel/unlang/call.h>
38#include <freeradius-devel/util/atexit.h>
39#include <freeradius-devel/util/dlist.h>
40#include <freeradius-devel/util/proto.h>
41#include <freeradius-devel/util/value.h>
42#include <freeradius-devel/util/edit.h>
43#include <freeradius-devel/util/token.h>
44#include <freeradius-devel/util/types.h>
78 if (!request)
return NULL;
81 if (!request->packet)
return NULL;
82 return &request->request_pairs;
86 if (!request->reply)
return NULL;
87 return &request->reply_pairs;
118 if (!request)
return NULL;
174 while ((rr = tmpl_request_list_next(rql, rr))) {
180 if (!request->parent)
return -1;
181 request = request->parent;
185 if (!request->parent)
return -1;
186 while (request->parent) request = request->parent;
308 RDEBUG4(
"EXPAND TMPL UNRESOLVED");
332 RDEBUG4(
"EXPAND TMPL XLAT PARSED");
342 if (slen < 0)
return slen;
366 if (ret < 0)
return -2;
369 src_type =
vp->vp_type;
425 "Have %zu bytes, need %zu bytes", bufflen,
426 to_cast->vb_length + 1);
429 memcpy(
buff, to_cast->vb_octets, to_cast->vb_length);
430 buff[to_cast->vb_length] =
'\0';
433 (
char *)
buff, to_cast->vb_length,
true);
456 if (src_type == dst_type) {
461 MEM(ctx = talloc_new(request));
463 from_cast = &value_from_cast;
469 if (ret < 0)
goto error;
485 if (from_cast->vb_length >= bufflen) {
487 "Have %zu bytes, need %zu bytes", bufflen,
488 from_cast->vb_length + 1);
491 memcpy(
buff, from_cast->vb_strvalue, from_cast->vb_length);
492 buff[from_cast->vb_length] =
'\0';
495 (
char *)
buff, from_cast->vb_length, from_cast->tainted);
503 if (from_cast->vb_length > bufflen) {
505 "Have %zu bytes, need %zu bytes", bufflen, from_cast->vb_length);
508 memcpy(
buff, from_cast->vb_octets, from_cast->vb_length);
510 buff, from_cast->vb_length, from_cast->tainted);
521 RDEBUG4(
"Copying %zu bytes to %p from offset %zu",
526 return from_cast->vb_length;
574 bool needs_dup =
false;
579 TALLOC_CTX *tmp_ctx = talloc_new(ctx);
585 RDEBUG4(
"EXPAND TMPL DATA UNRESOLVED");
619 slen =
xlat_aeval(tmp_ctx, &result, request,
vpt->name, escape, escape_ctx);
620 if (slen < 0)
goto error;
629 result, (
size_t)slen,
631 if (ret < 0)
goto error;
645 RDEBUG4(
"EXPAND TMPL XLAT STRUCT");
650 if (slen < 0)
goto error;
659 result, (
size_t)slen,
661 if (ret < 0)
goto error;
680 switch (to_cast->type) {
697 switch (to_cast->type) {
737 RPEDEBUG(
"Failed copying data to output box");
738 TALLOC_FREE(*vb_out);
748 if ((to_cast->type != dst_type) || needs_dup) {
750 if (ret < 0)
goto error;
752 switch (to_cast->type) {
759 if (
value.datum.ptr && (talloc_parent(
value.datum.ptr) == tmp_ctx)) {
760 (void)talloc_reparent(tmp_ctx, ctx,
value.datum.ptr);
770 RDEBUG4(
"Copying %zu bytes to %p from offset %zu",
781 return from_cast.vb_length;
857 switch (
vp->vp_type) {
944 if (!
head)
return -1;
977 TALLOC_CTX *pair_ctx = ctx;
979 tmpl_attr_list_head_t
const *ar_list = &
vpt->data.attribute.ar;
987 leaf = tmpl_attr_list_tail(ar_list);
988 ar = tmpl_attr_list_head(ar_list);
1014 ar = tmpl_attr_list_next(ar_list, ar);
1036 list = &
vp->vp_group;
1039 ar = tmpl_attr_list_next(ar_list, ar);
1056 fr_value_box_list_insert_tail(list, box);
1062 fr_value_box_list_insert_tail(list, box);
1086 fr_value_box_list_t list;
1090 fr_value_box_list_init(&list);
1118 value->datum.int32 = 0;
1119 fr_value_box_list_insert_tail(&list,
value);
1133 while (
vp != NULL) {
1139 if (!
value)
goto oom;
1141 fr_value_box_list_insert_tail(&list,
value);
1153 while (
vp != NULL) {
1156 if (!
value)
goto oom;
1165 if (!
value)
goto oom;
1169 fr_value_box_list_insert_tail(&list,
value);
1181 if (!
value)
goto oom;
1184 fr_value_box_list_insert_tail(&list,
value);
1194 fr_value_box_list_talloc_free(&list);
1199 fr_value_box_list_move(
out, &list);
1225 fr_value_box_list_t list;
1272 fr_value_box_list_init(&list);
1273 fr_value_box_list_insert_tail(&list,
value);
1276 fr_value_box_list_talloc_free(&list);
1280 fr_value_box_list_move(
out, &list);
1295 switch (escape->
uctx.type) {
1303 fr_assert_msg(escape->
uctx.size > 0,
"TMPL_ESCAPE_UCTX_ALLOC must specify uctx.size > 0");
1305 if (escape->
uctx.talloc_type) talloc_set_type(uctx, escape->
uctx.talloc_type);
1310 fr_assert_msg(escape->
uctx.
func.alloc,
"TMPL_ESCAPE_UCTX_ALLOC_FUNC must specify a non-null alloc.func");
1326 switch (escape->
uctx.type) {
1352 bool did_concat =
false;
1365 switch (
vpt->quote) {
1374 vb = fr_value_box_list_head(list);
1383 vpt->rules.escape.safe_for, uctx) < 0)) {
1392 if (slen < 0)
goto error;
1436 vpt->rules.escape.safe_for, uctx) < 0))
goto error;
1449 if (!
vpt->rules.escape.func &&
vpt->rules.escape.safe_for) {
1472 PERROR(
"%s", __FUNCTION__);
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
#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_dict_autofree(_to_free)
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
#define fr_dict_autoload(_to_load)
#define fr_dict_attr_is_key_field(_da)
Specifies a dictionary which must be loaded/loadable for the module to function.
#define FR_DLIST_HEAD(_name)
Expands to the type name used for the head wrapper structure.
#define EXEC_TIMEOUT
Default wait time for exec calls (in seconds).
int radius_exec_program_legacy(char *out, size_t outlen, request_t *request, char const *cmd, fr_pair_list_t *input_pairs, bool exec_wait, bool shell_escape, fr_time_delta_t timeout)
Execute a program.
#define RWDEBUG2(fmt,...)
#define RPEDEBUG(fmt,...)
size_t(* xlat_escape_legacy_t)(request_t *request, char *out, size_t outlen, char const *in, void *arg)
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_VALUE_BOX
A boxed value.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
int fr_pair_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and append)
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
int fr_pair_list_copy_to_box(fr_value_box_t *dst, fr_pair_list_t *from)
Copy the contents of a pair list to a set of value-boxes.
fr_dict_attr_t const * request_attr_request
fr_dict_attr_t const * request_attr_control
fr_dict_attr_t const * request_attr_local
fr_dict_attr_t const * request_attr_state
fr_dict_attr_t const * request_attr_reply
#define FR_SBUFF_IN(_start, _len_or_end)
static int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
Return the last attribute reference's attribute number.
#define TMPL_VERIFY(_vpt)
#define tmpl_is_xlat(vpt)
#define tmpl_rules_enumv(_tmpl)
#define tmpl_value(_tmpl)
#define tmpl_contains_regex(vpt)
#define tmpl_is_attr(vpt)
bool tmpl_async_required(tmpl_t const *vpt)
Return whether or not async is required for this tmpl.
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
static bool tmpl_attr_is_list_attr(tmpl_attr_t const *ar)
Return true if the tmpl_attr is one of the list types.
#define tmpl_rules_cast(_tmpl)
@ TMPL_TYPE_REGEX_UNCOMPILED
Regex where compilation is possible but hasn't been performed yet.
@ TMPL_TYPE_MAX
Marker for the last tmpl type.
@ 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_REGEX_XLAT_UNRESOLVED
A regular expression with unresolved xlat functions or attribute references.
@ TMPL_TYPE_DATA
Value in native boxed format.
@ TMPL_TYPE_REGEX
Compiled (and possibly JIT'd) regular expression.
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
@ TMPL_TYPE_XLAT_UNRESOLVED
A xlat expansion with unresolved xlat functions or attribute references.
@ TMPL_TYPE_REGEX_XLAT
A regex containing xlat expansions.
@ TMPL_TYPE_EXEC_UNRESOLVED
An exec with unresolved xlat function or attribute references.
@ TMPL_TYPE_UNINITIALISED
Uninitialised.
#define tmpl_pair_list_and_ctx(_ctx, _head, _request, _ref, _list)
Determine the correct context and list head.
#define tmpl_is_data(vpt)
#define tmpl_value_type(_tmpl)
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
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_OUTER
request_t containing the outer layer of the EAP conversation.
@ REQUEST_PARENT
Parent (whatever it is).
@ REQUEST_UNKNOWN
Unknown request.
@ REQUEST_CURRENT
The current request (default).
#define tmpl_aexpand(_ctx, _out, _request, _vpt, _escape, _escape_ctx)
Expand a tmpl to a C type, allocing a new buffer to hold the string.
#define tmpl_needs_resolving(vpt)
static char buff[sizeof("18446744073709551615")+3]
An element in a list of nested attribute references.
fr_dict_attr_t const *_CONST da
Resolved dictionary attribute.
Define manipulation functions for the attribute reference list.
tmpl_request_ref_t _CONST request
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Functions which we wish were included in the standard talloc distribution.
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
void tmpl_dcursor_clear(tmpl_dcursor_ctx_t *cc)
Clear any temporary state allocations.
#define tmpl_dcursor_init(_err, _ctx, _cc, _cursor, _request, _vpt)
Maintains state between cursor calls.
fr_value_box_escape_t func
How to escape when returned from evaluation.
#define tmpl_escape_post_concat(_tmpl)
See if we should perform output escaping after concatenation.
#define tmpl_escape_pre_concat(_tmpl)
See if we should perform output escaping before concatenation.
@ TMPL_ESCAPE_UCTX_ALLOC
A new uctx of the specified size and type is allocated and freed when escaping is complete.
@ TMPL_ESCAPE_UCTX_STATIC
A static (to us) is provided by whatever is initialising the tmpl_escape_t.
@ TMPL_ESCAPE_UCTX_ALLOC_FUNC
A new uctx of the specified size and type is allocated and pre-populated by memcpying uctx....
struct tmpl_escape_t::@74 uctx
Escaping rules for tmpls.
int tmpl_find_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt)
Returns the first VP matching a tmpl_t.
fr_packet_t * tmpl_packet_ptr(request_t *request, fr_dict_attr_t const *list)
Resolve a list to the fr_packet_t holding the HEAD pointer for a fr_pair_t list.
int tmpl_value_list_insert_tail(fr_value_box_list_t *list, fr_value_box_t *box, tmpl_t const *vpt)
Insert a value-box to a list, with casting.
fr_dict_attr_t const * tmpl_attr_unspec
Placeholder attribute for uses of unspecified attribute references.
static int _tmpl_global_free(UNUSED void *uctx)
static fr_dict_t const * dict_freeradius
static fr_dict_t const * dict_radius
int tmpl_request_ptr(request_t **context, FR_DLIST_HEAD(tmpl_request_list) const *rql)
Resolve a tmpl_request_ref_t to a request_t.
int tmpl_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
Gets the value of a tmpl.
int tmpl_eval_cast_in_place(fr_value_box_list_t *list, request_t *request, tmpl_t const *vpt)
Casts a value or list of values according to the tmpl.
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.
ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out, request_t *request, tmpl_t const *vpt, xlat_escape_legacy_t escape, void const *escape_ctx, fr_type_t dst_type)
Expand a template to a string, allocing a new buffer to hold the string.
int tmpl_global_init(void)
int tmpl_eval_pair(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
Gets the value of a real or virtual attribute.
ssize_t _tmpl_to_type(void *out, uint8_t *buff, size_t bufflen, request_t *request, tmpl_t const *vpt, xlat_escape_legacy_t escape, void const *escape_ctx, fr_type_t dst_type)
Expand a tmpl_t to a string writing the result to a buffer.
int tmpl_copy_pair_children(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
Copy children of pairs matching a tmpl_t in the current request_t.
int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
Copy pairs matching a tmpl_t in the current request_t.
static void tmpl_eval_escape_uctx_free(tmpl_escape_t const *escape, void *uctx)
Free a uctx for an escaping function.
int tmpl_find_or_add_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt)
Returns the first VP matching a tmpl_t, or if no VPs match, creates a new one.
static int _tmpl_global_init(UNUSED void *uctx)
fr_dict_autoload_t tmpl_dict[]
static void * tmpl_eval_escape_uctx_alloc(request_t *request, tmpl_escape_t const *escape)
Allocate a uctx for an escaping function.
fr_type_t tmpl_expanded_type(tmpl_t const *vpt)
Return the native data type of the expression.
int pair_append_by_tmpl_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, tmpl_t const *vpt, bool skip_list)
Allocate and insert a leaf vp from a tmpl_t, building the parent vps if needed.
@ T_SOLIDUS_QUOTED_STRING
ssize_t xlat_eval_compiled(char *out, size_t outlen, request_t *request, xlat_exp_head_t const *head, xlat_escape_legacy_t escape, void const *escape_ctx))
ssize_t xlat_aeval_compiled(TALLOC_CTX *ctx, char **out, request_t *request, xlat_exp_head_t const *head, xlat_escape_legacy_t escape, void const *escape_ctx))
ssize_t xlat_aeval(TALLOC_CTX *ctx, char **out, request_t *request, char const *fmt, xlat_escape_legacy_t escape, void const *escape_ctx))
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
#define fr_type_is_structural(_x)
#define fr_type_is_string(_x)
#define FR_TYPE_STRUCTURAL
#define fr_type_is_null(_x)
#define fr_type_is_leaf(_x)
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
size_t const fr_value_box_field_sizes[]
How many bytes wide each of the value data fields are.
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules, bool tainted)
int fr_value_box_strtrim(TALLOC_CTX *ctx, fr_value_box_t *vb)
Trim the length of the string buffer to match the length of the C string.
int fr_value_box_list_escape_in_place(fr_value_box_list_t *list, fr_value_box_escape_t escape, fr_value_box_safe_for_t safe_for, void *uctx)
Escape a list of value boxes in place.
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.
size_t const fr_value_box_offsets[]
Where the value starts in the fr_value_box_t.
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
int fr_value_box_cast_in_place(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
Convert one type of fr_value_box_t to another in place.
void fr_value_box_memdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Assign a buffer to a box, but don't copy it.
void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
Perform a shallow copy of a value_box.
size_t fr_value_str_unescape(fr_sbuff_t *out, fr_sbuff_t *in, size_t inlen, char quote)
Convert a string value with escape sequences into its binary form.
void fr_value_box_list_mark_safe_for(fr_value_box_list_t *list, fr_value_box_safe_for_t safe_for)
Set the escaped flag for all value boxes in a list.
void fr_value_box_strdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a buffer containing a nul terminated string to a box, but don't copy it.
int fr_value_box_bstr_alloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv, size_t len, bool tainted)
Alloc and assign an empty \0 terminated string to a fr_value_box_t.
int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
Copy value data verbatim moving any buffers to the specified context.
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
int fr_value_box_list_concat_in_place(TALLOC_CTX *ctx, fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type, fr_value_box_list_action_t proc_action, bool flatten, size_t max_size)
Concatenate a list of value boxes.
@ FR_VALUE_BOX_LIST_FREE_BOX
Free each processed box.
#define fr_value_box_list_foreach_safe(_list_head, _iter)
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
static int fr_value_box_memcpy_out(void *out, fr_value_box_t const *vb)
Copy the value of a value box to a field in a C struct.
#define FR_VALUE_BOX_INITIALISER_NULL(_vb)
A static initialiser for stack/globally allocated boxes.
#define VALUE_BOX_VERIFY(_x)
#define VALUE_BOX_LIST_VERIFY(_x)
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
static size_t char ** out