The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 91ac371a2266df042c545e2df2bd04011b3e0afe $
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  */
27 RCSID("$Id: 91ac371a2266df042c545e2df2bd04011b3e0afe $")
28 
29 #include <freeradius-devel/server/base.h>
30 #include <freeradius-devel/unlang/xlat.h>
31 #include <freeradius-devel/unlang/xlat_priv.h>
32 #include <freeradius-devel/util/debug.h>
33 #include <freeradius-devel/util/types.h>
34 #include <freeradius-devel/util/sbuff.h>
35 #include <freeradius-devel/util/value.h>
36 
37 #include <freeradius-devel/unlang/unlang_priv.h> /* Remove when everything uses new xlat API */
38 
39 
40 static int instance_count = 0;
41 
42 static fr_dict_t const *dict_freeradius;
43 static fr_dict_t const *dict_radius;
44 
46  { .out = &dict_freeradius, .proto = "freeradius" },
47  { .out = &dict_radius, .proto = "radius" },
48  { NULL }
49 };
50 
51 fr_dict_attr_t const *attr_expr_bool_enum; /* xlat_expr.c */
52 fr_dict_attr_t const *attr_cast_base; /* xlat_expr.c */
53 
55  { .out = &attr_expr_bool_enum, .name = "Expr-Bool-Enum", .type = FR_TYPE_BOOL, .dict = &dict_freeradius },
56  { .out = &attr_cast_base, .name = "Cast-Base", .type = FR_TYPE_UINT8, .dict = &dict_freeradius },
57  { NULL }
58 };
59 
61  { L("done"), XLAT_ACTION_DONE },
62  { L("fail"), XLAT_ACTION_FAIL },
63  { L("push-child"), XLAT_ACTION_PUSH_CHILD },
64  { L("yield"), XLAT_ACTION_YIELD }
65 };
67 
68 static ssize_t xlat_eval_sync(TALLOC_CTX *ctx, char **out, request_t *request, xlat_exp_head_t const * const head,
69  xlat_escape_legacy_t escape, void const *escape_ctx);
70 
71 /** Reconstruct the original expansion string from an xlat tree
72  *
73  * @param[in] out sbuff to print result in.
74  * @param[in] node in the tree to start printing.
75  * @return
76  * - The original expansion string on success.
77  * - NULL on error.
78  */
80 {
81  switch (node->type) {
82  case XLAT_BOX:
83  case XLAT_GROUP:
84  fr_assert(node->fmt != NULL);
85  return fr_sbuff_in_strcpy(out, node->fmt);
86 
87  case XLAT_ONE_LETTER:
88  fr_assert(node->fmt != NULL);
89  return fr_sbuff_in_sprintf(out, "%%%s", node->fmt);
90 
91  case XLAT_TMPL:
92  fr_assert(node->fmt != NULL);
93  if (tmpl_is_attr(node->vpt) && (node->fmt[0] == '&')) {
94  return fr_sbuff_in_strcpy(out, node->fmt);
95  } else {
96  return fr_sbuff_in_sprintf(out, "%%{%s}", node->fmt);
97  }
98 
99  case XLAT_VIRTUAL:
100  return fr_sbuff_in_sprintf(out, "%%{%s}", node->call.func->name);
101 
102 #ifdef HAVE_REGEX
103  case XLAT_REGEX:
104  return fr_sbuff_in_sprintf(out, "%%{%u}", node->regex_index);
105 #endif
106 
107  case XLAT_FUNC:
108  {
109  bool first_done = false;
110  fr_sbuff_t our_out;
111  fr_slen_t slen;
112 
113  /*
114  * No arguments, just print an empty function.
115  */
116  if (!xlat_exp_head(node->call.args)) return fr_sbuff_in_sprintf(out, "%%%s()", node->call.func->name);
117 
118  our_out = FR_SBUFF(out);
119  FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%%%s(", node->call.func->name);
120 
121  xlat_exp_foreach(node->call.args, arg) {
122  if ((first_done) && (node->call.func->input_type == XLAT_INPUT_ARGS)) {
123  FR_SBUFF_IN_CHAR_RETURN(&our_out, ',');
124  }
125 
126  slen = xlat_fmt_print(&our_out, arg);
127  if (slen < 0) return slen - fr_sbuff_used(&our_out);
128 
129  first_done = true;
130  }
131 
132  FR_SBUFF_IN_CHAR_RETURN(&our_out, ')');
133  return fr_sbuff_set(out, &our_out);
134  }
135 
136  default:
137  return 0;
138  }
139 }
140 
141 /** Output what we're currently expanding
142  *
143  * @param[in] request The current request.
144  * @param[in] node Being processed.
145  * @param[in] args from previous expansion.
146  * @param[in] line Unused
147  */
148 static inline void xlat_debug_log_expansion(request_t *request, xlat_exp_t const *node, fr_value_box_list_t const *args, UNUSED int line)
149 {
150  if (node->flags.constant) return;
151 
152  if (!RDEBUG_ENABLED2) return;
153 
154  /*
155  * Because it's difficult to keep track of what
156  * the function was actually called with,
157  * we print the concatenated arguments list as
158  * well as the original fmt string.
159  */
160  if ((node->type == XLAT_FUNC) && !xlat_is_literal(node->call.args)) {
161  RDEBUG2("| %%%s(%pM)", node->call.func->name, args);
162  } else {
163  fr_sbuff_t *agg;
164 
165  FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 1024, SIZE_MAX);
166 
167  if (xlat_fmt_print(agg, node) < 0) {
168  RERROR("Failed printing expansion");
169  return;
170  }
171  RDEBUG2("| %s", fr_sbuff_start(agg)); /* print line number here for debugging */
172  }
173 }
174 
175 /** Output the list result of an expansion
176  *
177  * @param[in] request The current request.
178  * @param[in] node which was expanded.
179  * @param[in] result of the expansion.
180  */
181 static inline void xlat_debug_log_list_result(request_t *request, xlat_exp_t const *node, fr_value_box_list_t const *result)
182 {
183  if (node->flags.constant) return;
184 
185  if (!RDEBUG_ENABLED2) return;
186 
187  RDEBUG2("| --> %pM", result);
188 }
189 
190 /** Output the result of an expansion
191  *
192  * @param[in] request The current request.
193  * @param[in] node which was expanded.
194  * @param[in] result of the expansion.
195  */
196 static inline void xlat_debug_log_result(request_t *request, xlat_exp_t const *node, fr_value_box_t const *result)
197 {
198  if (node->flags.constant) return;
199 
200  if (!RDEBUG_ENABLED2) return;
201 
202  RDEBUG2("| --> %pV", result);
203 }
204 
205 /** Process an individual xlat argument value box group
206  *
207  * @param[in] ctx to allocate any additional buffers in
208  * @param[in,out] list of value boxes representing one argument
209  * @param[in] request currently being processed
210  * @param[in] name of the function being called
211  * @param[in] arg specification of current argument
212  * @param[in] arg_num number of current argument in the argument specifications
213  * @return
214  * - XLAT_ACTION_DONE on success.
215  * - XLAT_ACTION_FAIL on failure.
216  */
217 static xlat_action_t xlat_process_arg_list(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request,
218  char const *name, xlat_arg_parser_t const *arg, unsigned int arg_num)
219 {
220  fr_value_box_t *vb;
221 
222 #define ESCAPE(_arg, _vb, _arg_num) \
223 do { \
224  if ((_arg)->func && (!(_vb)->safe_for || !fr_value_box_is_safe_for((_vb), (_arg)->safe_for) || (_arg)->always_escape)) { \
225  if ((_arg)->func(request, _vb, (_arg)->uctx) < 0) { \
226  RPEDEBUG("Function \"%s\" failed escaping argument %u", name, _arg_num); \
227  return XLAT_ACTION_FAIL; \
228  } \
229  fr_value_box_mark_safe_for((_vb), (_arg)->safe_for); \
230  } \
231 } while (0)
232 
233  if (fr_value_box_list_empty(list)) {
234  if (arg->required) {
235  REDEBUG("Function \"%s\" is missing required argument %u", name, arg_num);
236  return XLAT_ACTION_FAIL;
237  }
238  return XLAT_ACTION_DONE;
239  }
240 
241  vb = fr_value_box_list_head(list);
242 
243  /*
244  * Concatenate child boxes, casting to desired type,
245  * then replace group vb with first child vb
246  */
247  if (arg->concat) {
248  if (arg->func) {
249  do ESCAPE(arg, vb, arg_num); while ((vb = fr_value_box_list_next(list, vb)));
250 
251  vb = fr_value_box_list_head(list); /* Reset */
252  }
253 
255  vb, list, arg->type,
257  SIZE_MAX) < 0) {
258  RPEDEBUG("Function \"%s\" failed concatenating arguments to type %s", name, fr_type_to_str(arg->type));
259  return XLAT_ACTION_FAIL;
260  }
261  fr_assert(fr_value_box_list_num_elements(list) <= 1);
262 
263  return XLAT_ACTION_DONE;
264  }
265 
266  /*
267  * Only a single child box is valid here. Check there is
268  * just one, cast to the correct type
269  */
270  if (arg->single) {
271  if (fr_value_box_list_num_elements(list) > 1) {
272  RPEDEBUG("Function \"%s\" was provided an incorrect number of values at argument %u, "
273  "expected %s got %u",
274  name, arg_num,
275  arg->required ? "0-1" : "1",
276  fr_value_box_list_num_elements(list));
277  return XLAT_ACTION_FAIL;
278  }
279 
280  ESCAPE(arg, vb, arg_num);
281 
282  if ((arg->type != FR_TYPE_VOID) && (vb->type != arg->type)) {
283  cast_error:
284  if (fr_value_box_cast_in_place(ctx, vb,
285  arg->type, NULL) < 0) {
286  RPEDEBUG("Function \"%s\" failed to cast argument %u to type %s", name, arg_num, fr_type_to_str(arg->type));
287  return XLAT_ACTION_FAIL;
288  }
289  }
290 
291  return XLAT_ACTION_DONE;
292  }
293 
294  /*
295  * We're neither concatenating nor do we only expect a single value,
296  * cast all child values to the required type.
297  */
298  if (arg->type != FR_TYPE_VOID) {
299  do {
300  ESCAPE(arg, vb, arg_num);
301  if (vb->type == arg->type) continue;
302  if (fr_value_box_cast_in_place(ctx, vb,
303  arg->type, NULL) < 0) goto cast_error;
304  } while ((vb = fr_value_box_list_next(list, vb)));
305 
306  /*
307  * If it's not a void type we still need to escape the values
308  */
309  } else if (arg->func) {
310  do ESCAPE(arg, vb, arg_num); while ((vb = fr_value_box_list_next(list, vb)));
311  }
312 
313 #undef ESCAPE
314 
315  return XLAT_ACTION_DONE;
316 }
317 
318 
319 /** Process list of boxed values provided as input to an xlat
320  *
321  * Ensures that the value boxes passed to an xlat function match the
322  * requirements listed in its "args", and escapes any tainted boxes
323  * using the specified escaping routine.
324  *
325  * @param[in] ctx in which to allocate any buffers.
326  * @param[in,out] list value boxes provided as input.
327  * List will be modified in accordance to rules
328  * provided in the args array.
329  * @param[in] request being processed.
330  * @param[in] func to call
331  */
332 static inline CC_HINT(always_inline)
333 xlat_action_t xlat_process_args(TALLOC_CTX *ctx, fr_value_box_list_t *list,
334  request_t *request, xlat_t const *func)
335 {
336  xlat_arg_parser_t const *arg_p = func->args;
337  xlat_action_t xa;
338  fr_value_box_t *vb, *next;
339 
340  /*
341  * No args registered for this xlat
342  */
343  if (!func->args) return XLAT_ACTION_DONE;
344 
345  /*
346  * xlat needs no input processing just return.
347  */
348  switch (func->input_type) {
350  return XLAT_ACTION_DONE;
351 
352  /*
353  * xlat takes all input as a single vb.
354  */
355  case XLAT_INPUT_MONO:
356  case XLAT_INPUT_ARGS:
357  vb = fr_value_box_list_head(list);
358  while (arg_p->type != FR_TYPE_NULL) {
359  /*
360  * Separate check to see if the group
361  * box is there. Check in
362  * xlat_process_arg_list verifies it
363  * has a value.
364  */
365  if (!vb) {
366  if (arg_p->required) {
367  missing:
368  REDEBUG("Function \"%s\" is missing required argument %u",
369  func->name, (unsigned int)((arg_p - func->args) + 1));
370  return XLAT_ACTION_FAIL;
371  }
372 
373  /*
374  * The argument isn't required. Just omit it. xlat_func_args_set() enforces
375  * that optional arguments are at the end of the argument list.
376  */
377  return XLAT_ACTION_DONE;
378  }
379 
380  /*
381  * Everything in the top level list should be
382  * groups
383  */
384  if (!fr_cond_assert(vb->type == FR_TYPE_GROUP)) return XLAT_ACTION_FAIL;
385 
386  /*
387  * pre-advance, in case the vb is replaced
388  * during processing.
389  */
390  next = fr_value_box_list_next(list, vb);
391  xa = xlat_process_arg_list(ctx, &vb->vb_group, request, func->name, arg_p,
392  (unsigned int)((arg_p - func->args) + 1));
393  if (xa != XLAT_ACTION_DONE) return xa;
394 
395  /*
396  * This argument doesn't exist. That might be OK, or it may be a fatal error.
397  */
398  if (fr_value_box_list_empty(&vb->vb_group)) {
399  /*
400  * Variadic rules deal with empty boxes differently...
401  */
402  switch (arg_p->variadic) {
404  fr_value_box_list_talloc_free_head(list);
405  continue;
406 
408  goto empty_ok;
409 
411  break;
412  }
413 
414  /*
415  * Empty groups for optional arguments are OK, we can just stop processing the list.
416  */
417  if (!arg_p->required) {
418  /*
419  * If the caller doesn't care about the type, then we leave the
420  * empty group there.
421  */
422  if (arg_p->type == FR_TYPE_VOID) goto do_next;
423 
424  /*
425  * The caller does care about the type, and we don't have any
426  * matching data. Omit this argument, and all arguments after it.
427  *
428  * i.e. if the caller has 3 optional arguments, all
429  * FR_TYPE_UINT8, and the first one is missing, then we MUST
430  * either supply boxes all of FR_TYPE_UINT8, OR we supply nothing.
431  *
432  * We can't supply a box of any other type, because the caller
433  * has declared that it wants FR_TYPE_UINT8, and is naively
434  * accessing the box as vb_uint8, hoping that it's being passed
435  * the right thing.
436  */
437  fr_value_box_list_talloc_free_head(list);
438  break;
439  }
440 
441  /*
442  * If the caller is expecting a particular type, then getting nothing is
443  * an error.
444  *
445  * If the caller manually checks the input type, then we can leave it as
446  * an empty group.
447  */
448  if (arg_p->type != FR_TYPE_VOID) goto missing;
449  }
450 
451  empty_ok:
452  /*
453  * In some cases we replace the current argument with the head of the group.
454  *
455  * xlat_process_arg_list() has already done concatenations for us.
456  */
457  if (arg_p->single || arg_p->concat) {
458  fr_value_box_t *head = fr_value_box_list_pop_head(&vb->vb_group);
459 
460  /*
461  * If we're meant to be smashing the argument
462  * to a single box, but the group was empty,
463  * add a null box instead so ordering is maintained
464  * for subsequent boxes.
465  */
466  if (!head) head = fr_value_box_alloc_null(ctx);
467  fr_value_box_list_replace(list, vb, head);
468  talloc_free(vb);
469  }
470 
471  do_next:
472  if (arg_p->variadic) {
473  if (!next) break;
474  } else {
475  arg_p++;
476  }
477  vb = next;
478  }
479  break;
480  }
481 
482  return XLAT_ACTION_DONE;
483 }
484 
485 /** Validate that the return values from an xlat function match what it registered
486  *
487  * @param[in] request The current request.
488  * @param[in] func that was called.
489  * @param[in] returned the output list of the function.
490  * @param[in] pos current position in the output list.
491  * @return
492  * - true - If return values were correct.
493  * - false - If the return values were incorrect.
494  */
495 static inline CC_HINT(nonnull(1,2,3))
496 bool xlat_process_return(request_t *request, xlat_t const *func, fr_value_box_list_t const *returned, fr_value_box_t *pos)
497 {
498  unsigned int count = 0;
499 
500  /*
501  * Nothing to validate. We don't yet enforce that functions
502  * must return at least one instance of their type.
503  */
504  if (!pos || fr_type_is_void(func->return_type)) return true;
505 
506  if (fr_type_is_null(func->return_type)) {
507  /* Dynamic expansion to get the right name */
508  REDEBUG("%s return type registered as %s, but %s expansion produced data",
509  func->name, func->name, fr_type_to_str(func->return_type));
510 
511  /* We are not forgiving for debug builds */
512  fr_assert_fail("Treating invalid return type as fatal");
513 
514  return false;
515  }
516 
517  do {
518  if (pos->type != func->return_type) {
519  REDEBUG("%s returned invalid result type at index %u. Expected type %s, got type %s",
520  func->name, count, fr_type_to_str(func->return_type), fr_type_to_str(pos->type));
521 
522  /* We are not forgiving for debug builds */
523  fr_assert_fail("Treating invalid return type as fatal");
524  }
525  fr_value_box_mark_safe_for(pos, func->return_safe_for); /* Always set this */
526  count++;
527  } while ((pos = fr_value_box_list_next(returned, pos)));
528 
529  return true;
530 }
531 
532 /** One letter expansions
533  *
534  * @param[in] ctx to allocate boxed value, and buffers in.
535  * @param[out] out Where to write the boxed value.
536  * @param[in] request The current request.
537  * @param[in] letter to expand.
538  * @return
539  * - #XLAT_ACTION_FAIL on memory allocation errors.
540  * - #XLAT_ACTION_DONE if we're done processing this node.
541  *
542  */
543 static inline CC_HINT(always_inline)
544 xlat_action_t xlat_eval_one_letter(TALLOC_CTX *ctx, fr_value_box_list_t *out,
545  request_t *request, char letter)
546 {
547 
548  char buffer[64];
549  struct tm ts;
550  time_t now;
552 
553  now = fr_time_to_sec(request->packet->timestamp);
554 
555  switch (letter) {
556  case '%':
558  if (fr_value_box_strdup(value, value, NULL, "%", false) < 0) return XLAT_ACTION_FAIL;
559  break;
560 
561  /*
562  * RADIUS request values
563  */
564 
565  case 'I': /* Request ID */
567  value->datum.uint32 = request->packet->id;
568  break;
569 
570  case 'n': /* Request number */
572  value->datum.uint64 = request->number;
573  break;
574 
575  case 's': /* First request in this sequence */
577  value->datum.uint64 = request->seq_start;
578  break;
579 
580  /*
581  * Current time
582  */
583 
584  case 'c': /* Current epoch time seconds */
585  /*
586  * @todo - leave this as FR_TYPE_DATE, but add an enumv which changes the scale to
587  * seconds?
588  */
590  value->datum.uint64 = (uint64_t)fr_time_to_sec(fr_time());
591  break;
592 
593  case 'C': /* Current epoch time microsecond component */
594  /*
595  * @todo - we probably should remove this now that we have FR_TYPE_DATE with scaling.
596  */
598  value->datum.uint64 = (uint64_t)fr_time_to_usec(fr_time()) % 1000000;
599  break;
600 
601  /*
602  * Time of the current request
603  */
604 
605  case 'd': /* Request day */
606  if (!localtime_r(&now, &ts)) {
607  error:
608  REDEBUG("Failed converting packet timestamp to localtime: %s", fr_syserror(errno));
609  return XLAT_ACTION_FAIL;
610  }
611 
612  MEM(value = fr_value_box_alloc(ctx, FR_TYPE_UINT8, NULL));
613  value->datum.uint8 = ts.tm_mday;
614  break;
615 
616  case 'D': /* Request date */
617  if (!localtime_r(&now, &ts)) goto error;
618 
619  strftime(buffer, sizeof(buffer), "%Y%m%d", &ts);
620 
622  if (fr_value_box_strdup(value, value, NULL, buffer, false) < 0) goto error;
623  break;
624 
625  case 'e': /* Request second */
626  if (!localtime_r(&now, &ts)) goto error;
627 
628  MEM(value = fr_value_box_alloc(ctx, FR_TYPE_UINT8, NULL));
629  value->datum.uint8 = ts.tm_sec;
630  break;
631 
632  case 'G': /* Request minute */
633  if (!localtime_r(&now, &ts)) goto error;
634 
635  MEM(value = fr_value_box_alloc(ctx, FR_TYPE_UINT8, NULL));
636  value->datum.uint8 = ts.tm_min;
637  break;
638 
639  case 'H': /* Request hour */
640  if (!localtime_r(&now, &ts)) goto error;
641 
642  MEM(value = fr_value_box_alloc(ctx, FR_TYPE_UINT8, NULL));
643  value->datum.uint8 = ts.tm_hour;
644  break;
645 
646  case 'l': /* Request timestamp as seconds since the epoch */
647  /*
648  * @todo - leave this as FR_TYPE_DATE, but add an enumv which changes the scale to
649  * seconds?
650  */
652  value->datum.uint64 = (uint64_t ) now;
653  break;
654 
655  case 'm': /* Request month */
656  if (!localtime_r(&now, &ts)) goto error;
657 
658  MEM(value = fr_value_box_alloc(ctx, FR_TYPE_UINT8, NULL));
659  value->datum.uint8 = ts.tm_mon + 1;
660  break;
661 
662  case 'M': /* Request time microsecond component */
663  /*
664  * @todo - we probably should remove this now that we have FR_TYPE_DATE with scaling.
665  */
667  value->datum.uint32 = fr_time_to_msec(request->packet->timestamp) % 1000;
668  break;
669 
670  case 'S': /* Request timestamp in SQL format */
671  if (!localtime_r(&now, &ts)) goto error;
672 
673  strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &ts);
674 
676  if (fr_value_box_strdup(value, value, NULL, buffer, false) < 0) goto error;
677  break;
678 
679  case 't': /* Request timestamp in CTIME format */
680  {
681  char *p;
682 
683  CTIME_R(&now, buffer, sizeof(buffer));
684  p = strchr(buffer, '\n');
685  if (p) *p = '\0';
686 
688  if (fr_value_box_strdup(value, value, NULL, buffer, false) < 0) goto error;
689  }
690  break;
691 
692  case 'T': /* Request timestamp in ISO format */
693  {
694  int len = 0;
695 
696  if (!gmtime_r(&now, &ts)) goto error;
697 
698  if (!(len = strftime(buffer, sizeof(buffer) - 1, "%Y-%m-%dT%H:%M:%S", &ts))) {
699  REDEBUG("Failed converting packet timestamp to gmtime: Buffer full");
700  return XLAT_ACTION_FAIL;
701  }
702  strcat(buffer, ".");
703  len++;
704  snprintf(buffer + len, sizeof(buffer) - len, "%03i",
705  (int) fr_time_to_msec(request->packet->timestamp) % 1000);
706 
708  if (fr_value_box_strdup(value, value, NULL, buffer, false) < 0) goto error;
709  }
710  break;
711 
712  case 'Y': /* Request year */
713  if (!localtime_r(&now, &ts)) goto error;
714 
716 
717  value->datum.int16 = ts.tm_year + 1900;
718  break;
719 
720  default:
721  fr_assert_fail("%%%c is not a valid one letter expansion", letter);
722  return XLAT_ACTION_FAIL;
723  }
724 
725  fr_value_box_list_insert_tail(out, value);
726 
727  return XLAT_ACTION_DONE;
728 }
729 
730 typedef struct {
731  int status;
732  fr_value_box_list_t list;
734 
736  xlat_ctx_t const *xctx,
737  UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
738 {
739  xlat_exec_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_exec_rctx_t);
740 
741  if (rctx->status != 0) {
742  fr_strerror_printf("Program failed with status %d", rctx->status);
743  return XLAT_ACTION_FAIL;
744  }
745 
746  fr_value_box_list_move((fr_value_box_list_t *)out->dlist, &rctx->list);
747 
748  return XLAT_ACTION_DONE;
749 }
750 
751 
752 /** Signal an xlat function
753  *
754  * @param[in] signal function to call.
755  * @param[in] exp Xlat node that previously yielded.
756  * @param[in] request The current request.
757  * @param[in] rctx Opaque (to us), resume ctx provided by the xlat function
758  * when it yielded.
759  * @param[in] action What the request should do (the type of signal).
760  */
761 void xlat_signal(xlat_func_signal_t signal, xlat_exp_t const *exp,
762  request_t *request, void *rctx, fr_signal_t action)
763 {
765 
766  signal(XLAT_CTX(exp->call.inst, t->data, t->mctx, NULL, rctx), request, action);
767 }
768 
770  UNUSED xlat_ctx_t const *xctx,
771  UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
772 {
773  return XLAT_ACTION_DONE;
774 }
775 
776 /** Call an xlat's resumption method
777  *
778  * @param[in] ctx to allocate value boxes in.
779  * @param[out] out a list of #fr_value_box_t to append to.
780  * @param[out] child to evaluate. If a child needs to be evaluated
781  * by the caller, we return XLAT_ACTION_PUSH_CHILD
782  * and place the child to be evaluated here.
783  * Once evaluation is complete, the caller
784  * should call us with the same #xlat_exp_t and the
785  * result of the nested evaluation in result.
786  * @param[in] request the current request.
787  * @param[in] head of the list to evaluate
788  * @param[in,out] in xlat node to evaluate. Advanced as we process
789  * additional #xlat_exp_t.
790  * @param[in] result Previously expanded arguments to this xlat function.
791  * @param[in] resume function to call.
792  * @param[in] rctx Opaque (to us), resume ctx provided by xlat function
793  * when it yielded.
794  */
796  xlat_exp_head_t const **child,
797  request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in,
798  fr_value_box_list_t *result, xlat_func_t resume, void *rctx)
799 {
800  xlat_action_t xa;
801  xlat_exp_t const *node = *in;
802 
803  /*
804  * It's important that callbacks leave the result list
805  * in a valid state, as it leads to all kinds of hard
806  * to debug problems if they free or change elements
807  * and don't remove them from the list.
808  */
809  VALUE_BOX_LIST_VERIFY(result);
810 
811  if (node->type != XLAT_FUNC) {
812  xa = resume(ctx, out, XLAT_CTX(NULL, NULL, NULL, NULL, rctx), request, result);
813  } else {
815  t = xlat_thread_instance_find(node);
816  xa = resume(ctx, out, XLAT_CTX(node->call.inst->data, t->data, t->mctx, NULL, rctx), request, result);
817  VALUE_BOX_LIST_VERIFY(result);
818 
819  RDEBUG2("| %%%s(...)", node->call.func->name);
820  }
821 
822  switch (xa) {
823  case XLAT_ACTION_YIELD:
824  RDEBUG2("| (YIELD)");
825  return xa;
826 
827  case XLAT_ACTION_DONE:
828  if (unlang_xlat_yield(request, xlat_null_resume, NULL, 0, NULL) != XLAT_ACTION_YIELD) return XLAT_ACTION_FAIL;
829 
830  fr_dcursor_next(out); /* Wind to the start of this functions output */
831  if (node->call.func) {
832  RDEBUG2("| --> %pV", fr_dcursor_current(out));
833  if (!xlat_process_return(request, node->call.func, (fr_value_box_list_t *)out->dlist,
835  }
836 
837  /*
838  * It's easier if we get xlat_frame_eval to continue evaluating the frame.
839  */
840  *in = xlat_exp_next(head, *in); /* advance */
841  return xlat_frame_eval(ctx, out, child, request, head, in);
842 
845  case XLAT_ACTION_FAIL:
846  break;
847  }
848 
849  return xa;
850 }
851 
852 /** Process the result of a previous nested expansion
853  *
854  * @param[in] ctx to allocate value boxes in.
855  * @param[out] out a list of #fr_value_box_t to append to.
856  * @param[out] child to evaluate. If a child needs to be evaluated
857  * by the caller, we return XLAT_ACTION_PUSH_CHILD
858  * and place the child to be evaluated here.
859  * Once evaluation is complete, the caller
860  * should call us with the same #xlat_exp_t and the
861  * result of the nested evaluation in result.
862  * @param[in] request the current request.
863  * @param[in] head of the list to evaluate
864  * @param[in,out] in xlat node to evaluate. Advanced as we process
865  * additional #xlat_exp_t.
866  * @param[in] env_data Expanded call env.
867  * @param[in] result of a previous nested evaluation.
868  */
870  xlat_exp_head_t const **child,
871  request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in,
872  void *env_data, fr_value_box_list_t *result)
873 {
874  xlat_exp_t const *node = *in;
875 
876  fr_dcursor_tail(out); /* Needed for reentrant behaviour and debugging */
877 
878  switch (node->type) {
879  case XLAT_FUNC:
880  {
881  xlat_action_t xa;
883  fr_value_box_list_t result_copy;
884 
885  t = xlat_thread_instance_find(node);
886  fr_assert(t);
887 
888  XLAT_DEBUG("** [%i] %s(func-async) - %%%s(%pM)",
889  unlang_interpret_stack_depth(request), __FUNCTION__,
890  node->fmt, result);
891 
892  VALUE_BOX_LIST_VERIFY(result);
893 
894  /*
895  * Always need to init and free the
896  * copy list as debug level could change
897  * when the xlat function executes.
898  */
899  fr_value_box_list_init(&result_copy);
900 
901  /*
902  * Need to copy the input list in case
903  * the async function mucks with it.
904  */
906  xa = xlat_process_args(ctx, result, request, node->call.func);
907  if (xa == XLAT_ACTION_FAIL) {
908  fr_value_box_list_talloc_free(&result_copy);
909  return xa;
910  }
911 
912  VALUE_BOX_LIST_VERIFY(result);
913  xa = node->call.func->func(ctx, out,
914  XLAT_CTX(node->call.inst->data, t->data, t->mctx, env_data, NULL),
915  request, result);
916  VALUE_BOX_LIST_VERIFY(result);
917 
918  if (RDEBUG_ENABLED2) {
919  REXDENT();
920  xlat_debug_log_expansion(request, *in, &result_copy, __LINE__);
921  RINDENT();
922  }
923  fr_value_box_list_talloc_free(&result_copy);
924 
925  switch (xa) {
926  case XLAT_ACTION_FAIL:
927  return xa;
928 
930  RDEBUG3("| -- CHILD");
931  return xa;
932 
934  RDEBUG3("| -- UNLANG");
935  return xa;
936 
937  case XLAT_ACTION_YIELD:
938  RDEBUG3("| -- YIELD");
939  return xa;
940 
941  case XLAT_ACTION_DONE: /* Process the result */
943  REXDENT();
945  if (!xlat_process_return(request, node->call.func,
946  (fr_value_box_list_t *)out->dlist,
948  RINDENT();
949  break;
950  }
951  }
952  break;
953 
954  case XLAT_GROUP:
955  {
956  fr_value_box_t *arg;
957 
958  /*
959  * We'd like to do indent / exdent for groups, but that also involves fixing all of the
960  * error paths. Which we won't do right now.
961  */
962  XLAT_DEBUG("** [%i] %s(child) - continuing %%{%s ...}", unlang_interpret_stack_depth(request), __FUNCTION__,
963  node->fmt);
964 
965  MEM(arg = fr_value_box_alloc(ctx, FR_TYPE_GROUP, NULL));
966 
967  if (!fr_value_box_list_empty(result)) {
968  VALUE_BOX_LIST_VERIFY(result);
969  fr_value_box_list_move(&arg->vb_group, result);
970  }
971 
972 // xlat_debug_log_expansion(request, *in, NULL, __LINE__);
973 // xlat_debug_log_result(request, *in, arg);
974 
975  VALUE_BOX_VERIFY(arg);
976 
977  fr_dcursor_insert(out, arg);
978  }
979  break;
980 
981  case XLAT_TMPL:
982  fr_assert(tmpl_is_exec(node->vpt));
983 
984  if (tmpl_eval_cast_in_place(result, request, node->vpt) < 0) {
985  fr_value_box_list_talloc_free(result);
986  return XLAT_ACTION_FAIL;
987  }
988 
989  /*
990  * First entry is the command to run. Subsequent entries are the options to pass to the
991  * command.
992  */
993  fr_value_box_list_move((fr_value_box_list_t *)out->dlist, result);
994  break;
995 
996  default:
997  fr_assert(0);
998  return XLAT_ACTION_FAIL;
999  }
1000 
1001  /*
1002  * It's easier if we get xlat_frame_eval to continue evaluating the frame.
1003  */
1004  *in = xlat_exp_next(head, *in); /* advance */
1005  return xlat_frame_eval(ctx, out, child, request, head, in);
1006 }
1007 
1008 /** Converts xlat nodes to value boxes
1009  *
1010  * Evaluates a single level of expansions.
1011  *
1012  * @param[in] ctx to allocate value boxes in.
1013  * @param[out] out a list of #fr_value_box_t to append to.
1014  * @param[out] child to evaluate. If a child needs to be evaluated
1015  * by the caller, we return XLAT_ACTION_PUSH_CHILD
1016  * and place the child to be evaluated here.
1017  * Once evaluation is complete, the caller
1018  * should call us with the same #xlat_exp_t and the
1019  * result of the nested evaluation in result.
1020  * @param[in] request the current request.
1021  * @param[in] head of the list to evaluate
1022  * @param[in,out] in xlat node to evaluate. Advanced as we process
1023  * additional #xlat_exp_t.
1024  * @return
1025  * - XLAT_ACTION_PUSH_CHILD if we need to evaluate a deeper level of nested.
1026  * child will be filled with the node that needs to be evaluated.
1027  * call #xlat_frame_eval_repeat on this node, once there are results
1028  * from the nested expansion.
1029  * - XLAT_ACTION_YIELD a resumption frame was pushed onto the stack by an
1030  * xlat function and we need to wait for the request to be resumed
1031  * before continuing.
1032  * - XLAT_ACTION_DONE we're done, pop the frame.
1033  * - XLAT_ACTION_FAIL an xlat module failed.
1034  */
1036  request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in)
1037 {
1039  xlat_exp_t const *node;
1040  fr_value_box_list_t result; /* tmp list so debug works correctly */
1042 
1043  fr_value_box_list_init(&result);
1044 
1045  *child = NULL;
1046 
1047  if (!*in) return XLAT_ACTION_DONE;
1048 
1049  XLAT_DEBUG("** [%i] %s >> entered", unlang_interpret_stack_depth(request), __FUNCTION__);
1050 
1051  for (node = *in; node; node = xlat_exp_next(head, node)) {
1052  *in = node; /* Update node in our caller */
1053  fr_dcursor_tail(out); /* Needed for debugging */
1054  VALUE_BOX_LIST_VERIFY((fr_value_box_list_t *)out->dlist);
1055 
1056  fr_assert(fr_value_box_list_num_elements(&result) == 0); /* Should all have been moved */
1057 
1058  switch (node->type) {
1059  case XLAT_BOX:
1060  XLAT_DEBUG("** [%i] %s(value_box) - %s", unlang_interpret_stack_depth(request), __FUNCTION__, node->fmt);
1061 
1062  /*
1063  * Empty boxes are only allowed if
1064  * they're the only node in the expansion.
1065  *
1066  * If they're found anywhere else the xlat
1067  * parser has an error.
1068  */
1069  fr_assert(((node == *in) && !xlat_exp_next(head, node)) || (talloc_array_length(node->fmt) > 1));
1070 
1071  /*
1072  * We unfortunately need to dup the buffer
1073  * because references aren't threadsafe.
1074  */
1076  if (fr_value_box_copy(value, value, &node->data) < 0) goto fail;
1078  continue;
1079 
1080  case XLAT_ONE_LETTER:
1081  XLAT_DEBUG("** [%i] %s(one-letter) - %%%s", unlang_interpret_stack_depth(request), __FUNCTION__,
1082  node->fmt);
1083 
1084  xlat_debug_log_expansion(request, node, NULL, __LINE__);
1085  if (xlat_eval_one_letter(ctx, &result, request, node->fmt[0]) == XLAT_ACTION_FAIL) {
1086  fail:
1087  fr_value_box_list_talloc_free(&result);
1088  xa = XLAT_ACTION_FAIL;
1089  goto finish;
1090  }
1091  xlat_debug_log_list_result(request, *in, &result);
1092  fr_value_box_list_move((fr_value_box_list_t *)out->dlist, &result);
1093  continue;
1094 
1095  case XLAT_TMPL:
1096  if (tmpl_is_data(node->vpt)) {
1097  XLAT_DEBUG("** [%i] %s(value) - %s", unlang_interpret_stack_depth(request), __FUNCTION__,
1098  node->vpt->name);
1099 
1100  MEM(value = fr_value_box_alloc(ctx, tmpl_value_type(node->vpt), NULL));
1101 
1102  fr_value_box_copy(value, value, tmpl_value(node->vpt)); /* Also dups taint */
1103  fr_value_box_list_insert_tail(&result, value);
1104 
1105  /*
1106  * Cast the results if necessary.
1107  */
1108  if (tmpl_eval_cast_in_place(&result, request, node->vpt) < 0) goto fail;
1109 
1110  fr_value_box_list_move((fr_value_box_list_t *)out->dlist, &result);
1111  continue;
1112 
1113  } else if (tmpl_is_attr(node->vpt)) {
1114  if (node->fmt[0] == '&') {
1115  XLAT_DEBUG("** [%i] %s(attribute) - %s", unlang_interpret_stack_depth(request), __FUNCTION__,
1116  node->fmt);
1117  } else {
1118  XLAT_DEBUG("** [%i] %s(attribute) - %%{%s}", unlang_interpret_stack_depth(request), __FUNCTION__,
1119  node->fmt);
1120  }
1121  xlat_debug_log_expansion(request, node, NULL, __LINE__);
1122 
1123  if (tmpl_eval_pair(ctx, &result, request, node->vpt) < 0) goto fail;
1124 
1125  } else if (tmpl_is_exec(node->vpt) || tmpl_is_xlat(node->vpt)) {
1126  xlat_exec_rctx_t *rctx;
1127 
1128  /*
1129  * Allocate and initialize the output context, with value-boxes, exec status, etc.
1130  */
1131  MEM(rctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), xlat_exec_rctx_t));
1132  fr_value_box_list_init(&rctx->list);
1133 
1134  xlat_debug_log_expansion(request, node, NULL, __LINE__);
1135 
1136  if (unlang_xlat_yield(request, xlat_exec_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto fail;
1137 
1138  if (unlang_tmpl_push(ctx, &rctx->list, request, node->vpt,
1140  false, &rctx->status)) < 0) goto fail;
1141 
1143  goto finish;
1144 
1145  } else {
1146 #ifdef NDEBUG
1147  xa = XLAT_ACTION_FAIL;
1148  goto finish;
1149 #endif
1150 
1151  /*
1152  * Either this should have been handled previously, or we need to write
1153  * code to deal with this case.
1154  */
1155  fr_assert(0);
1156  }
1157 
1158  xlat_debug_log_list_result(request, node, &result);
1159  fr_value_box_list_move((fr_value_box_list_t *)out->dlist, &result);
1160  continue;
1161 
1162  case XLAT_VIRTUAL:
1163  {
1164  XLAT_DEBUG("** [%i] %s(virtual) - %%{%s}", unlang_interpret_stack_depth(request), __FUNCTION__,
1165  node->fmt);
1166 
1167  xlat_debug_log_expansion(request, node, NULL, __LINE__);
1168  xa = node->call.func->func(ctx, out,
1169  XLAT_CTX(node->call.func->uctx, NULL, NULL, NULL, NULL),
1170  request, NULL);
1172 
1173  xlat_debug_log_result(request, node, fr_dcursor_current(out));
1174  }
1175  continue;
1176 
1177  case XLAT_FUNC:
1178  XLAT_DEBUG("** [%i] %s(func) - %%%s(...)", unlang_interpret_stack_depth(request), __FUNCTION__,
1179  node->fmt);
1180 
1181  /*
1182  * Hand back the child node to the caller
1183  * for evaluation.
1184  */
1185  if (xlat_exp_head(node->call.args)) {
1186  *child = node->call.args;
1188  goto finish;
1189  }
1190 
1191  /*
1192  * If there's no children we can just
1193  * call the function directly.
1194  */
1195  xa = xlat_frame_eval_repeat(ctx, out, child, request, head, in, NULL, &result);
1196  if (xa != XLAT_ACTION_DONE || (!*in)) goto finish;
1197  continue;
1198 
1199 #ifdef HAVE_REGEX
1200  case XLAT_REGEX:
1201  {
1202  char *str = NULL;
1203 
1204  XLAT_DEBUG("** [%i] %s(regex) - %%{%s}", unlang_interpret_stack_depth(request), __FUNCTION__,
1205  node->fmt);
1206 
1207  xlat_debug_log_expansion(request, node, NULL, __LINE__);
1209  if (regex_request_to_sub(ctx, &str, request, node->regex_index) < 0) {
1210  talloc_free(value);
1211  continue;
1212  }
1213  fr_value_box_bstrdup_buffer_shallow(NULL, value, NULL, str, false);
1214 
1215  xlat_debug_log_result(request, node, value);
1217  }
1218  continue;
1219 #endif
1220 
1221  case XLAT_GROUP:
1222  XLAT_DEBUG("** [%i] %s(child) - %%{%s ...}", unlang_interpret_stack_depth(request), __FUNCTION__,
1223  node->fmt);
1224  if (!node->group) return XLAT_ACTION_DONE;
1225 
1226  /*
1227  * Hand back the child node to the caller
1228  * for evaluation.
1229  */
1230  *child = node->group;
1232  goto finish;
1233 
1234  /*
1235  * Should have been fixed up during pass2
1236  */
1237  case XLAT_INVALID:
1238  case XLAT_FUNC_UNRESOLVED:
1240  fr_assert(0);
1241  return XLAT_ACTION_FAIL;
1242  }
1243  }
1244 
1245 finish:
1246  VALUE_BOX_LIST_VERIFY((fr_value_box_list_t *)out->dlist);
1247  XLAT_DEBUG("** [%i] %s << %s", unlang_interpret_stack_depth(request),
1248  __FUNCTION__, fr_table_str_by_value(xlat_action_table, xa, "<INVALID>"));
1249 
1250  return xa;
1251 }
1252 
1253 static ssize_t xlat_eval_sync(TALLOC_CTX *ctx, char **out, request_t *request, xlat_exp_head_t const * const head,
1254  xlat_escape_legacy_t escape, void const *escape_ctx)
1255 {
1256  fr_value_box_list_t result;
1257  bool success = false;
1258  TALLOC_CTX *pool = talloc_new(NULL);
1259  rlm_rcode_t rcode;
1260  char *str;
1261 
1262  XLAT_DEBUG("xlat_eval_sync");
1263 
1264  *out = NULL;
1265 
1266  fr_value_box_list_init(&result);
1267  /*
1268  * Use the unlang stack to evaluate
1269  * the async xlat up until the point
1270  * that it needs to yield.
1271  */
1272  if (unlang_xlat_push(pool, &success, &result, request, head, true) < 0) {
1273  talloc_free(pool);
1274  return -1;
1275  }
1276 
1277  rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request);
1278  switch (rcode) {
1279  default:
1280  break;
1281 
1282  case RLM_MODULE_REJECT:
1283  case RLM_MODULE_FAIL:
1284  eval_failed:
1285  talloc_free(pool);
1286  return -1;
1287  }
1288  if (!success) goto eval_failed;
1289 
1290  if (!fr_value_box_list_empty(&result)) {
1291  if (escape) {
1292  fr_value_box_t *vb = NULL;
1293 
1294  /*
1295  * For tainted boxes perform the requested escaping
1296  */
1297  while ((vb = fr_value_box_list_next(&result, vb))) {
1298  fr_value_box_entry_t entry;
1299  size_t len, real_len;
1300  char *escaped;
1301 
1302  if (!vb->tainted) continue;
1303 
1304  if (fr_value_box_cast_in_place(pool, vb, FR_TYPE_STRING, NULL) < 0) {
1305  RPEDEBUG("Failed casting result to string");
1306  error:
1307  talloc_free(pool);
1308  return -1;
1309  }
1310 
1311  len = vb->vb_length * 3;
1312  MEM(escaped = talloc_array(pool, char, len));
1313  real_len = escape(request, escaped, len, vb->vb_strvalue, UNCONST(void *, escape_ctx));
1314 
1315  entry = vb->entry;
1317  fr_value_box_bstrndup(vb, vb, NULL, escaped, real_len, false);
1318  vb->entry = entry;
1319 
1320  talloc_free(escaped);
1321  }
1322  }
1323 
1324  str = fr_value_box_list_aprint(ctx, &result, NULL, NULL);
1325  if (!str) {
1326  talloc_free(pool);
1327  goto error;
1328  }
1329  } else {
1330  str = talloc_typed_strdup(ctx, "");
1331  }
1332  talloc_free(pool); /* Memory should be in new ctx */
1333 
1334  *out = str;
1335 
1336  return talloc_array_length(str) - 1;
1337 }
1338 
1339 /** Replace %whatever in a string.
1340  *
1341  * See 'doc/unlang/xlat.adoc' for more information.
1342  *
1343  * @param[in] ctx to allocate expansion buffers in.
1344  * @param[out] out Where to write pointer to output buffer.
1345  * @param[in] outlen Size of out.
1346  * @param[in] request current request.
1347  * @param[in] head the xlat structure to expand
1348  * @param[in] escape function to escape final value e.g. SQL quoting.
1349  * @param[in] escape_ctx pointer to pass to escape function.
1350  * @return length of string written @bug should really have -1 for failure.
1351  */
1352 static ssize_t _xlat_eval_compiled(TALLOC_CTX *ctx, char **out, size_t outlen, request_t *request,
1353  xlat_exp_head_t const *head, xlat_escape_legacy_t escape, void const *escape_ctx)
1354 {
1355  char *buff;
1356  ssize_t slen;
1357 
1358  fr_assert(head != NULL);
1359 
1360  slen = xlat_eval_sync(ctx, &buff, request, head, escape, escape_ctx);
1361  if (slen < 0) {
1362  fr_assert(buff == NULL);
1363  if (*out) **out = '\0';
1364  return slen;
1365  }
1366 
1367  /*
1368  * If out doesn't point to an existing buffer
1369  * copy the pointer to our buffer over.
1370  */
1371  if (!*out) {
1372  *out = buff;
1373  return slen;
1374  }
1375 
1376  if ((size_t)slen >= outlen) {
1377  fr_strerror_const("Insufficient output buffer space");
1378  return -1;
1379  }
1380 
1381  /*
1382  * Otherwise copy the talloced buffer to the fixed one.
1383  */
1384  memcpy(*out, buff, slen);
1385  (*out)[slen] = '\0';
1386  talloc_free(buff);
1387 
1388  return slen;
1389 }
1390 
1391 /** Replace %whatever in a string.
1392  *
1393  * See 'doc/unlang/xlat.adoc' for more information.
1394  *
1395  * @param[in] ctx to allocate expansion buffers in.
1396  * @param[out] out Where to write pointer to output buffer.
1397  * @param[in] outlen Size of out.
1398  * @param[in] request current request.
1399  * @param[in] fmt string to expand.
1400  * @param[in] escape function to escape final value e.g. SQL quoting.
1401  * @param[in] escape_ctx pointer to pass to escape function.
1402  * @return length of string written @bug should really have -1 for failure.
1403  */
1404 static CC_HINT(nonnull (2, 4, 5))
1405 ssize_t _xlat_eval(TALLOC_CTX *ctx, char **out, size_t outlen, request_t *request, char const *fmt,
1406  xlat_escape_legacy_t escape, void const *escape_ctx)
1407 {
1408  ssize_t len;
1410 
1411  RINDENT();
1412 
1413  /*
1414  * Give better errors than the old code.
1415  */
1416  len = xlat_tokenize(ctx, &head,
1417  &FR_SBUFF_IN(fmt, strlen(fmt)),
1418  NULL,
1419  &(tmpl_rules_t){
1420  .attr = {
1421  .dict_def = request->dict,
1422  .list_def = request_attr_request,
1423  },
1424  .xlat = {
1425  .runtime_el = unlang_interpret_event_list(request),
1426  },
1427  .at_runtime = true,
1428  }, 0);
1429  if (len == 0) {
1430  if (*out) {
1431  **out = '\0';
1432  } else {
1433  *out = talloc_zero_array(ctx, char, 1);
1434  }
1435  REXDENT();
1436  return 0;
1437  }
1438 
1439  if (len < 0) {
1440  REMARKER(fmt, -(len), "%s", fr_strerror());
1441  if (*out) **out = '\0';
1442  REXDENT();
1443  return -1;
1444  }
1445 
1446  len = _xlat_eval_compiled(ctx, out, outlen, request, head, escape, escape_ctx);
1447  talloc_free(head);
1448 
1449  REXDENT();
1450 
1451  return len;
1452 }
1453 
1454 ssize_t xlat_eval(char *out, size_t outlen, request_t *request,
1455  char const *fmt, xlat_escape_legacy_t escape, void const *escape_ctx)
1456 {
1458 
1459  return _xlat_eval(request, &out, outlen, request, fmt, escape, escape_ctx);
1460 }
1461 
1462 ssize_t xlat_eval_compiled(char *out, size_t outlen, request_t *request,
1463  xlat_exp_head_t const *xlat, xlat_escape_legacy_t escape, void const *escape_ctx)
1464 {
1466 
1467  return _xlat_eval_compiled(request, &out, outlen, request, xlat, escape, escape_ctx);
1468 }
1469 
1470 ssize_t xlat_aeval(TALLOC_CTX *ctx, char **out, request_t *request, char const *fmt,
1471  xlat_escape_legacy_t escape, void const *escape_ctx)
1472 {
1474 
1475  *out = NULL;
1476  return _xlat_eval(ctx, out, 0, request, fmt, escape, escape_ctx);
1477 }
1478 
1479 ssize_t xlat_aeval_compiled(TALLOC_CTX *ctx, char **out, request_t *request,
1480  xlat_exp_head_t const *xlat, xlat_escape_legacy_t escape, void const *escape_ctx)
1481 {
1483 
1484  *out = NULL;
1485  return _xlat_eval_compiled(ctx, out, 0, request, xlat, escape, escape_ctx);
1486 }
1487 
1488 
1489 /** Synchronous compile xlat_tokenize_argv() into argv[] array.
1490  *
1491  * This is mostly for synchronous evaluation.
1492  *
1493  * @param ctx The talloc_ctx
1494  * @param[out] argv the argv array of resulting strings, size is argc + 1
1495  * @param request the request
1496  * @param head from xlat_tokenize_argv()
1497  * @param escape escape function
1498  * @param escape_ctx context for escape function
1499  * @return
1500  * - <=0 on error number indicates which argument caused the problem
1501  * - >0 on success which is argc to the corresponding argv
1502  */
1503 int xlat_aeval_compiled_argv(TALLOC_CTX *ctx, char ***argv, request_t *request,
1504  xlat_exp_head_t const *head, xlat_escape_legacy_t escape, void const *escape_ctx)
1505 {
1506  int i;
1507  ssize_t slen;
1508  char **my_argv;
1509  size_t count;
1510 
1511  count = 0;
1512  xlat_exp_foreach(head, node) {
1513  count++;
1514  }
1515 
1516  MEM(my_argv = talloc_zero_array(ctx, char *, count + 1));
1517  *argv = my_argv;
1518 
1520 
1521  i = 0;
1522  xlat_exp_foreach(head, node) {
1523  my_argv[i] = NULL;
1524 
1525  slen = _xlat_eval_compiled(my_argv, &my_argv[i], 0, request, node->group, escape, escape_ctx);
1526  if (slen < 0) return -i;
1527 
1528  i++;
1529  }
1530 
1531  return count;
1532 }
1533 
1534 /** Turn xlat_tokenize_argv() into an argv[] array, and nuke the input list.
1535  *
1536  * This is mostly for async use.
1537  */
1539 {
1540  int i;
1541  xlat_exp_head_t **my_argv;
1542  size_t count;
1543 
1544  count = 0;
1545  xlat_exp_foreach(head, node) {
1546  count++;
1547  }
1548 
1549  MEM(my_argv = talloc_zero_array(ctx, xlat_exp_head_t *, count + 1));
1550  *argv = my_argv;
1551 
1553 
1554  i = 0;
1555  xlat_exp_foreach(head, node) {
1556  fr_assert(node->type == XLAT_GROUP);
1557  my_argv[i++] = talloc_steal(my_argv, node->group);
1558  }
1559 
1560  fr_value_box_list_talloc_free((fr_value_box_list_t *)&head->dlist);
1561 
1562  return count;
1563 }
1564 
1565 /** Walk over all xlat nodes (depth first) in a xlat expansion, calling a callback
1566  *
1567  * @param[in] head to evaluate.
1568  * @param[in] walker callback to pass nodes to.
1569  * @param[in] type if > 0 a mask of types to call walker for.
1570  * @param[in] uctx to pass to walker.
1571  * @return
1572  * - 0 on success (walker always returned 0).
1573  * - <0 if walker returned <0.
1574  */
1576 {
1577  int ret;
1578 
1579  /*
1580  * Iterate over nodes at the same depth
1581  */
1582  xlat_exp_foreach(head, node) {
1583  switch (node->type){
1584  case XLAT_FUNC:
1585  /*
1586  * Evaluate the function's arguments
1587  * first, as they may get moved around
1588  * when the function is instantiated.
1589  */
1590  if (xlat_exp_head(node->call.args)) {
1591  ret = xlat_eval_walk(node->call.args, walker, type, uctx);
1592  if (ret < 0) return ret;
1593  }
1594 
1595  if (!type || (type & XLAT_FUNC)) {
1596  ret = walker(node, uctx);
1597  if (ret < 0) return ret;
1598  }
1599  break;
1600 
1601  case XLAT_FUNC_UNRESOLVED:
1602  if (xlat_exp_head(node->call.args)) {
1603  ret = xlat_eval_walk(node->call.args, walker, type, uctx);
1604  if (ret < 0) return ret;
1605  }
1606 
1607  if (!type || (type & XLAT_FUNC_UNRESOLVED)) {
1608  ret = walker(node, uctx);
1609  if (ret < 0) return ret;
1610  }
1611  break;
1612 
1613  case XLAT_GROUP:
1614  if (!type || (type & XLAT_GROUP)) {
1615  ret = walker(node, uctx);
1616  if (ret < 0) return ret;
1617  if (ret > 0) continue;
1618  }
1619 
1620  /*
1621  * Evaluate the child.
1622  */
1623  ret = xlat_eval_walk(node->group, walker, type, uctx);
1624  if (ret < 0) return ret;
1625  break;
1626 
1627  default:
1628  if (!type || (type & node->type)) {
1629  ret = walker(node, uctx);
1630  if (ret < 0) return ret;
1631  }
1632  break;
1633  }
1634  }
1635 
1636  return 0;
1637 }
1638 
1640 {
1642 
1643  if (instance_count > 0) {
1644  instance_count++;
1645  return 0;
1646  }
1647 
1648  instance_count++;
1649 
1650  if (fr_dict_autoload(xlat_eval_dict) < 0) {
1651  PERROR("%s", __FUNCTION__);
1652  return -1;
1653  }
1654 
1656  PERROR("%s", __FUNCTION__);
1658  return -1;
1659  }
1660 
1661  return 0;
1662 }
1663 
1664 void xlat_eval_free(void)
1665 {
1667 
1668  if (--instance_count > 0) return;
1669 
1671 }
static int const char char buffer[256]
Definition: acutest.h:574
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:165
#define RCSID(id)
Definition: build.h:444
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:405
static void * fr_dcursor_tail(fr_dcursor_t *cursor)
Wind cursor to the tail item in the list.
Definition: dcursor.h:258
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition: dcursor.h:434
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition: dcursor.h:336
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition: debug.h:214
#define fr_dict_autofree(_to_free)
Definition: dict.h:674
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:250
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
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:3647
#define fr_dict_autoload(_to_load)
Definition: dict.h:671
static fr_slen_t in
Definition: dict.h:645
Specifies an attribute which must be present for the module to function.
Definition: dict.h:249
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
Test enumeration values.
Definition: dict_test.h:92
#define EXEC_TIMEOUT
Default wait time for exec calls (in seconds).
Definition: exec.h:32
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition: interpret.c:1745
int unlang_interpret_stack_depth(request_t *request)
Return the depth of the request's stack.
Definition: interpret.c:1263
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition: interpret.c:1384
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)
Definition: merged_model.c:213
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
Definition: merged_model.c:81
@ FR_TYPE_UINT16
16 Bit unsigned integer.
Definition: merged_model.c:98
@ FR_TYPE_UINT8
8 Bit unsigned integer.
Definition: merged_model.c:97
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_UINT64
64 Bit unsigned integer.
Definition: merged_model.c:100
@ FR_TYPE_VOID
User data.
Definition: merged_model.c:127
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
long int ssize_t
Definition: merged_model.c:24
unsigned char bool
Definition: merged_model.c:19
ssize_t fr_slen_t
Definition: merged_model.c:35
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 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:41
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:1419
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition: sbuff.c:1554
#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:215
#define tmpl_value(_tmpl)
Definition: tmpl.h:932
#define tmpl_is_attr(vpt)
Definition: tmpl.h:213
#define tmpl_is_exec(vpt)
Definition: tmpl.h:216
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:1344
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:1075
#define tmpl_is_data(vpt)
Definition: tmpl.h:211
#define tmpl_value_type(_tmpl)
Definition: tmpl.h:934
Optional arguments passed to vp_tmpl functions.
Definition: tmpl.h:341
fr_signal_t
Definition: signal.h:48
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:175
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition: table.h:253
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition: talloc.c:333
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:729
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:709
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:588
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:699
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:259
goto success
Definition: tmpl_eval.c:1450
VALUE_BOX_LIST_VERIFY(list)
#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:561
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:274
fr_type_t type
Type to cast argument to.
Definition: xlat.h:153
void * data
Thread specific instance data.
Definition: xlat.h:97
bool xlat_is_literal(xlat_exp_head_t const *head)
Check to see if the expansion consists entirely of value-box elements.
xlat_thread_inst_t * xlat_thread_instance_find(xlat_exp_t const *node)
Retrieve xlat/thread specific instance data.
Definition: xlat_inst.c:402
bool required
Argument must be present, and non-empty.
Definition: xlat.h:146
xlat_escape_func_t func
Function to handle tainted values.
Definition: xlat.h:154
@ XLAT_ARG_VARIADIC_EMPTY_KEEP
Empty argument groups are left alone, and either passed through as empty groups or null boxes.
Definition: xlat.h:137
@ XLAT_ARG_VARIADIC_EMPTY_SQUASH
Empty argument groups are removed.
Definition: xlat.h:136
@ XLAT_ARG_VARIADIC_DISABLED
Definition: xlat.h:135
static fr_slen_t head
Definition: xlat.h:408
xlat_arg_parser_variadic_t variadic
All additional boxes should be processed using this definition.
Definition: xlat.h:149
bool concat
Concat boxes together.
Definition: xlat.h:147
bool single
Argument must only contain a single box.
Definition: xlat.h:148
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:225
@ XLAT_INPUT_MONO
Ingests a single argument.
Definition: xlat.h:47
@ XLAT_INPUT_ARGS
Ingests a number of arguments.
Definition: xlat.h:48
@ XLAT_INPUT_UNPROCESSED
No input argument processing.
Definition: xlat.h:46
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:214
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, fr_value_box_safe_for_t literals_safe_for)
Tokenize an xlat expansion.
xlat_action_t
Definition: xlat.h:35
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition: xlat.h:42
@ XLAT_ACTION_YIELD
An xlat function pushed a resume frame onto the stack.
Definition: xlat.h:40
@ XLAT_ACTION_PUSH_UNLANG
An xlat function pushed an unlang frame onto the unlang stack.
Definition: xlat.h:37
@ XLAT_ACTION_PUSH_CHILD
A deeper level of nesting needs to be evaluated.
Definition: xlat.h:36
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition: xlat.h:41
bool constant
xlat is just tmpl_attr_tail_data, or XLAT_BOX
Definition: xlat.h:116
module_ctx_t const * mctx
A synthesised module calling ctx containing module global and thread instance data.
Definition: xlat.h:99
Definition for a single argument consumend by an xlat function.
Definition: xlat.h:145
Thread specific instance data for xlat expansion node.
Definition: xlat.h:88
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
#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:357
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition: types.h:433
#define fr_type_is_null(_x)
Definition: types.h:326
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:3689
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:3521
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition: value.c:3630
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:3876
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:5976
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:6106
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
Definition: value.c:4097
int fr_value_box_bstrdup_buffer_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a talloced buffer containing a nul terminated string to a box, but don't copy it.
Definition: value.c:4202
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:5725
@ FR_VALUE_BOX_LIST_FREE
Definition: value.h:214
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:608
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition: value.h:1035
#define VALUE_BOX_VERIFY(_x)
Definition: value.h:1291
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:619
static size_t char ** out
Definition: value.h:984
#define XLAT_CTX(_inst, _thread, _mctx, _env_data, _rctx)
Wrapper to create a xlat_ctx_t as a compound literal.
Definition: xlat_ctx.h:86
void * rctx
Resume context.
Definition: xlat_ctx.h:47
An xlat calling ctx.
Definition: xlat_ctx.h:42
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:1462
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:79
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:148
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:869
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:761
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:196
int xlat_eval_init(void)
Definition: xlat_eval.c:1639
fr_table_num_sorted_t const xlat_action_table[]
Definition: xlat_eval.c:60
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:795
static fr_dict_t const * dict_freeradius
Definition: xlat_eval.c:42
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:544
fr_dict_attr_t const * attr_expr_bool_enum
Definition: xlat_eval.c:51
int xlat_flatten_compiled_argv(TALLOC_CTX *ctx, xlat_exp_head_t ***argv, xlat_exp_head_t *head)
Turn xlat_tokenize_argv() into an argv[] array, and nuke the input list.
Definition: xlat_eval.c:1538
static xlat_action_t xlat_process_args(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, xlat_t const *func)
Process list of boxed values provided as input to an xlat.
Definition: xlat_eval.c:333
static fr_dict_t const * dict_radius
Definition: xlat_eval.c:43
size_t xlat_action_table_len
Definition: xlat_eval.c:66
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:1405
static fr_dict_autoload_t xlat_eval_dict[]
Definition: xlat_eval.c:45
fr_dict_attr_t const * attr_cast_base
Definition: xlat_eval.c:52
fr_value_box_list_t list
Definition: xlat_eval.c:732
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:1454
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:1035
static fr_dict_attr_autoload_t xlat_eval_dict_attr[]
Definition: xlat_eval.c:54
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:496
void xlat_eval_free(void)
Definition: xlat_eval.c:1664
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:1575
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:769
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:1470
int xlat_aeval_compiled_argv(TALLOC_CTX *ctx, char ***argv, request_t *request, xlat_exp_head_t const *head, xlat_escape_legacy_t escape, void const *escape_ctx)
Synchronous compile xlat_tokenize_argv() into argv[] array.
Definition: xlat_eval.c:1503
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:1352
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:1479
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:181
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:1253
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:735
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, unsigned int arg_num)
Process an individual xlat argument value box group.
Definition: xlat_eval.c:217
#define ESCAPE(_arg, _vb, _arg_num)
static int instance_count
Definition: xlat_eval.c:40
#define XLAT_DEBUG(...)
Definition: xlat_expr.c:39
static xlat_exp_t * xlat_exp_next(xlat_exp_head_t const *head, xlat_exp_t const *node)
Definition: xlat_priv.h:239
xlat_flags_t flags
Flags that control resolution and evaluation.
Definition: xlat_priv.h:153
int(* xlat_walker_t)(xlat_exp_t *exp, void *uctx)
Walker callback for xlat_walk()
Definition: xlat_priv.h:260
xlat_type_t
Definition: xlat_priv.h:101
@ XLAT_ONE_LETTER
Special "one-letter" expansion.
Definition: xlat_priv.h:104
@ XLAT_BOX
fr_value_box_t
Definition: xlat_priv.h:103
@ XLAT_TMPL
xlat attribute
Definition: xlat_priv.h:109
@ XLAT_VIRTUAL_UNRESOLVED
virtual attribute needs resolution during pass2.
Definition: xlat_priv.h:108
@ XLAT_FUNC
xlat module
Definition: xlat_priv.h:105
@ XLAT_VIRTUAL
virtual attribute
Definition: xlat_priv.h:107
@ XLAT_GROUP
encapsulated string of xlats
Definition: xlat_priv.h:113
@ XLAT_FUNC_UNRESOLVED
func needs resolution during pass2.
Definition: xlat_priv.h:106
@ XLAT_INVALID
Bad expansion.
Definition: xlat_priv.h:102
static xlat_exp_t * xlat_exp_head(xlat_exp_head_t const *head)
Definition: xlat_priv.h:203
char const *_CONST fmt
The original format string (a talloced buffer).
Definition: xlat_priv.h:150
xlat_type_t _CONST type
type of this expansion.
Definition: xlat_priv.h:154
#define xlat_exp_foreach(_list_head, _iter)
Iterate over the contents of a list, only one level.
Definition: xlat_priv.h:216
An xlat expansion node.
Definition: xlat_priv.h:147