27 RCSID(
"$Id: c34ce3a43289c510402048a04e4453367cf5b014 $")
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>
37 #include <freeradius-devel/util/dlist.h>
38 #include <freeradius-devel/util/proto.h>
39 #include <freeradius-devel/util/value.h>
40 #include <freeradius-devel/util/edit.h>
41 #include <freeradius-devel/util/token.h>
42 #include <freeradius-devel/util/types.h>
76 if (!request)
return NULL;
79 if (!request->packet)
return NULL;
80 return &request->request_pairs;
84 if (!request->reply)
return NULL;
85 return &request->reply_pairs;
116 if (!request)
return NULL;
172 while ((rr = tmpl_request_list_next(rql, rr))) {
178 if (!request->parent)
return -1;
179 request = request->parent;
183 if (!request->parent)
return -1;
184 while (request->parent) request = request->parent;
306 RDEBUG4(
"EXPAND TMPL UNRESOLVED");
330 RDEBUG4(
"EXPAND TMPL XLAT PARSED");
340 if (slen < 0)
return slen;
364 if (ret < 0)
return -2;
367 src_type =
vp->vp_type;
423 "Have %zu bytes, need %zu bytes", bufflen,
424 to_cast->vb_length + 1);
427 memcpy(
buff, to_cast->vb_octets, to_cast->vb_length);
428 buff[to_cast->vb_length] =
'\0';
431 (
char *)
buff, to_cast->vb_length,
true);
454 if (src_type == dst_type) {
459 MEM(ctx = talloc_new(request));
461 from_cast = &value_from_cast;
467 if (ret < 0)
goto error;
483 if (from_cast->vb_length >= bufflen) {
485 "Have %zu bytes, need %zu bytes", bufflen,
486 from_cast->vb_length + 1);
489 memcpy(
buff, from_cast->vb_strvalue, from_cast->vb_length);
490 buff[from_cast->vb_length] =
'\0';
493 (
char *)
buff, from_cast->vb_length, from_cast->tainted);
501 if (from_cast->vb_length > bufflen) {
503 "Have %zu bytes, need %zu bytes", bufflen, from_cast->vb_length);
506 memcpy(
buff, from_cast->vb_octets, from_cast->vb_length);
508 buff, from_cast->vb_length, from_cast->tainted);
519 RDEBUG4(
"Copying %zu bytes to %p from offset %zu",
524 return from_cast->vb_length;
572 bool needs_dup =
false;
577 TALLOC_CTX *tmp_ctx = talloc_new(ctx);
583 RDEBUG4(
"EXPAND TMPL DATA UNRESOLVED");
617 slen =
xlat_aeval(tmp_ctx, &result, request,
vpt->name, escape, escape_ctx);
618 if (slen < 0)
goto error;
627 result, (
size_t)slen,
629 if (ret < 0)
goto error;
643 RDEBUG4(
"EXPAND TMPL XLAT STRUCT");
648 if (slen < 0)
goto error;
657 result, (
size_t)slen,
659 if (ret < 0)
goto error;
678 switch (to_cast->type) {
695 switch (to_cast->type) {
735 RPEDEBUG(
"Failed copying data to output box");
736 TALLOC_FREE(*vb_out);
746 if ((to_cast->type != dst_type) || needs_dup) {
748 if (ret < 0)
goto error;
750 switch (to_cast->type) {
757 if (
value.datum.ptr && (talloc_parent(
value.datum.ptr) == tmp_ctx)) {
758 (void)talloc_reparent(tmp_ctx, ctx,
value.datum.ptr);
768 RDEBUG4(
"Copying %zu bytes to %p from offset %zu",
779 return from_cast.vb_length;
855 switch (
vp->vp_type) {
942 if (!
head)
return -1;
975 TALLOC_CTX *pair_ctx = ctx;
977 tmpl_attr_list_head_t
const *ar_list = &
vpt->data.attribute.ar;
985 leaf = tmpl_attr_list_tail(ar_list);
986 ar = tmpl_attr_list_head(ar_list);
1012 ar = tmpl_attr_list_next(ar_list, ar);
1034 list = &
vp->vp_group;
1037 ar = tmpl_attr_list_next(ar_list, ar);
1054 fr_value_box_list_insert_tail(list, box);
1060 fr_value_box_list_insert_tail(list, box);
1084 fr_value_box_list_t list;
1088 fr_value_box_list_init(&list);
1116 value->datum.int32 = 0;
1117 fr_value_box_list_insert_tail(&list,
value);
1131 while (
vp != NULL) {
1137 if (!
value)
goto oom;
1139 fr_value_box_list_insert_tail(&list,
value);
1151 while (
vp != NULL) {
1154 if (!
value)
goto oom;
1163 if (!
value)
goto oom;
1167 fr_value_box_list_insert_tail(&list,
value);
1176 if (!
value)
goto oom;
1179 fr_value_box_list_insert_tail(&list,
value);
1189 fr_value_box_list_talloc_free(&list);
1194 fr_value_box_list_move(
out, &list);
1220 fr_value_box_list_t list;
1267 fr_value_box_list_init(&list);
1268 fr_value_box_list_insert_tail(&list,
value);
1271 fr_value_box_list_talloc_free(&list);
1275 fr_value_box_list_move(
out, &list);
1290 switch (escape->
uctx.type) {
1298 fr_assert_msg(escape->
uctx.size > 0,
"TMPL_ESCAPE_UCTX_ALLOC must specify uctx.size > 0");
1300 if (escape->
uctx.talloc_type) talloc_set_type(uctx, escape->
uctx.talloc_type);
1305 fr_assert_msg(escape->
uctx.
func.alloc,
"TMPL_ESCAPE_UCTX_ALLOC_FUNC must specify a non-null alloc.func");
1321 switch (escape->
uctx.type) {
1347 bool did_concat =
false;
1360 switch (
vpt->quote) {
1369 vb = fr_value_box_list_head(list);
1378 vpt->rules.escape.safe_for, uctx) < 0)) {
1387 if (slen < 0)
goto error;
1431 vpt->rules.escape.safe_for, uctx) < 0))
goto error;
1444 if (!
vpt->rules.escape.func &&
vpt->rules.escape.safe_for) {
1458 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...
void fr_dict_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
#define fr_dict_autofree(_to_free)
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
#define fr_dict_autoload(_to_load)
#define fr_dict_attr_is_key_field(_da)
fr_dict_attr_t * fr_dict_unknown_attr_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num))
Initialise a fr_dict_attr_t from a number.
Specifies a dictionary which must be loaded/loadable for the module to function.
#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,...)
typedef FR_DLIST_HEAD(map_list) map_list_t
Given these are used in so many places, it's more friendly to have a proper type.
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.
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_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.
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)
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.
#define tmpl_contains_regex(vpt)
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
#define tmpl_is_attr(vpt)
bool tmpl_async_required(tmpl_t const *vpt)
Return whether or not async is required for this tmpl.
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)
@ 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).
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
#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]
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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.
struct tmpl_escape_t::@72 uctx
#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....
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.
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.
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 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.
void tmpl_global_free(void)
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.
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.
static void * tmpl_eval_escape_uctx_alloc(request_t *request, tmpl_escape_t const *escape)
Allocate a uctx for an escaping function.
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.
VALUE_BOX_LIST_VERIFY(list)
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.
fr_dict_autoload_t tmpl_dict[]
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)
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
#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)
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 fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
static size_t char ** out