The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
xlat_eval.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: ed6de1aace7fea49029213a3ac6327de9236c8cb $
19 *
20 * @file xlat_eval.c
21 * @brief String expansion ("translation"). Evaluation of pre-parsed xlat expansions.
22 *
23 * @copyright 2018-2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 * @copyright 2000,2006 The FreeRADIUS server project
25 * @copyright 2000 Alan DeKok (aland@freeradius.org)
26 */
27RCSID("$Id: ed6de1aace7fea49029213a3ac6327de9236c8cb $")
28
29#include <freeradius-devel/server/base.h>
30#include <freeradius-devel/server/tmpl_dcursor.h>
31#include <freeradius-devel/unlang/xlat_priv.h>
32
33static int instance_count = 0;
34
36
38 { .out = &dict_freeradius, .proto = "freeradius" },
39 { NULL }
40};
41
42fr_dict_attr_t const *attr_expr_bool_enum; /* xlat_expr.c */
43fr_dict_attr_t const *attr_cast_base; /* xlat_expr.c */
44
56
58 { .out = &attr_expr_bool_enum, .name = "Expr-Bool-Enum", .type = FR_TYPE_BOOL, .dict = &dict_freeradius },
59 { .out = &attr_cast_base, .name = "Cast-Base", .type = FR_TYPE_UINT8, .dict = &dict_freeradius },
60
61 { .out = &attr_cast_time_res_sec, .name = "Cast-Time-Res-Sec", .type = FR_TYPE_TIME_DELTA, .dict = &dict_freeradius },
62 { .out = &attr_cast_time_res_min, .name = "Cast-Time-Res-Min", .type = FR_TYPE_TIME_DELTA, .dict = &dict_freeradius },
63 { .out = &attr_cast_time_res_hour, .name = "Cast-Time-Res-Hour", .type = FR_TYPE_TIME_DELTA, .dict = &dict_freeradius },
64 { .out = &attr_cast_time_res_day, .name = "Cast-Time-Res-Day", .type = FR_TYPE_TIME_DELTA, .dict = &dict_freeradius },
65 { .out = &attr_cast_time_res_week, .name = "Cast-Time-Res-Week", .type = FR_TYPE_TIME_DELTA, .dict = &dict_freeradius },
66 { .out = &attr_cast_time_res_month, .name = "Cast-Time-Res-Month", .type = FR_TYPE_TIME_DELTA, .dict = &dict_freeradius },
67 { .out = &attr_cast_time_res_year, .name = "Cast-Time-Res-Year", .type = FR_TYPE_TIME_DELTA, .dict = &dict_freeradius },
68 { .out = &attr_cast_time_res_csec, .name = "Cast-Time-Res-Centi-Sec", .type = FR_TYPE_TIME_DELTA, .dict = &dict_freeradius },
69 { .out = &attr_cast_time_res_msec, .name = "Cast-Time-Res-Milli-Sec", .type = FR_TYPE_TIME_DELTA, .dict = &dict_freeradius },
70 { .out = &attr_cast_time_res_usec, .name = "Cast-Time-Res-Micro-Sec", .type = FR_TYPE_TIME_DELTA, .dict = &dict_freeradius },
71 { .out = &attr_cast_time_res_nsec, .name = "Cast-Time-Res-Nano-Sec", .type = FR_TYPE_TIME_DELTA, .dict = &dict_freeradius },
72
73 { NULL }
74};
75
77 { L("done"), XLAT_ACTION_DONE },
78 { L("fail"), XLAT_ACTION_FAIL },
79 { L("push-child"), XLAT_ACTION_PUSH_CHILD },
80 { L("yield"), XLAT_ACTION_YIELD }
81};
83
84/*
85 * This should be updated if fr_time_precision_table[] adds more time resolutions.
86 */
88 { L("microseconds"), &attr_cast_time_res_usec },
89 { L("us"), &attr_cast_time_res_usec },
90
91 { L("nanoseconds"), &attr_cast_time_res_nsec },
92 { L("ns"), &attr_cast_time_res_nsec },
93
94 { L("milliseconds"), &attr_cast_time_res_msec },
95 { L("ms"), &attr_cast_time_res_msec },
96
97 { L("centiseconds"), &attr_cast_time_res_csec },
98 { L("cs"), &attr_cast_time_res_csec },
99
100 { L("seconds"), &attr_cast_time_res_sec },
101 { L("s"), &attr_cast_time_res_sec },
102
103 { L("minutes"), &attr_cast_time_res_min },
104 { L("m"), &attr_cast_time_res_min },
105
106 { L("hours"), &attr_cast_time_res_hour },
107 { L("h"), &attr_cast_time_res_hour },
108
109 { L("days"), &attr_cast_time_res_day },
110 { L("d"), &attr_cast_time_res_day },
111
112 { L("weeks"), &attr_cast_time_res_week },
113 { L("w"), &attr_cast_time_res_week },
114
115 /*
116 * These use special values FR_TIME_DUR_MONTH and FR_TIME_DUR_YEAR
117 */
118 { L("months"), &attr_cast_time_res_month },
119 { L("M"), &attr_cast_time_res_month },
120
121 { L("years"), &attr_cast_time_res_year },
122 { L("y"), &attr_cast_time_res_year },
123
124};
126
127fr_dict_attr_t const *xlat_time_res_attr(char const *res)
128{
129 fr_dict_attr_t const **da_p;
130
132 if (!da_p) return NULL;
133
134 return *da_p;
135}
136
137static ssize_t xlat_eval_sync(TALLOC_CTX *ctx, char **out, request_t *request, xlat_exp_head_t const * const head,
138 xlat_escape_legacy_t escape, void const *escape_ctx);
139
140/** Reconstruct the original expansion string from an xlat tree
141 *
142 * @param[in] out sbuff to print result in.
143 * @param[in] node in the tree to start printing.
144 * @return
145 * - The original expansion string on success.
146 * - NULL on error.
147 */
149{
150 switch (node->type) {
151 case XLAT_BOX:
152 case XLAT_GROUP:
153 fr_assert(node->fmt != NULL);
154 return fr_sbuff_in_sprintf(out, "%pV", fr_box_strvalue_buffer(node->fmt));
155
156 case XLAT_ONE_LETTER:
157 fr_assert(node->fmt != NULL);
158 return fr_sbuff_in_sprintf(out, "%%%s", node->fmt);
159
160 case XLAT_TMPL:
161 fr_assert(node->fmt != NULL);
162 if (tmpl_is_attr(node->vpt) && (node->fmt[0] == '&')) {
163 return fr_sbuff_in_strcpy(out, node->fmt);
164 } else {
165 return fr_sbuff_in_sprintf(out, "%%{%pV}", fr_box_strvalue_buffer(node->fmt));
166 }
167
168#ifdef HAVE_REGEX
169 case XLAT_REGEX:
170 return fr_sbuff_in_sprintf(out, "%%{%u}", node->regex_index);
171#endif
172
173 case XLAT_FUNC:
174 {
175 bool first_done = false;
176 fr_sbuff_t our_out;
177 fr_slen_t slen;
178
179 /*
180 * No arguments, just print an empty function.
181 */
182 if (!xlat_exp_head(node->call.args)) return fr_sbuff_in_sprintf(out, "%%%s()", node->call.func->name);
183
184 our_out = FR_SBUFF(out);
185 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%%%s(", node->call.func->name);
186
187 if (node->call.args) {
188 xlat_exp_foreach(node->call.args, arg) {
189 if (first_done && (node->call.func->args)) {
190 FR_SBUFF_IN_CHAR_RETURN(&our_out, ',');
191 }
192
193 slen = xlat_fmt_print(&our_out, arg);
194 if (slen < 0) return slen - fr_sbuff_used(&our_out);
195
196 first_done = true;
197 }
198 }
199
200 FR_SBUFF_IN_CHAR_RETURN(&our_out, ')');
201 return fr_sbuff_set(out, &our_out);
202 }
203
204 default:
205 return 0;
206 }
207}
208
209/** Output what we're currently expanding
210 *
211 * @param[in] request The current request.
212 * @param[in] node Being processed.
213 * @param[in] args from previous expansion.
214 * @param[in] line Unused
215 */
216static inline void xlat_debug_log_expansion(request_t *request, xlat_exp_t const *node, fr_value_box_list_t const *args, UNUSED int line)
217{
218 if (node->flags.constant) return;
219
220 if (!RDEBUG_ENABLED2) return;
221
222 /*
223 * Because it's difficult to keep track of what
224 * the function was actually called with,
225 * we print the concatenated arguments list as
226 * well as the original fmt string.
227 */
228 if ((node->type == XLAT_FUNC) && !xlat_is_literal(node->call.args)) {
229 RDEBUG2("| %%%s(%pM)", node->call.func->name, args);
230 } else {
231 fr_sbuff_t *agg;
232
233 FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 1024, SIZE_MAX);
234
235 if (xlat_fmt_print(agg, node) < 0) {
236 RERROR("Failed printing expansion");
237 return;
238 }
239 RDEBUG2("| %s", fr_sbuff_start(agg)); /* print line number here for debugging */
240 }
241}
242
243/** Output the list result of an expansion
244 *
245 * @param[in] request The current request.
246 * @param[in] node which was expanded.
247 * @param[in] result of the expansion.
248 */
249static inline void xlat_debug_log_list_result(request_t *request, xlat_exp_t const *node, fr_value_box_list_t const *result)
250{
251 if (node->flags.constant) return;
252
253 if (!RDEBUG_ENABLED2) return;
254
255 RDEBUG2("| --> %pM", result);
256}
257
258/** Output the result of an expansion
259 *
260 * @param[in] request The current request.
261 * @param[in] node which was expanded.
262 * @param[in] result of the expansion.
263 */
264static inline void xlat_debug_log_result(request_t *request, xlat_exp_t const *node, fr_value_box_t const *result)
265{
266 if (node->flags.constant) return;
267
268 if (!RDEBUG_ENABLED2) return;
269
270 RDEBUG2("| --> %pV", result);
271}
272
273static int xlat_arg_stringify(request_t *request, xlat_arg_parser_t const *arg, xlat_exp_t const *node, fr_value_box_t *vb)
274{
275 int rcode;
276
277 if (vb->type == FR_TYPE_GROUP) {
278 fr_value_box_list_foreach(&vb->vb_group, child) {
279 if (xlat_arg_stringify(request, arg, NULL, child) < 0) return -1;
280 }
281
282 if (!node || (node->quote == T_BARE_WORD)) return 0;
283
284 fr_assert(node->type == XLAT_GROUP);
285
286 /*
287 * Empty lists are empty strings.
288 */
289 if (!fr_value_box_list_head(&vb->vb_group)) {
290 fr_value_box_entry_t entry;
291
292 entry = vb->entry;
293 fr_value_box_init(vb, FR_TYPE_STRING, NULL, false);
294 fr_value_box_strdup(vb, vb, NULL, "", false);
295 vb->entry = entry;
296
298 return 0;
299 }
300
301 /*
302 * Mash all of the child value-box to a string.
303 */
304 if (fr_value_box_list_concat_in_place(vb, vb, &vb->vb_group, FR_TYPE_STRING, FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0) {
305 return -1;
306 }
307
308 /*
309 * Do NOT mark this as safe for anything. The inputs could have come from anywhere.
310 *
311 * The arg->safe_for value is set ONLY after the data has been escaped.
312 */
313 return 0;
314 }
315
316 if (fr_value_box_is_safe_for(vb, arg->safe_for) && !arg->always_escape) return 0;
317
318 rcode = arg->func(request, vb, arg->uctx);
319 if (rcode != 0) return rcode;
320
322 return 0;
323}
324
325/** Process an individual xlat argument value box group
326 *
327 * @param[in] ctx to allocate any additional buffers in
328 * @param[in,out] list of value boxes representing one argument
329 * @param[in] request currently being processed
330 * @param[in] name of the function being called
331 * @param[in] arg specification of current argument
332 * @param[in] node expansion for the current argument
333 * @param[in] arg_num number of current argument in the argument specifications
334 * @return
335 * - XLAT_ACTION_DONE on success.
336 * - XLAT_ACTION_FAIL on failure.
337 */
338static xlat_action_t xlat_process_arg_list(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request,
339 char const *name, xlat_arg_parser_t const *arg, xlat_exp_t const *node, unsigned int arg_num)
340{
341 fr_value_box_t *vb;
342 bool concat = false;
343 bool quoted = false;
345
346 /*
347 * The function does it's own escaping and concatenation.
348 */
349 if (arg->will_escape) {
351 return XLAT_ACTION_DONE;
352 }
353
354 /*
355 * See if we have to concatenate multiple value-boxes into one output string / whatever.
356 *
357 * If the input xlat is more complicated expression, it's going to be a function, e.g.
358 *
359 * 1+2 --> %op_add(1,2).
360 *
361 * And then we can't do escaping. Note that this is also the case for
362 *
363 * "foo" + User-Name --> %op_add("foo", User-Name)
364 *
365 * Arguably, we DO want to escape User-Name, but not Foo. Because "+" here is a special case. :(
366 */
367 if ((fr_dlist_num_elements(&node->group->dlist) == 1) && (xlat_exp_head(node->group)->quote != T_BARE_WORD)) {
368 quoted = concat = true;
370
371 } else {
372 concat = arg->concat;
373 type = arg->type;
374 }
375
376 /*
377 * No data - nothing to do.
378 */
379 if (fr_value_box_list_empty(list)) {
380 /*
381 * The expansion resulted in no data, BUT the admin wants a string. So we create an
382 * empty string.
383 *
384 * i.e. If attribute 'foo' doesn't exist, then we have:
385 *
386 * %{foo} --> nothing, because 'foo' doesn't exist
387 * "%{foo}" --> "", because we want a string, therefore the contents of the string are nothing.
388 *
389 * Also note that an empty string satisfies a required argument.
390 */
391 if (quoted) {
392 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL));
393 fr_value_box_strdup(vb, vb, NULL, "", false);
394 fr_value_box_list_insert_tail(list, vb);
395
396 return XLAT_ACTION_DONE;
397 }
398
399 if (arg->required) {
400 REDEBUG("Function \"%s\" is missing required argument %u", name, arg_num);
401 return XLAT_ACTION_FAIL;
402 }
403
404 return XLAT_ACTION_DONE;
405 }
406
407 /*
408 * The function may be URI or SQL, which have different sub-types. So we call the function if it
409 * is NOT marked as "globally safe for SQL", but the called function may check the more specific
410 * flag "safe for MySQL". And then things which aren't safe for MySQL are escaped, and then
411 * marked as "safe for MySQL".
412 *
413 * If the escape function returns "0", then we set the safe_for value. If the escape function
414 * returns "1", then it has set the safe_for value.
415 */
416 if (arg->func) {
417 for (vb = fr_value_box_list_head(list);
418 vb != NULL;
419 vb = fr_value_box_list_next(list, vb)) {
420 if (xlat_arg_stringify(request, arg, node, vb) < 0) {
421 RPEDEBUG("Function \"%s\" failed escaping argument %u", name, arg_num);
422 return XLAT_ACTION_FAIL;
423 }
424 }
425 }
426
427 vb = fr_value_box_list_head(list);
428 fr_assert(node->type == XLAT_GROUP);
429
430 /*
431 * Concatenate child boxes, then cast to the desired type.
432 */
433 if (concat) {
434 if (fr_value_box_list_concat_in_place(ctx, vb, list, type, FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0) {
435 RPEDEBUG("Function \"%s\" failed concatenating arguments to type %s", name, fr_type_to_str(type));
436 return XLAT_ACTION_FAIL;
437 }
438 fr_assert(fr_value_box_list_num_elements(list) == 1);
439
440 goto check_types;
441 }
442
443 /*
444 * Only a single child box is valid here. Check there is
445 * just one, cast to the correct type
446 */
447 if (arg->single) {
448 if (fr_value_box_list_num_elements(list) > 1) {
449 RPEDEBUG("Function \"%s\" was provided an incorrect number of values at argument %u, "
450 "expected %s got %u",
451 name, arg_num,
452 arg->required ? "0-1" : "1",
453 fr_value_box_list_num_elements(list));
454 return XLAT_ACTION_FAIL;
455 }
456
457 check_types:
458 if (!fr_type_is_leaf(arg->type)) goto check_non_leaf;
459
460 /*
461 * Cast to the correct type if necessary.
462 */
463 if (vb->type != arg->type) {
464 if (fr_value_box_cast_in_place(ctx, vb, arg->type, NULL) < 0) {
465 cast_error:
466 RPEDEBUG("Function \"%s\" failed to cast argument %u to type %s", name, arg_num, fr_type_to_str(arg->type));
467 return XLAT_ACTION_FAIL;
468 }
469 }
470
471 return XLAT_ACTION_DONE;
472 }
473
474 /*
475 * We're neither concatenating nor do we only expect a single value,
476 * cast all child values to the required type.
477 */
478 if (fr_type_is_leaf(arg->type)) {
479 do {
480 if (vb->type == arg->type) continue;
481 if (fr_value_box_cast_in_place(ctx, vb,
482 arg->type, NULL) < 0) goto cast_error;
483 } while ((vb = fr_value_box_list_next(list, vb)));
484
485 return XLAT_ACTION_DONE;
486 }
487
488check_non_leaf:
489 if (arg->type == FR_TYPE_VOID) return XLAT_ACTION_DONE;
490
491 /*
492 * We already have a pair cursor, the argument was an attribute reference.
493 */
494 if (vb->type == FR_TYPE_PAIR_CURSOR) return XLAT_ACTION_DONE;
495
496 /*
497 * If the argument is a pair
498 */
499 fr_assert(vb->type != FR_TYPE_PAIR_CURSOR);
500
501 {
502 int err;
503 tmpl_t *vpt;
504
505 /*
506 * Cursor names have to be strings, which are completely safe.
507 */
508 if (vb->type != FR_TYPE_STRING) {
509 REDEBUG("Expected attribute reference as string, not %s", fr_type_to_str(vb->type));
510 return XLAT_ACTION_FAIL;
511 }
512
515 REDEBUG("Refusing to reference attribute from unsafe data");
516 return XLAT_ACTION_FAIL;
517 }
518
519 if (tmpl_afrom_attr_str(ctx, NULL, &vpt, vb->vb_strvalue,
520 &(tmpl_rules_t){
521 .attr = {
522 .dict_def = request->proto_dict, /* we can't encode local attributes */
523 .list_def = request_attr_request,
524 .allow_wildcard = arg->allow_wildcard,
525 }
526 }) <= 0) {
527 RPEDEBUG("Failed parsing attribute reference");
528 return XLAT_ACTION_FAIL;
529 }
530
532
533 /*
534 * The cursor can return something, nothing (-1), or no list (-2) or no context (-3). Of
535 * these, only the last two are actually errors.
536 *
537 * "no matching pair" returns _no_ cursor, and not an empty cursor.
538 */
539 (void) tmpl_dcursor_value_box_init(&err, vb, vb, request, vpt);
540 if (err < 0) return XLAT_ACTION_FAIL;
541 }
542
543#undef ESCAPE
544
545 return XLAT_ACTION_DONE;
546}
547
548
549/** Process list of boxed values provided as input to an xlat
550 *
551 * Ensures that the value boxes passed to an xlat function match the
552 * requirements listed in its "args", and escapes any tainted boxes
553 * using the specified escaping routine.
554 *
555 * @param[in] ctx in which to allocate any buffers.
556 * @param[in,out] list value boxes provided as input.
557 * List will be modified in accordance to rules
558 * provided in the args array.
559 * @param[in] request being processed.
560 * @param[in] node which is a function
561 */
562static inline CC_HINT(always_inline)
563xlat_action_t xlat_process_args(TALLOC_CTX *ctx, fr_value_box_list_t *list,
564 request_t *request, xlat_exp_t const *node)
565{
566 xlat_t const *func = node->call.func;
567 xlat_arg_parser_t const *arg_p = func->args;
568 xlat_exp_t *arg, *arg_next;
569 xlat_action_t xa;
570 fr_value_box_t *vb, *vb_next;
571
572 /*
573 * No args registered for this xlat
574 */
575 if (!func->args) return XLAT_ACTION_DONE;
576
577 /*
578 * Manage the arguments.
579 */
580 vb = fr_value_box_list_head(list);
581 arg = xlat_exp_head(node->call.args);
582
583 while (arg_p->type != FR_TYPE_NULL) {
584 /*
585 * Separate check to see if the group
586 * box is there. Check in
587 * xlat_process_arg_list verifies it
588 * has a value.
589 */
590 if (!vb) {
591 if (arg_p->required) {
592 missing:
593 REDEBUG("Function \"%s\" is missing required argument %u",
594 func->name, (unsigned int)((arg_p - func->args) + 1));
595 return XLAT_ACTION_FAIL;
596 }
597
598 /*
599 * The argument isn't required. Just omit it. xlat_func_args_set() enforces
600 * that optional arguments are at the end of the argument list.
601 */
602 return XLAT_ACTION_DONE;
603 }
604
605 /*
606 * Everything in the top level list should be
607 * groups
608 */
609 if (!fr_cond_assert(vb->type == FR_TYPE_GROUP)) return XLAT_ACTION_FAIL;
610
611 /*
612 * pre-advance, in case the vb is replaced
613 * during processing.
614 */
615 vb_next = fr_value_box_list_next(list, vb);
616 arg_next = xlat_exp_next(node->call.args, arg);
617
618 xa = xlat_process_arg_list(ctx, &vb->vb_group, request, func->name, arg_p, arg,
619 (unsigned int)((arg_p - func->args) + 1));
620 if (xa != XLAT_ACTION_DONE) return xa;
621
622 /*
623 * This argument doesn't exist. That might be OK, or it may be a fatal error.
624 */
625 if (fr_value_box_list_empty(&vb->vb_group)) {
626 /*
627 * Variadic rules deal with empty boxes differently...
628 */
629 switch (arg_p->variadic) {
631 fr_value_box_list_talloc_free_head(list);
632 goto do_next;
633
635 goto empty_ok;
636
638 break;
639 }
640
641 /*
642 * Empty groups for optional arguments are OK, we can just stop processing the list.
643 */
644 if (!arg_p->required) {
645 /*
646 * If the caller doesn't care about the type, then we leave the
647 * empty group there.
648 */
649 if (arg_p->type == FR_TYPE_VOID) goto do_next;
650
651 /*
652 * The caller does care about the type, and we don't have any
653 * matching data. Omit this argument, and all arguments after it.
654 *
655 * i.e. if the caller has 3 optional arguments, all
656 * FR_TYPE_UINT8, and the first one is missing, then we MUST
657 * either supply boxes all of FR_TYPE_UINT8, OR we supply nothing.
658 *
659 * We can't supply a box of any other type, because the caller
660 * has declared that it wants FR_TYPE_UINT8, and is naively
661 * accessing the box as vb_uint8, hoping that it's being passed
662 * the right thing.
663 */
664 fr_value_box_list_talloc_free_head(list);
665 break;
666 }
667
668 /*
669 * If the caller is expecting a particular type, then getting nothing is
670 * an error.
671 *
672 * If the caller manually checks the input type, then we can leave it as
673 * an empty group.
674 */
675 if (arg_p->type != FR_TYPE_VOID) goto missing;
676 }
677
678 empty_ok:
679 /*
680 * In some cases we replace the current argument with the head of the group.
681 *
682 * xlat_process_arg_list() has already done concatenations for us.
683 */
684 if (arg_p->single || arg_p->concat) {
685 fr_value_box_t *head = fr_value_box_list_pop_head(&vb->vb_group);
686
687 /*
688 * If we're meant to be smashing the argument
689 * to a single box, but the group was empty,
690 * add a null box instead so ordering is maintained
691 * for subsequent boxes.
692 */
693 if (!head) head = fr_value_box_alloc_null(ctx);
694 fr_value_box_list_replace(list, vb, head);
695 talloc_free(vb);
696 }
697
698 do_next:
699 if (arg_p->variadic) {
700 if (!vb_next) break;
701 } else {
702 arg_p++;
703 arg = arg_next;
704 }
705 vb = vb_next;
706 }
707
708 return XLAT_ACTION_DONE;
709}
710
711/** Validate that the return values from an xlat function match what it registered
712 *
713 * @param[in] request The current request.
714 * @param[in] func that was called.
715 * @param[in] returned the output list of the function.
716 * @param[in] pos current position in the output list.
717 * @return
718 * - true - If return values were correct.
719 * - false - If the return values were incorrect.
720 */
721static inline CC_HINT(nonnull(1,2,3))
722bool xlat_process_return(request_t *request, xlat_t const *func, fr_value_box_list_t const *returned, fr_value_box_t *pos)
723{
724 unsigned int count = 0;
725
726 /*
727 * Nothing to validate. We don't yet enforce that functions
728 * must return at least one instance of their type.
729 */
730 if (!pos || fr_type_is_void(func->return_type)) return true;
731
732 if (fr_type_is_null(func->return_type)) {
733 /* Dynamic expansion to get the right name */
734 REDEBUG("%s return type registered as %s, but %s expansion produced data",
735 func->name, func->name, fr_type_to_str(func->return_type));
736
737 /* We are not forgiving for debug builds */
738 fr_assert_fail("Treating invalid return type as fatal");
739
740 return false;
741 }
742
743 do {
744 if (pos->type != func->return_type) {
745 REDEBUG("%s returned invalid result type at index %u. Expected type %s, got type %s",
746 func->name, count, fr_type_to_str(func->return_type), fr_type_to_str(pos->type));
747
748 /* We are not forgiving for debug builds */
749 fr_assert_fail("Treating invalid return type as fatal");
750 }
751 fr_value_box_mark_safe_for(pos, func->return_safe_for); /* Always set this */
752 count++;
753 } while ((pos = fr_value_box_list_next(returned, pos)));
754
755 return true;
756}
757
758/** One letter expansions
759 *
760 * @param[in] ctx to allocate boxed value, and buffers in.
761 * @param[out] out Where to write the boxed value.
762 * @param[in] request The current request.
763 * @param[in] letter to expand.
764 * @return
765 * - #XLAT_ACTION_FAIL on memory allocation errors.
766 * - #XLAT_ACTION_DONE if we're done processing this node.
767 *
768 */
769static inline CC_HINT(always_inline)
770xlat_action_t xlat_eval_one_letter(TALLOC_CTX *ctx, fr_value_box_list_t *out,
771 request_t *request, char letter)
772{
773
774 char buffer[64];
775 struct tm ts;
776 time_t now;
778
779 now = fr_time_to_sec(request->packet->timestamp);
780
781 switch (letter) {
782 case '%':
784 if (fr_value_box_strdup(value, value, NULL, "%", false) < 0) return XLAT_ACTION_FAIL;
785 break;
786
787 /*
788 * RADIUS request values
789 */
790
791 case 'I': /* Request ID */
793 value->datum.uint32 = request->packet->id;
794 break;
795
796 case 'n': /* Request number */
798 value->datum.uint64 = request->number;
799 break;
800
801 case 's': /* First request in this sequence */
803 value->datum.uint64 = request->seq_start;
804 break;
805
806 /*
807 * Current time
808 */
809
810 case 'c': /* Current epoch time seconds */
811 /*
812 * @todo - leave this as FR_TYPE_DATE, but add an enumv which changes the scale to
813 * seconds?
814 */
816 value->datum.uint64 = (uint64_t)fr_time_to_sec(fr_time());
817 break;
818
819 case 'C': /* Current epoch time microsecond component */
820 /*
821 * @todo - we probably should remove this now that we have FR_TYPE_DATE with scaling.
822 */
824 value->datum.uint64 = (uint64_t)fr_time_to_usec(fr_time()) % 1000000;
825 break;
826
827 /*
828 * Time of the current request
829 */
830
831 case 'd': /* Request day */
832 if (!localtime_r(&now, &ts)) {
833 error:
834 REDEBUG("Failed converting packet timestamp to localtime: %s", fr_syserror(errno));
835 return XLAT_ACTION_FAIL;
836 }
837
839 value->datum.uint8 = ts.tm_mday;
840 break;
841
842 case 'D': /* Request date */
843 if (!localtime_r(&now, &ts)) goto error;
844
845 strftime(buffer, sizeof(buffer), "%Y%m%d", &ts);
846
848 if (fr_value_box_strdup(value, value, NULL, buffer, false) < 0) goto error;
849 break;
850
851 case 'e': /* Request second */
852 if (!localtime_r(&now, &ts)) goto error;
853
855 value->datum.uint8 = ts.tm_sec;
856 break;
857
858 case 'G': /* Request minute */
859 if (!localtime_r(&now, &ts)) goto error;
860
862 value->datum.uint8 = ts.tm_min;
863 break;
864
865 case 'H': /* Request hour */
866 if (!localtime_r(&now, &ts)) goto error;
867
869 value->datum.uint8 = ts.tm_hour;
870 break;
871
872 case 'l': /* Request timestamp as seconds since the epoch */
873 /*
874 * @todo - leave this as FR_TYPE_DATE, but add an enumv which changes the scale to
875 * seconds?
876 */
878 value->datum.uint64 = (uint64_t ) now;
879 break;
880
881 case 'm': /* Request month */
882 if (!localtime_r(&now, &ts)) goto error;
883
885 value->datum.uint8 = ts.tm_mon + 1;
886 break;
887
888 case 'M': /* Request time microsecond component */
889 /*
890 * @todo - we probably should remove this now that we have FR_TYPE_DATE with scaling.
891 */
893 value->datum.uint32 = fr_time_to_msec(request->packet->timestamp) % 1000;
894 break;
895
896 case 'S': /* Request timestamp in SQL format */
897 if (!localtime_r(&now, &ts)) goto error;
898
899 strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &ts);
900
902 if (fr_value_box_strdup(value, value, NULL, buffer, false) < 0) goto error;
903 break;
904
905 case 't': /* Request timestamp in CTIME format */
906 {
907 char *p;
908
909 CTIME_R(&now, buffer, sizeof(buffer));
910 p = strchr(buffer, '\n');
911 if (p) *p = '\0';
912
914 if (fr_value_box_strdup(value, value, NULL, buffer, false) < 0) goto error;
915 }
916 break;
917
918 case 'T': /* Request timestamp in ISO format */
919 {
920 int len = 0;
921
922 if (!gmtime_r(&now, &ts)) goto error;
923
924 if (!(len = strftime(buffer, sizeof(buffer) - 1, "%Y-%m-%dT%H:%M:%S", &ts))) {
925 REDEBUG("Failed converting packet timestamp to gmtime: Buffer full");
926 return XLAT_ACTION_FAIL;
927 }
928 strcat(buffer, ".");
929 len++;
930 snprintf(buffer + len, sizeof(buffer) - len, "%03i",
931 (int) fr_time_to_msec(request->packet->timestamp) % 1000);
932
934 if (fr_value_box_strdup(value, value, NULL, buffer, false) < 0) goto error;
935 }
936 break;
937
938 case 'Y': /* Request year */
939 if (!localtime_r(&now, &ts)) goto error;
940
942
943 value->datum.int16 = ts.tm_year + 1900;
944 break;
945
946 default:
947 fr_assert_fail("%%%c is not a valid one letter expansion", letter);
948 return XLAT_ACTION_FAIL;
949 }
950
951 fr_value_box_list_insert_tail(out, value);
952
953 return XLAT_ACTION_DONE;
954}
955
956typedef struct {
958 fr_value_box_list_t list;
960
962 xlat_ctx_t const *xctx,
963 UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
964{
965 xlat_exec_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_exec_rctx_t);
966
967 if (rctx->status != 0) {
968 fr_strerror_printf("Program failed with status %d", rctx->status);
969 return XLAT_ACTION_FAIL;
970 }
971
972 fr_value_box_list_move((fr_value_box_list_t *)out->dlist, &rctx->list);
973
974 return XLAT_ACTION_DONE;
975}
976
977
978/** Signal an xlat function
979 *
980 * @param[in] signal function to call.
981 * @param[in] exp Xlat node that previously yielded.
982 * @param[in] request The current request.
983 * @param[in] rctx Opaque (to us), resume ctx provided by the xlat function
984 * when it yielded.
985 * @param[in] action What the request should do (the type of signal).
986 */
988 request_t *request, void *rctx, fr_signal_t action)
989{
991
992 signal(XLAT_CTX(exp->call.inst, t->data, exp, t->mctx, NULL, rctx), request, action);
993}
994
996 UNUSED xlat_ctx_t const *xctx,
997 UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
998{
999 return XLAT_ACTION_DONE;
1000}
1001
1002/** Call an xlat's resumption method
1003 *
1004 * @param[in] ctx to allocate value boxes in.
1005 * @param[out] out a list of #fr_value_box_t to append to.
1006 * @param[out] child to evaluate. If a child needs to be evaluated
1007 * by the caller, we return XLAT_ACTION_PUSH_CHILD
1008 * and place the child to be evaluated here.
1009 * Once evaluation is complete, the caller
1010 * should call us with the same #xlat_exp_t and the
1011 * result of the nested evaluation in result.
1012 * @param[in] request the current request.
1013 * @param[in] head of the list to evaluate
1014 * @param[in,out] in xlat node to evaluate. Advanced as we process
1015 * additional #xlat_exp_t.
1016 * @param[in] result Previously expanded arguments to this xlat function.
1017 * @param[in] resume function to call.
1018 * @param[in] rctx Opaque (to us), resume ctx provided by xlat function
1019 * when it yielded.
1020 */
1022 xlat_exp_head_t const **child,
1023 request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in,
1024 fr_value_box_list_t *result, xlat_func_t resume, void *rctx)
1025{
1026 xlat_action_t xa;
1027 xlat_exp_t const *node = *in;
1028
1029 /*
1030 * It's important that callbacks leave the result list
1031 * in a valid state, as it leads to all kinds of hard
1032 * to debug problems if they free or change elements
1033 * and don't remove them from the list.
1034 */
1035 VALUE_BOX_LIST_VERIFY(result);
1036
1037 if (node->type != XLAT_FUNC) {
1038 xa = resume(ctx, out, XLAT_CTX(NULL, NULL, NULL, NULL, NULL, rctx), request, result);
1039 } else {
1041 t = xlat_thread_instance_find(node);
1042 xa = resume(ctx, out, XLAT_CTX(node->call.inst->data, t->data, node, t->mctx, NULL, rctx), request, result);
1043 VALUE_BOX_LIST_VERIFY(result);
1044
1045 RDEBUG2("| %%%s(...)", node->call.func->name);
1046 }
1047
1048 switch (xa) {
1049 case XLAT_ACTION_YIELD:
1050 RDEBUG2("| (YIELD)");
1051 return xa;
1052
1053 case XLAT_ACTION_DONE:
1054 if (unlang_xlat_yield(request, xlat_null_resume, NULL, 0, NULL) != XLAT_ACTION_YIELD) return XLAT_ACTION_FAIL;
1055
1056 fr_dcursor_next(out); /* Wind to the start of this functions output */
1057 if (node->call.func) {
1058 RDEBUG2("| --> %pV", fr_dcursor_current(out));
1059 if (!xlat_process_return(request, node->call.func, (fr_value_box_list_t *)out->dlist,
1061 }
1062
1063 /*
1064 * It's easier if we get xlat_frame_eval to continue evaluating the frame.
1065 */
1066 *in = xlat_exp_next(head, *in); /* advance */
1067 return xlat_frame_eval(ctx, out, child, request, head, in);
1068
1071 case XLAT_ACTION_FAIL:
1072 break;
1073 }
1074
1075 return xa;
1076}
1077
1078/** Process the result of a previous nested expansion
1079 *
1080 * @param[in] ctx to allocate value boxes in.
1081 * @param[out] out a list of #fr_value_box_t to append to.
1082 * @param[out] child to evaluate. If a child needs to be evaluated
1083 * by the caller, we return XLAT_ACTION_PUSH_CHILD
1084 * and place the child to be evaluated here.
1085 * Once evaluation is complete, the caller
1086 * should call us with the same #xlat_exp_t and the
1087 * result of the nested evaluation in result.
1088 * @param[in] request the current request.
1089 * @param[in] head of the list to evaluate
1090 * @param[in,out] in xlat node to evaluate. Advanced as we process
1091 * additional #xlat_exp_t.
1092 * @param[in] env_data Expanded call env.
1093 * @param[in] result of a previous nested evaluation.
1094 */
1096 xlat_exp_head_t const **child,
1097 request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in,
1098 void *env_data, fr_value_box_list_t *result)
1099{
1100 xlat_exp_t const *node = *in;
1101
1102 fr_dcursor_tail(out); /* Needed for reentrant behaviour and debugging */
1103
1104 switch (node->type) {
1105 case XLAT_FUNC:
1106 {
1107 xlat_action_t xa;
1109 fr_value_box_list_t result_copy;
1110
1111 t = xlat_thread_instance_find(node);
1112 fr_assert(t);
1113
1114 XLAT_DEBUG("** [%i] %s(func-async) - %%%s(%pM)",
1115 unlang_interpret_stack_depth(request), __FUNCTION__,
1116 node->fmt, result);
1117
1118 VALUE_BOX_LIST_VERIFY(result);
1119
1120 /*
1121 * Always need to init and free the
1122 * copy list as debug level could change
1123 * when the xlat function executes.
1124 */
1125 fr_value_box_list_init(&result_copy);
1126
1127 /*
1128 * Need to copy the input list in case
1129 * the async function mucks with it.
1130 */
1132 xa = xlat_process_args(ctx, result, request, node);
1133 if (xa == XLAT_ACTION_FAIL) {
1134 fr_value_box_list_talloc_free(&result_copy);
1135 return xa;
1136 }
1137
1138 VALUE_BOX_LIST_VERIFY(result);
1139 xa = node->call.func->func(ctx, out,
1140 XLAT_CTX(node->call.inst->data, t->data, node, t->mctx, env_data, NULL),
1141 request, result);
1142 VALUE_BOX_LIST_VERIFY(result);
1143
1144 if (RDEBUG_ENABLED2) {
1145 REXDENT();
1146 xlat_debug_log_expansion(request, *in, &result_copy, __LINE__);
1147 RINDENT();
1148 }
1149 fr_value_box_list_talloc_free(&result_copy);
1150
1151 switch (xa) {
1152 case XLAT_ACTION_FAIL:
1153 return xa;
1154
1156 RDEBUG3("| -- CHILD");
1157 return xa;
1158
1160 RDEBUG3("| -- UNLANG");
1161 return xa;
1162
1163 case XLAT_ACTION_YIELD:
1164 RDEBUG3("| -- YIELD");
1165 return xa;
1166
1167 case XLAT_ACTION_DONE: /* Process the result */
1169
1170 REXDENT();
1172 if (!xlat_process_return(request, node->call.func,
1173 (fr_value_box_list_t *)out->dlist,
1175 RINDENT();
1176 return XLAT_ACTION_FAIL;
1177 }
1178 RINDENT();
1179 break;
1180 }
1181 }
1182 break;
1183
1184 case XLAT_GROUP:
1185 {
1186 fr_value_box_t *arg;
1187
1188 /*
1189 * We'd like to do indent / exdent for groups, but that also involves fixing all of the
1190 * error paths. Which we won't do right now.
1191 */
1192 XLAT_DEBUG("** [%i] %s(child) - continuing %%{%s ...}", unlang_interpret_stack_depth(request), __FUNCTION__,
1193 node->fmt);
1194
1195 /*
1196 * Hoist %{...} to its results.
1197 *
1198 * There may be zero or more results.
1199 */
1200 if (node->hoist) {
1201 /*
1202 * Mash quoted strings, UNLESS they're in a function argument. In which case the argument parser
1203 * will do escaping.
1204 *
1205 * @todo - when pushing the xlat for expansion, also push the escaping rules. In which case we can do escaping here.
1206 */
1207 if ((node->quote != T_BARE_WORD) && !head->is_argv) {
1208 if (!fr_value_box_list_head(result)) {
1209 MEM(arg = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL));
1210 fr_value_box_strdup(arg, arg, NULL, "", false);
1211 fr_dcursor_insert(out, arg);
1212 break;
1213 }
1214
1215 /*
1216 * Mash all of the child value-box to a string.
1217 */
1218 arg = fr_value_box_list_head(result);
1219 fr_assert(arg != NULL);
1220
1221 if (fr_value_box_list_concat_in_place(arg, arg, result, FR_TYPE_STRING, FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0) {
1222 return -1;
1223 }
1224 }
1225
1226 while ((arg = fr_value_box_list_pop_head(result)) != NULL) {
1227 talloc_steal(ctx, arg);
1228 fr_dcursor_insert(out, arg);
1229 }
1230 break;
1231 }
1232
1233 MEM(arg = fr_value_box_alloc(ctx, FR_TYPE_GROUP, NULL));
1234
1235 if (!fr_value_box_list_empty(result)) {
1236 VALUE_BOX_LIST_VERIFY(result);
1237 fr_value_box_list_move(&arg->vb_group, result);
1238 }
1239
1240 VALUE_BOX_VERIFY(arg);
1241
1242 fr_dcursor_insert(out, arg);
1243 }
1244 break;
1245
1246 case XLAT_TMPL:
1247 fr_assert(tmpl_is_exec(node->vpt));
1248
1249 if (tmpl_eval_cast_in_place(result, request, node->vpt) < 0) {
1250 fr_value_box_list_talloc_free(result);
1251 return XLAT_ACTION_FAIL;
1252 }
1253
1254 /*
1255 * First entry is the command to run. Subsequent entries are the options to pass to the
1256 * command.
1257 */
1258 fr_value_box_list_move((fr_value_box_list_t *)out->dlist, result);
1259 break;
1260
1261 default:
1262 fr_assert(0);
1263 return XLAT_ACTION_FAIL;
1264 }
1265
1266 /*
1267 * It's easier if we get xlat_frame_eval to continue evaluating the frame.
1268 */
1269 *in = xlat_exp_next(head, *in); /* advance */
1270 return xlat_frame_eval(ctx, out, child, request, head, in);
1271}
1272
1273/** Converts xlat nodes to value boxes
1274 *
1275 * Evaluates a single level of expansions.
1276 *
1277 * @param[in] ctx to allocate value boxes in.
1278 * @param[out] out a list of #fr_value_box_t to append to.
1279 * @param[out] child to evaluate. If a child needs to be evaluated
1280 * by the caller, we return XLAT_ACTION_PUSH_CHILD
1281 * and place the child to be evaluated here.
1282 * Once evaluation is complete, the caller
1283 * should call us with the same #xlat_exp_t and the
1284 * result of the nested evaluation in result.
1285 * @param[in] request the current request.
1286 * @param[in] head of the list to evaluate
1287 * @param[in,out] in xlat node to evaluate. Advanced as we process
1288 * additional #xlat_exp_t.
1289 * @return
1290 * - XLAT_ACTION_PUSH_CHILD if we need to evaluate a deeper level of nested.
1291 * child will be filled with the node that needs to be evaluated.
1292 * call #xlat_frame_eval_repeat on this node, once there are results
1293 * from the nested expansion.
1294 * - XLAT_ACTION_YIELD a resumption frame was pushed onto the stack by an
1295 * xlat function and we need to wait for the request to be resumed
1296 * before continuing.
1297 * - XLAT_ACTION_DONE we're done, pop the frame.
1298 * - XLAT_ACTION_FAIL an xlat module failed.
1299 */
1301 request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in)
1302{
1304 xlat_exp_t const *node;
1305 fr_value_box_list_t result; /* tmp list so debug works correctly */
1307
1308 fr_value_box_list_init(&result);
1309
1310 *child = NULL;
1311
1312 if (!*in) return XLAT_ACTION_DONE;
1313
1314 /*
1315 * An attribute reference which is a cursor just gets a
1316 * value-box of cursor returned. That is filled in
1317 * later.
1318 */
1319 if (unlikely(head && head->cursor)) {
1320 int err;
1321
1322 fr_assert((*in)->type == XLAT_TMPL);
1323
1325
1326 (void) tmpl_dcursor_value_box_init(&err, value, value, request, (*in)->vpt);
1327 if (err < -1) return XLAT_ACTION_FAIL;
1328
1330 goto finish;
1331 }
1332
1333 XLAT_DEBUG("** [%i] %s >> entered", unlang_interpret_stack_depth(request), __FUNCTION__);
1334
1335 for (node = *in; node; node = xlat_exp_next(head, node)) {
1336 *in = node; /* Update node in our caller */
1337 fr_dcursor_tail(out); /* Needed for debugging */
1338 VALUE_BOX_LIST_VERIFY((fr_value_box_list_t *)out->dlist);
1339
1340 fr_assert(fr_value_box_list_num_elements(&result) == 0); /* Should all have been moved */
1341
1342 switch (node->type) {
1343 case XLAT_BOX:
1344 XLAT_DEBUG("** [%i] %s(value_box) - %s", unlang_interpret_stack_depth(request), __FUNCTION__, node->fmt);
1345
1346 /*
1347 * Empty boxes are only allowed if
1348 * they're the only node in the expansion.
1349 *
1350 * If they're found anywhere else the xlat
1351 * parser has an error.
1352 */
1353 fr_assert(((node == *in) && !xlat_exp_next(head, node)) || (talloc_array_length(node->fmt) > 1));
1354
1355 /*
1356 * We unfortunately need to dup the buffer
1357 * because references aren't threadsafe.
1358 */
1360 if (fr_value_box_copy(value, value, &node->data) < 0) goto fail;
1362 continue;
1363
1364 case XLAT_ONE_LETTER:
1365 XLAT_DEBUG("** [%i] %s(one-letter) - %%%s", unlang_interpret_stack_depth(request), __FUNCTION__,
1366 node->fmt);
1367
1368 xlat_debug_log_expansion(request, node, NULL, __LINE__);
1369 if (xlat_eval_one_letter(ctx, &result, request, node->fmt[0]) == XLAT_ACTION_FAIL) {
1370 fail:
1371 fr_value_box_list_talloc_free(&result);
1372 xa = XLAT_ACTION_FAIL;
1373 goto finish;
1374 }
1375 xlat_debug_log_list_result(request, *in, &result);
1376 fr_value_box_list_move((fr_value_box_list_t *)out->dlist, &result);
1377 continue;
1378
1379 case XLAT_TMPL:
1380 /*
1381 * Everything should have been resolved.
1382 */
1383 fr_assert(!tmpl_needs_resolving(node->vpt));
1384
1385 if (tmpl_is_data(node->vpt)) {
1386 XLAT_DEBUG("** [%i] %s(value) - %s", unlang_interpret_stack_depth(request), __FUNCTION__,
1387 node->vpt->name);
1388
1389 MEM(value = fr_value_box_alloc(ctx, tmpl_value_type(node->vpt), NULL));
1390
1391 fr_value_box_copy(value, value, tmpl_value(node->vpt)); /* Also dups taint */
1392 fr_value_box_list_insert_tail(&result, value);
1393
1394 /*
1395 * Cast the results if necessary.
1396 */
1397 if (tmpl_eval_cast_in_place(&result, request, node->vpt) < 0) goto fail;
1398
1399 fr_value_box_list_move((fr_value_box_list_t *)out->dlist, &result);
1400 continue;
1401
1402 } else if (tmpl_is_attr(node->vpt)) {
1403 if (node->fmt[0] == '&') {
1404 XLAT_DEBUG("** [%i] %s(attribute) - %s", unlang_interpret_stack_depth(request), __FUNCTION__,
1405 node->fmt);
1406 } else {
1407 XLAT_DEBUG("** [%i] %s(attribute) - %%{%s}", unlang_interpret_stack_depth(request), __FUNCTION__,
1408 node->fmt);
1409 }
1410 xlat_debug_log_expansion(request, node, NULL, __LINE__);
1411
1412 if (tmpl_eval_pair(ctx, &result, request, node->vpt) < 0) goto fail;
1413
1414 } else if (tmpl_is_exec(node->vpt) || tmpl_is_xlat(node->vpt)) {
1415 xlat_exec_rctx_t *rctx;
1416
1417 /*
1418 * Allocate and initialize the output context, with value-boxes, exec status, etc.
1419 */
1420 MEM(rctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), xlat_exec_rctx_t));
1421 fr_value_box_list_init(&rctx->list);
1422
1423 xlat_debug_log_expansion(request, node, NULL, __LINE__);
1424
1425 if (unlang_xlat_yield(request, xlat_exec_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto fail;
1426
1427 if (unlang_tmpl_push(ctx, &rctx->list, request, node->vpt,
1429 false, &rctx->status)) < 0) goto fail;
1430
1432 goto finish;
1433
1434 } else {
1435#ifdef NDEBUG
1436 xa = XLAT_ACTION_FAIL;
1437 goto finish;
1438#endif
1439
1440 /*
1441 * Either this should have been handled previously, or we need to write
1442 * code to deal with this case.
1443 */
1444 fr_assert(0);
1445 }
1446
1447 xlat_debug_log_list_result(request, node, &result);
1448 fr_value_box_list_move((fr_value_box_list_t *)out->dlist, &result);
1449 continue;
1450
1451 case XLAT_FUNC:
1452 XLAT_DEBUG("** [%i] %s(func) - %%%s(...)", unlang_interpret_stack_depth(request), __FUNCTION__,
1453 node->fmt);
1454
1455 /*
1456 * Hand back the child node to the caller
1457 * for evaluation.
1458 */
1459 if (xlat_exp_head(node->call.args)) {
1460 *child = node->call.args;
1462 goto finish;
1463 }
1464
1465 /*
1466 * If there's no children we can just
1467 * call the function directly.
1468 */
1469 xa = xlat_frame_eval_repeat(ctx, out, child, request, head, in, NULL, &result);
1470 if (xa != XLAT_ACTION_DONE || (!*in)) goto finish;
1471 continue;
1472
1473#ifdef HAVE_REGEX
1474 case XLAT_REGEX:
1475 XLAT_DEBUG("** [%i] %s(regex) - %%{%s}", unlang_interpret_stack_depth(request), __FUNCTION__,
1476 node->fmt);
1477
1478 xlat_debug_log_expansion(request, node, NULL, __LINE__);
1480 if (regex_request_to_sub(value, value, request, node->regex_index) < 0) {
1482 continue;
1483 }
1484
1485 xlat_debug_log_result(request, node, value);
1487 continue;
1488#endif
1489
1490 case XLAT_GROUP:
1491 XLAT_DEBUG("** [%i] %s(child) - %%{%s ...}", unlang_interpret_stack_depth(request), __FUNCTION__,
1492 node->fmt);
1493 if (!node->group) return XLAT_ACTION_DONE;
1494
1495 /*
1496 * Hand back the child node to the caller
1497 * for evaluation.
1498 */
1499 *child = node->group;
1501 goto finish;
1502
1503 /*
1504 * Should have been fixed up during pass2
1505 */
1506 case XLAT_INVALID:
1508 fr_assert(0);
1509 return XLAT_ACTION_FAIL;
1510 }
1511 }
1512
1513finish:
1514 VALUE_BOX_LIST_VERIFY((fr_value_box_list_t *)out->dlist);
1515 XLAT_DEBUG("** [%i] %s << %s", unlang_interpret_stack_depth(request),
1516 __FUNCTION__, fr_table_str_by_value(xlat_action_table, xa, "<INVALID>"));
1517
1518 return xa;
1519}
1520
1521static int xlat_sync_stringify(TALLOC_CTX *ctx, request_t *request, xlat_exp_head_t const *head, fr_value_box_list_t *list,
1522 xlat_escape_legacy_t escape, void const *escape_ctx)
1523{
1524 fr_value_box_t *vb, *box;
1525 xlat_exp_t *node;
1526 fr_value_box_safe_for_t safe_for_expected = escape ? (fr_value_box_safe_for_t) escape : FR_VALUE_BOX_SAFE_FOR_ANY;
1528
1529 vb = fr_value_box_list_head(list);
1530 if (!vb) return 0;
1531
1532 node = xlat_exp_head(head);
1533 fr_assert(node != NULL);
1534
1535 do {
1536 size_t len, real_len;
1537 char *escaped;
1538
1539 /*
1540 * Groups commonly are because of quoted strings.
1541 *
1542 * However, we sometimes have a group because of %{...}, in which case the result is just
1543 * a leaf value.
1544 */
1545 if ((node->type == XLAT_GROUP) && (vb->type == FR_TYPE_GROUP)) {
1546 fr_assert(node->quote != T_BARE_WORD);
1547
1548 if (xlat_sync_stringify(vb, request, node->group, &vb->vb_group, escape, escape_ctx) < 0) return -1;
1549
1550 /*
1551 * Replace the group wuth a fixed string.
1552 */
1553 MEM(box = fr_value_box_alloc_null(ctx));
1554
1555 if (fr_value_box_cast(box, box, FR_TYPE_STRING, NULL, vb) < 0) return -1;
1556
1557 /*
1558 * Remove the group, and replace it with the string.
1559 */
1560 fr_value_box_list_insert_before(list, vb, box);
1561 fr_value_box_list_remove(list, vb);
1562 talloc_free(vb);
1563 vb = box;
1564
1565 /*
1566 * It's now safe, so we don't need to do anything else.
1567 */
1568 fr_value_box_mark_safe_for(vb, safe_for_mark);
1569 goto next;
1570 }
1571
1572 if (!escape) goto next;
1573
1574 if (fr_value_box_is_safe_for(vb, safe_for_expected)) goto next;
1575
1576 /*
1577 * We cast EVERYTHING to a string and also escape everything.
1578 */
1579 if (fr_value_box_cast_in_place(vb, vb, FR_TYPE_STRING, NULL) < 0) {
1580 return -1;
1581 }
1582
1583 len = vb->vb_length * 3;
1584 MEM(escaped = talloc_array(vb, char, len));
1585 real_len = escape(request, escaped, len, vb->vb_strvalue, UNCONST(void *, escape_ctx));
1586
1587 fr_value_box_strdup_shallow_replace(vb, escaped, real_len);
1588 fr_value_box_mark_safe_for(vb, safe_for_mark);
1589
1590 next:
1591 vb = fr_value_box_list_next(list, vb);
1592 node = xlat_exp_next(head, node);
1593
1594 } while (node && vb);
1595
1596 return 0;
1597}
1598
1599static ssize_t xlat_eval_sync(TALLOC_CTX *ctx, char **out, request_t *request, xlat_exp_head_t const * const head,
1600 xlat_escape_legacy_t escape, void const *escape_ctx)
1601{
1602 fr_value_box_list_t result;
1603 bool success = false;
1604 TALLOC_CTX *pool = talloc_new(NULL);
1605 rlm_rcode_t rcode;
1606 char *str;
1607
1608 XLAT_DEBUG("xlat_eval_sync");
1609
1610 *out = NULL;
1611
1612 fr_value_box_list_init(&result);
1613
1614 /*
1615 * Use the unlang stack to evaluate the xlat.
1616 */
1617 if (unlang_xlat_push(pool, &success, &result, request, head, UNLANG_TOP_FRAME) < 0) {
1618 fail:
1619 talloc_free(pool);
1620 return -1;
1621 }
1622
1623 /*
1624 * Pure functions don't yield, and can therefore be
1625 * expanded in place. This check saves an expensive
1626 * bounce through a new synchronous interpreter.
1627 */
1628 if (!xlat_impure_func(head) && unlang_interpret_get(request)) {
1629 rcode = unlang_interpret(request, UNLANG_REQUEST_RUNNING);
1630 } else {
1632 }
1633
1634 switch (rcode) {
1635 default:
1636 if (!success) goto fail;
1637 break;
1638
1639 case RLM_MODULE_REJECT:
1640 case RLM_MODULE_FAIL:
1641 goto fail;
1642 }
1643
1644 if (!fr_value_box_list_empty(&result)) {
1645 /*
1646 * Walk over the data recursively, escaping it, and converting quoted groups to strings.
1647 */
1648 if (xlat_sync_stringify(pool, request, head, &result, escape, escape_ctx) < 0) {
1649 goto fail;
1650 }
1651
1652 str = fr_value_box_list_aprint(ctx, &result, NULL, NULL);
1653 if (!str) goto fail;
1654 } else {
1655 str = talloc_typed_strdup(ctx, "");
1656 }
1657 talloc_free(pool); /* Memory should be in new ctx */
1658
1659 *out = str;
1660
1661 return talloc_array_length(str) - 1;
1662}
1663
1664/** Replace %whatever in a string.
1665 *
1666 * See 'doc/unlang/xlat.adoc' for more information.
1667 *
1668 * @param[in] ctx to allocate expansion buffers in.
1669 * @param[out] out Where to write pointer to output buffer.
1670 * @param[in] outlen Size of out.
1671 * @param[in] request current request.
1672 * @param[in] head the xlat structure to expand
1673 * @param[in] escape function to escape final value e.g. SQL quoting.
1674 * @param[in] escape_ctx pointer to pass to escape function.
1675 * @return length of string written @bug should really have -1 for failure.
1676 */
1677static ssize_t _xlat_eval_compiled(TALLOC_CTX *ctx, char **out, size_t outlen, request_t *request,
1678 xlat_exp_head_t const *head, xlat_escape_legacy_t escape, void const *escape_ctx)
1679{
1680 char *buff;
1681 ssize_t slen;
1682
1683 fr_assert(head != NULL);
1684
1685 slen = xlat_eval_sync(ctx, &buff, request, head, escape, escape_ctx);
1686 if (slen < 0) {
1687 fr_assert(buff == NULL);
1688 if (*out) **out = '\0';
1689 return slen;
1690 }
1691
1692 /*
1693 * If out doesn't point to an existing buffer
1694 * copy the pointer to our buffer over.
1695 */
1696 if (!*out) {
1697 *out = buff;
1698 return slen;
1699 }
1700
1701 if ((size_t)slen >= outlen) {
1702 fr_strerror_const("Insufficient output buffer space");
1703 return -1;
1704 }
1705
1706 /*
1707 * Otherwise copy the talloced buffer to the fixed one.
1708 */
1709 memcpy(*out, buff, slen);
1710 (*out)[slen] = '\0';
1712
1713 return slen;
1714}
1715
1716/** Replace %whatever in a string.
1717 *
1718 * See 'doc/unlang/xlat.adoc' for more information.
1719 *
1720 * @param[in] ctx to allocate expansion buffers in.
1721 * @param[out] out Where to write pointer to output buffer.
1722 * @param[in] outlen Size of out.
1723 * @param[in] request current request.
1724 * @param[in] fmt string to expand.
1725 * @param[in] escape function to escape final value e.g. SQL quoting.
1726 * @param[in] escape_ctx pointer to pass to escape function.
1727 * @return length of string written @bug should really have -1 for failure.
1728 */
1729static CC_HINT(nonnull (2, 4, 5))
1730ssize_t _xlat_eval(TALLOC_CTX *ctx, char **out, size_t outlen, request_t *request, char const *fmt,
1731 xlat_escape_legacy_t escape, void const *escape_ctx)
1732{
1733 ssize_t len;
1735
1736 RINDENT();
1737
1738 /*
1739 * Give better errors than the old code.
1740 */
1741 len = xlat_tokenize(ctx, &head,
1742 &FR_SBUFF_IN(fmt, strlen(fmt)),
1743 NULL,
1744 &(tmpl_rules_t){
1745 .attr = {
1746 .dict_def = request->local_dict,
1747 .list_def = request_attr_request,
1748 },
1749 .xlat = {
1750 .runtime_el = unlang_interpret_event_list(request),
1751 },
1752 .at_runtime = true,
1753 });
1754 if (len == 0) {
1755 if (*out) {
1756 **out = '\0';
1757 } else {
1758 *out = talloc_zero_array(ctx, char, 1);
1759 }
1760 REXDENT();
1761 return 0;
1762 }
1763
1764 if (len < 0) {
1765 REMARKER(fmt, -(len), "%s", fr_strerror());
1766 if (*out) **out = '\0';
1767 REXDENT();
1768 return -1;
1769 }
1770
1771 len = _xlat_eval_compiled(ctx, out, outlen, request, head, escape, escape_ctx);
1773
1774 REXDENT();
1775
1776 return len;
1777}
1778
1779ssize_t xlat_eval(char *out, size_t outlen, request_t *request,
1780 char const *fmt, xlat_escape_legacy_t escape, void const *escape_ctx)
1781{
1783
1784 return _xlat_eval(request, &out, outlen, request, fmt, escape, escape_ctx);
1785}
1786
1787ssize_t xlat_eval_compiled(char *out, size_t outlen, request_t *request,
1788 xlat_exp_head_t const *xlat, xlat_escape_legacy_t escape, void const *escape_ctx)
1789{
1791
1792 return _xlat_eval_compiled(request, &out, outlen, request, xlat, escape, escape_ctx);
1793}
1794
1795ssize_t xlat_aeval(TALLOC_CTX *ctx, char **out, request_t *request, char const *fmt,
1796 xlat_escape_legacy_t escape, void const *escape_ctx)
1797{
1799
1800 *out = NULL;
1801 return _xlat_eval(ctx, out, 0, request, fmt, escape, escape_ctx);
1802}
1803
1804ssize_t xlat_aeval_compiled(TALLOC_CTX *ctx, char **out, request_t *request,
1805 xlat_exp_head_t const *xlat, xlat_escape_legacy_t escape, void const *escape_ctx)
1806{
1808
1809 *out = NULL;
1810 return _xlat_eval_compiled(ctx, out, 0, request, xlat, escape, escape_ctx);
1811}
1812
1813
1814/** Turn am xlat list into an argv[] array, and nuke the input list.
1815 *
1816 * This is mostly for async use.
1817 */
1819{
1820 int i;
1821 xlat_exp_head_t **my_argv;
1822 size_t count;
1823
1824 if (head->flags.needs_resolving) {
1825 fr_strerror_printf("Cannot flatten expression with unresolved functions");
1826 return -1;
1827 }
1828
1829 count = 0;
1830 xlat_exp_foreach(head, node) {
1831 count++;
1832 }
1833
1834 MEM(my_argv = talloc_zero_array(ctx, xlat_exp_head_t *, count + 1));
1835 *argv = my_argv;
1836
1838
1839 i = 0;
1840 xlat_exp_foreach(head, node) {
1841 fr_assert(node->type == XLAT_GROUP);
1842 my_argv[i++] = talloc_steal(my_argv, node->group);
1843 }
1844
1845 fr_value_box_list_talloc_free((fr_value_box_list_t *)&head->dlist);
1846
1847 return count;
1848}
1849
1850/** Walk over all xlat nodes (depth first) in a xlat expansion, calling a callback
1851 *
1852 * @param[in] head to evaluate.
1853 * @param[in] walker callback to pass nodes to.
1854 * @param[in] type if > 0 a mask of types to call walker for.
1855 * @param[in] uctx to pass to walker.
1856 * @return
1857 * - 0 on success (walker always returned 0).
1858 * - <0 if walker returned <0.
1859 */
1861{
1862 int ret;
1863
1864 /*
1865 * Iterate over nodes at the same depth
1866 */
1867 xlat_exp_foreach(head, node) {
1868 switch (node->type){
1869 case XLAT_FUNC:
1870 /*
1871 * Evaluate the function's arguments
1872 * first, as they may get moved around
1873 * when the function is instantiated.
1874 */
1875 if (xlat_exp_head(node->call.args)) {
1876 ret = xlat_eval_walk(node->call.args, walker, type, uctx);
1877 if (ret < 0) return ret;
1878 }
1879
1880 if (!type || (type & XLAT_FUNC)) {
1881 ret = walker(node, uctx);
1882 if (ret < 0) return ret;
1883 }
1884 break;
1885
1887 if (xlat_exp_head(node->call.args)) {
1888 ret = xlat_eval_walk(node->call.args, walker, type, uctx);
1889 if (ret < 0) return ret;
1890 }
1891
1892 if (!type || (type & XLAT_FUNC_UNRESOLVED)) {
1893 ret = walker(node, uctx);
1894 if (ret < 0) return ret;
1895 }
1896 break;
1897
1898 case XLAT_GROUP:
1899 if (!type || (type & XLAT_GROUP)) {
1900 ret = walker(node, uctx);
1901 if (ret < 0) return ret;
1902 if (ret > 0) continue;
1903 }
1904
1905 /*
1906 * Evaluate the child.
1907 */
1908 ret = xlat_eval_walk(node->group, walker, type, uctx);
1909 if (ret < 0) return ret;
1910 break;
1911
1912 default:
1913 if (!type || (type & node->type)) {
1914 ret = walker(node, uctx);
1915 if (ret < 0) return ret;
1916 }
1917 break;
1918 }
1919 }
1920
1921 return 0;
1922}
1923
1925{
1927
1928 if (instance_count > 0) {
1930 return 0;
1931 }
1932
1934
1936 PERROR("%s", __FUNCTION__);
1937 return -1;
1938 }
1939
1941 PERROR("%s", __FUNCTION__);
1943 return -1;
1944 }
1945
1946 return 0;
1947}
1948
1950{
1952
1953 if (--instance_count > 0) return;
1954
1956}
static int const char char buffer[256]
Definition acutest.h:576
va_list args
Definition acutest.h:770
static int const char * fmt
Definition acutest.h:573
int const char int line
Definition acutest.h:702
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:290
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:408
static void * fr_dcursor_tail(fr_dcursor_t *cursor)
Wind cursor to the tail item in the list.
Definition dcursor.h:260
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition dcursor.h:437
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:339
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition debug.h:216
#define MEM(x)
Definition debug.h:36
#define fr_dict_autofree(_to_free)
Definition dict.h:869
static fr_slen_t err
Definition dict.h:840
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:273
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:286
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4134
#define fr_dict_autoload(_to_load)
Definition dict.h:866
static fr_slen_t in
Definition dict.h:840
Specifies an attribute which must be present for the module to function.
Definition dict.h:272
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:285
Test enumeration values.
Definition dict_test.h:92
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition dlist.h:939
#define EXEC_TIMEOUT
Default wait time for exec calls (in seconds).
Definition exec.h:32
rlm_rcode_t unlang_interpret(request_t *request, bool running)
Run the interpreter for a current request.
Definition interpret.c:712
unlang_interpret_t * unlang_interpret_get(request_t *request)
Get the interpreter set for a request.
Definition interpret.c:1747
int unlang_interpret_stack_depth(request_t *request)
Return the depth of the request's stack.
Definition interpret.c:1276
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:1405
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:1757
#define UNLANG_TOP_FRAME
Definition interpret.h:35
#define UNLANG_REQUEST_RUNNING
Definition interpret.h:41
rlm_rcode_t unlang_interpret_synchronous(fr_event_list_t *el, request_t *request)
Execute an unlang section synchronously.
#define PERROR(_fmt,...)
Definition log.h:228
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:443
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RERROR(fmt,...)
Definition log.h:298
#define REMARKER(_str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
Definition log.h:498
#define RPEDEBUG(fmt,...)
Definition log.h:376
#define RINDENT()
Indent R* messages by one level.
Definition log.h:430
talloc_free(reap)
size_t(* xlat_escape_legacy_t)(request_t *request, char *out, size_t outlen, char const *in, void *arg)
fr_type_t
@ 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_UINT16
16 Bit unsigned integer.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_VOID
User data.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_GROUP
A grouping of other attributes.
long int ssize_t
unsigned char bool
ssize_t fr_slen_t
struct tm * gmtime_r(time_t const *l_clock, struct tm *result)
Definition missing.c:201
struct tm * localtime_r(time_t const *l_clock, struct tm *result)
Definition missing.c:163
#define fr_assert(_expr)
Definition rad_assert.h:38
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG_ENABLED2()
Definition radclient.h:50
#define RDEBUG2(fmt,...)
Definition radclient.h:54
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:42
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:41
fr_dict_attr_t const * request_attr_request
Definition request.c:43
static char const * name
ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1456
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition sbuff.c:1597
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define fr_sbuff_set(_dst, _src)
#define FR_SBUFF_IN(_start, _len_or_end)
#define FR_SBUFF_IN_SPRINTF_RETURN(...)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
#define tmpl_is_xlat(vpt)
Definition tmpl.h:210
#define tmpl_value(_tmpl)
Definition tmpl.h:937
#define tmpl_is_attr(vpt)
Definition tmpl.h:208
#define tmpl_is_exec(vpt)
Definition tmpl.h:211
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.
int tmpl_eval_cast_in_place(fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
Casts a value or list of values according to the tmpl.
Definition tmpl_eval.c:1228
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.
Definition tmpl_eval.c:956
#define tmpl_is_data(vpt)
Definition tmpl.h:206
static fr_slen_t vpt
Definition tmpl.h:1269
#define tmpl_value_type(_tmpl)
Definition tmpl.h:939
#define tmpl_needs_resolving(vpt)
Definition tmpl.h:223
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:332
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
return count
Definition module.c:155
fr_aka_sim_id_type_t type
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
An element in an arbitrarily ordered array of name to ptr mappings.
Definition table.h:73
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition talloc.c:467
static int64_t fr_time_to_sec(fr_time_t when)
Convert an fr_time_t (internal time) to number of sec since the unix epoch (wallclock time)
Definition time.h:731
static int64_t fr_time_to_msec(fr_time_t when)
Convert an fr_time_t (internal time) to number of msec since the unix epoch (wallclock time)
Definition time.h:711
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
static int64_t fr_time_to_usec(fr_time_t when)
Convert an fr_time_t (internal time) to number of usec since the unix epoch (wallclock time)
Definition time.h:701
int unlang_tmpl_push(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *tmpl, unlang_tmpl_args_t *args)
Push a tmpl onto the stack for evaluation.
Definition tmpl.c:260
fr_pair_t * tmpl_dcursor_value_box_init(int *err, TALLOC_CTX *ctx, fr_value_box_t *vb, request_t *request, tmpl_t const *vpt)
Initialize a #tmpl_dcursor_t into a fr_value_box_t.
goto success
Definition tmpl_eval.c:1332
@ T_BARE_WORD
Definition token.h:120
#define TMPL_ARGS_EXEC(_env, _timeout, _stdout_on_error, _status_out)
Create a temporary argument structure for evaluating an exec type tmpl.
Definition tmpl.h:75
xlat_action_t unlang_xlat_yield(request_t *request, xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition xlat.c:567
int unlang_xlat_push(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
Definition xlat.c:283
fr_type_t type
Type to cast argument to.
Definition xlat.h:154
uint8_t single
Argument must only contain a single box.
Definition xlat.h:147
void * data
Thread specific instance data.
Definition xlat.h:93
xlat_thread_inst_t * xlat_thread_instance_find(xlat_exp_t const *node)
Retrieve xlat/thread specific instance data.
Definition xlat_inst.c:405
bool xlat_is_literal(xlat_exp_head_t const *head)
Check to see if the expansion consists entirely of value-box elements.
void * uctx
Argument to pass to escape callback.
Definition xlat.h:158
bool xlat_impure_func(xlat_exp_head_t const *head)
xlat_escape_func_t func
Function to handle tainted values.
Definition xlat.h:155
fr_slen_t xlat_tokenize(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)
Tokenize an xlat expansion.
uint8_t always_escape
Pass all arguments to escape function not just tainted ones.
Definition xlat.h:150
@ XLAT_ARG_VARIADIC_EMPTY_KEEP
Empty argument groups are left alone, and either passed through as empty groups or null boxes.
Definition xlat.h:136
@ XLAT_ARG_VARIADIC_EMPTY_SQUASH
Empty argument groups are removed.
Definition xlat.h:135
@ XLAT_ARG_VARIADIC_DISABLED
Definition xlat.h:134
static fr_slen_t head
Definition xlat.h:419
xlat_arg_parser_variadic_t variadic
All additional boxes should be processed using this definition.
Definition xlat.h:152
void(* xlat_func_signal_t)(xlat_ctx_t const *xctx, request_t *request, fr_signal_t action)
A callback when the request gets a fr_signal_t.
Definition xlat.h:242
uint8_t will_escape
the function will do escaping and concatenation.
Definition xlat.h:149
fr_value_box_safe_for_t safe_for
Escaped value to set for boxes processed by this escape function.
Definition xlat.h:156
uint8_t required
Argument must be present, and non-empty.
Definition xlat.h:145
xlat_action_t(* xlat_func_t)(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
xlat callback function
Definition xlat.h:231
uint8_t concat
Concat boxes together.
Definition xlat.h:146
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_YIELD
An xlat function pushed a resume frame onto the stack.
Definition xlat.h:42
@ XLAT_ACTION_PUSH_UNLANG
An xlat function pushed an unlang frame onto the unlang stack.
Definition xlat.h:39
@ XLAT_ACTION_PUSH_CHILD
A deeper level of nesting needs to be evaluated.
Definition xlat.h:38
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
uint8_t constant
xlat is just tmpl_attr_tail_data, or XLAT_BOX
Definition xlat.h:113
module_ctx_t const * mctx
A synthesised module calling ctx containing module global and thread instance data.
Definition xlat.h:95
Definition for a single argument consumend by an xlat function.
Definition xlat.h:144
Thread specific instance data for xlat expansion node.
Definition xlat.h:84
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_type_is_void(_x)
Definition types.h:374
@ FR_TYPE_PAIR_CURSOR
cursor over a fr_pair_t
Definition types.h:89
#define fr_type_is_null(_x)
Definition types.h:343
#define fr_type_is_leaf(_x)
Definition types.h:389
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:450
void fr_value_box_debug(fr_value_box_t const *vb)
Print the value of a box as info messages.
Definition value.c:6684
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.
Definition value.c:3574
char * fr_value_box_list_aprint(TALLOC_CTX *ctx, fr_value_box_list_t const *list, char const *delim, fr_sbuff_escape_rules_t const *e_rules)
Concatenate the string representations of a list of value boxes together.
Definition value.c:6213
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.
Definition value.c:3962
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.
Definition value.c:3790
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:3899
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
Definition value.c:4158
void fr_value_box_strdup_shallow_replace(fr_value_box_t *vb, char const *src, ssize_t len)
Free the existing buffer (if talloced) associated with the valuebox, and replace it with a new one.
Definition value.c:4283
int fr_value_box_list_acopy(TALLOC_CTX *ctx, fr_value_box_list_t *out, fr_value_box_list_t const *in)
Do a full copy of a list of value boxes.
Definition value.c:6343
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.
Definition value.c:5949
@ FR_VALUE_BOX_LIST_FREE
Definition value.h:237
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:640
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition value.h:1071
#define fr_box_strvalue_buffer(_val)
Definition value.h:308
#define fr_value_box_is_safe_for(_box, _safe_for)
Definition value.h:1078
#define FR_VALUE_BOX_SAFE_FOR_NONE
Definition value.h:170
uintptr_t fr_value_box_safe_for_t
Escaping that's been applied to a value box.
Definition value.h:160
#define VALUE_BOX_VERIFY(_x)
Definition value.h:1318
#define VALUE_BOX_LIST_VERIFY(_x)
Definition value.h:1319
int nonnull(2, 5))
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:651
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:606
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:222
static size_t char ** out
Definition value.h:1020
#define FR_VALUE_BOX_SAFE_FOR_ANY
Definition value.h:171
void * rctx
Resume context.
Definition xlat_ctx.h:54
#define XLAT_CTX(_inst, _thread, _ex, _mctx, _env_data, _rctx)
Wrapper to create a xlat_ctx_t as a compound literal.
Definition xlat_ctx.h:95
An xlat calling ctx.
Definition xlat_ctx.h:49
ssize_t xlat_eval_compiled(char *out, size_t outlen, request_t *request, xlat_exp_head_t const *xlat, xlat_escape_legacy_t escape, void const *escape_ctx)
Definition xlat_eval.c:1787
static size_t xlat_time_precision_table_len
Definition xlat_eval.c:125
static fr_dict_attr_t const * attr_cast_time_res_week
Definition xlat_eval.c:49
static fr_table_ptr_ordered_t const xlat_time_precision_table[]
Definition xlat_eval.c:87
static fr_slen_t xlat_fmt_print(fr_sbuff_t *out, xlat_exp_t const *node)
Reconstruct the original expansion string from an xlat tree.
Definition xlat_eval.c:148
static void xlat_debug_log_expansion(request_t *request, xlat_exp_t const *node, fr_value_box_list_t const *args, UNUSED int line)
Output what we're currently expanding.
Definition xlat_eval.c:216
xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_t const **child, request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in, void *env_data, fr_value_box_list_t *result)
Process the result of a previous nested expansion.
Definition xlat_eval.c:1095
void xlat_signal(xlat_func_signal_t signal, xlat_exp_t const *exp, request_t *request, void *rctx, fr_signal_t action)
Signal an xlat function.
Definition xlat_eval.c:987
fr_dict_attr_t const * xlat_time_res_attr(char const *res)
Definition xlat_eval.c:127
static void xlat_debug_log_result(request_t *request, xlat_exp_t const *node, fr_value_box_t const *result)
Output the result of an expansion.
Definition xlat_eval.c:264
int xlat_eval_init(void)
Definition xlat_eval.c:1924
fr_table_num_sorted_t const xlat_action_table[]
Definition xlat_eval.c:76
xlat_action_t xlat_frame_eval_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_t const **child, request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in, fr_value_box_list_t *result, xlat_func_t resume, void *rctx)
Call an xlat's resumption method.
Definition xlat_eval.c:1021
static fr_dict_attr_t const * attr_cast_time_res_year
Definition xlat_eval.c:51
static fr_dict_t const * dict_freeradius
Definition xlat_eval.c:35
static fr_dict_attr_t const * attr_cast_time_res_nsec
Definition xlat_eval.c:55
static xlat_action_t xlat_eval_one_letter(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, char letter)
One letter expansions.
Definition xlat_eval.c:770
static fr_dict_attr_t const * attr_cast_time_res_month
Definition xlat_eval.c:50
static fr_dict_attr_t const * attr_cast_time_res_usec
Definition xlat_eval.c:54
fr_dict_attr_t const * attr_expr_bool_enum
Definition xlat_eval.c:42
static fr_dict_attr_t const * attr_cast_time_res_csec
Definition xlat_eval.c:52
size_t xlat_action_table_len
Definition xlat_eval.c:82
static ssize_t _xlat_eval(TALLOC_CTX *ctx, char **out, size_t outlen, request_t *request, char const *fmt, xlat_escape_legacy_t escape, void const *escape_ctx)
Replace whatever in a string.
Definition xlat_eval.c:1730
static xlat_action_t xlat_process_arg_list(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, char const *name, xlat_arg_parser_t const *arg, xlat_exp_t const *node, unsigned int arg_num)
Process an individual xlat argument value box group.
Definition xlat_eval.c:338
static fr_dict_autoload_t xlat_eval_dict[]
Definition xlat_eval.c:37
static fr_dict_attr_t const * attr_cast_time_res_msec
Definition xlat_eval.c:53
fr_dict_attr_t const * attr_cast_base
Definition xlat_eval.c:43
fr_value_box_list_t list
Definition xlat_eval.c:958
ssize_t xlat_eval(char *out, size_t outlen, request_t *request, char const *fmt, xlat_escape_legacy_t escape, void const *escape_ctx)
Definition xlat_eval.c:1779
xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_t const **child, request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in)
Converts xlat nodes to value boxes.
Definition xlat_eval.c:1300
int xlat_flatten_to_argv(TALLOC_CTX *ctx, xlat_exp_head_t ***argv, xlat_exp_head_t *head)
Turn am xlat list into an argv[] array, and nuke the input list.
Definition xlat_eval.c:1818
static fr_dict_attr_autoload_t xlat_eval_dict_attr[]
Definition xlat_eval.c:57
static xlat_action_t xlat_process_args(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, xlat_exp_t const *node)
Process list of boxed values provided as input to an xlat.
Definition xlat_eval.c:563
static bool xlat_process_return(request_t *request, xlat_t const *func, fr_value_box_list_t const *returned, fr_value_box_t *pos)
Validate that the return values from an xlat function match what it registered.
Definition xlat_eval.c:722
void xlat_eval_free(void)
Definition xlat_eval.c:1949
static int xlat_arg_stringify(request_t *request, xlat_arg_parser_t const *arg, xlat_exp_t const *node, fr_value_box_t *vb)
Definition xlat_eval.c:273
int xlat_eval_walk(xlat_exp_head_t *head, xlat_walker_t walker, xlat_type_t type, void *uctx)
Walk over all xlat nodes (depth first) in a xlat expansion, calling a callback.
Definition xlat_eval.c:1860
static fr_dict_attr_t const * attr_cast_time_res_sec
Definition xlat_eval.c:45
static xlat_action_t xlat_null_resume(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
Definition xlat_eval.c:995
ssize_t xlat_aeval(TALLOC_CTX *ctx, char **out, request_t *request, char const *fmt, xlat_escape_legacy_t escape, void const *escape_ctx)
Definition xlat_eval.c:1795
static fr_dict_attr_t const * attr_cast_time_res_day
Definition xlat_eval.c:48
static ssize_t _xlat_eval_compiled(TALLOC_CTX *ctx, char **out, size_t outlen, request_t *request, xlat_exp_head_t const *head, xlat_escape_legacy_t escape, void const *escape_ctx)
Replace whatever in a string.
Definition xlat_eval.c:1677
ssize_t xlat_aeval_compiled(TALLOC_CTX *ctx, char **out, request_t *request, xlat_exp_head_t const *xlat, xlat_escape_legacy_t escape, void const *escape_ctx)
Definition xlat_eval.c:1804
static int xlat_sync_stringify(TALLOC_CTX *ctx, request_t *request, xlat_exp_head_t const *head, fr_value_box_list_t *list, xlat_escape_legacy_t escape, void const *escape_ctx)
Definition xlat_eval.c:1521
static void xlat_debug_log_list_result(request_t *request, xlat_exp_t const *node, fr_value_box_list_t const *result)
Output the list result of an expansion.
Definition xlat_eval.c:249
static fr_dict_attr_t const * attr_cast_time_res_min
Definition xlat_eval.c:46
static ssize_t xlat_eval_sync(TALLOC_CTX *ctx, char **out, request_t *request, xlat_exp_head_t const *const head, xlat_escape_legacy_t escape, void const *escape_ctx)
Definition xlat_eval.c:1599
static xlat_action_t xlat_exec_resume(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
Definition xlat_eval.c:961
static fr_dict_attr_t const * attr_cast_time_res_hour
Definition xlat_eval.c:47
static int instance_count
Definition xlat_eval.c:33
#define XLAT_DEBUG(...)
Definition xlat_expr.c:38
char const * name
Name of xlat function.
Definition xlat_priv.h:64
xlat_flags_t flags
Flags that control resolution and evaluation.
Definition xlat_priv.h:154
fr_type_t return_type
Function is guaranteed to return one or more boxes of this type.
Definition xlat_priv.h:101
static xlat_exp_t * xlat_exp_next(xlat_exp_head_t const *head, xlat_exp_t const *node)
Definition xlat_priv.h:246
xlat_func_t func
async xlat function (async unsafe).
Definition xlat_priv.h:65
int(* xlat_walker_t)(xlat_exp_t *exp, void *uctx)
Walker callback for xlat_walk()
Definition xlat_priv.h:267
fr_token_t quote
Type of quoting around XLAT_GROUP types.
Definition xlat_priv.h:152
xlat_type_t
Definition xlat_priv.h:106
@ XLAT_ONE_LETTER
Special "one-letter" expansion.
Definition xlat_priv.h:109
@ XLAT_BOX
fr_value_box_t
Definition xlat_priv.h:108
@ XLAT_TMPL
xlat attribute
Definition xlat_priv.h:112
@ XLAT_FUNC
xlat module
Definition xlat_priv.h:110
@ XLAT_GROUP
encapsulated string of xlats
Definition xlat_priv.h:116
@ XLAT_FUNC_UNRESOLVED
func needs resolution during pass2.
Definition xlat_priv.h:111
@ XLAT_INVALID
Bad expansion.
Definition xlat_priv.h:107
xlat_arg_parser_t const * args
Definition of args consumed.
Definition xlat_priv.h:94
char const *_CONST fmt
The original format string (a talloced buffer).
Definition xlat_priv.h:151
xlat_type_t _CONST type
type of this expansion.
Definition xlat_priv.h:155
fr_value_box_safe_for_t return_safe_for
Escaped value to set in output boxes.
Definition xlat_priv.h:100
#define xlat_exp_foreach(_list_head, _iter)
Iterate over the contents of a list, only one level.
Definition xlat_priv.h:222
static xlat_exp_t * xlat_exp_head(xlat_exp_head_t const *head)
Definition xlat_priv.h:209
An xlat expansion node.
Definition xlat_priv.h:148