The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
xlat_builtin.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: 1236b4853171f69746d054f86eca82823c475870 $
19  *
20  * @file xlat_builtin.c
21  * @brief String expansion ("translation"). Baked in expansions.
22  *
23  * @copyright 2000,2006 The FreeRADIUS server project
24  * @copyright 2000 Alan DeKok (aland@freeradius.org)
25  */
26 
27 RCSID("$Id: 1236b4853171f69746d054f86eca82823c475870 $")
28 
29 /**
30  * @defgroup xlat_functions xlat expansion functions
31  */
32 
33 #include <freeradius-devel/server/base.h>
34 #include <freeradius-devel/server/tmpl_dcursor.h>
35 #include <freeradius-devel/unlang/interpret.h>
36 #include <freeradius-devel/unlang/xlat_priv.h>
37 #include <freeradius-devel/unlang/xlat_func.h>
38 #include <freeradius-devel/unlang/xlat.h>
39 #include <freeradius-devel/unlang/xlat_ctx.h>
40 
41 #include <freeradius-devel/io/test_point.h>
42 
43 #include <freeradius-devel/util/base64.h>
44 #include <freeradius-devel/util/base16.h>
45 #include <freeradius-devel/util/dlist.h>
46 #include <freeradius-devel/util/md5.h>
47 #include <freeradius-devel/util/misc.h>
48 #include <freeradius-devel/util/rand.h>
49 #include <freeradius-devel/util/regex.h>
50 #include <freeradius-devel/util/sbuff.h>
51 #include <freeradius-devel/util/sha1.h>
52 #include <freeradius-devel/util/value.h>
53 
54 #ifdef HAVE_OPENSSL_EVP_H
55 # include <freeradius-devel/tls/openssl_user_macros.h>
56 # include <openssl/evp.h>
57 #endif
58 
59 #include <sys/stat.h>
60 #include <fcntl.h>
61 
62 static char const hextab[] = "0123456789abcdef";
63 
64 /** Return a VP from the specified request.
65  *
66  * @note DEPRECATED, TO NOT USE.
67  *
68  * @param out where to write the pointer to the resolved VP. Will be NULL if the attribute couldn't
69  * be resolved.
70  * @param request current request.
71  * @param name attribute name including qualifiers.
72  * @return
73  * - -4 if either the attribute or qualifier were invalid.
74  * - The same error codes as #tmpl_find_vp for other error conditions.
75  */
76 int xlat_fmt_get_vp(fr_pair_t **out, request_t *request, char const *name)
77 {
78  int ret;
79  tmpl_t *vpt;
80 
81  *out = NULL;
82 
83  if (tmpl_afrom_attr_str(request, NULL, &vpt, name,
84  &(tmpl_rules_t){
85  .attr = {
86  .dict_def = request->dict,
87  .list_def = request_attr_request,
89  }
90  }) <= 0) return -4;
91 
92  ret = tmpl_find_vp(out, request, vpt);
94 
95  return ret;
96 }
97 
98 /*
99  * Regular xlat functions
100  */
102  { .single = true, .type = FR_TYPE_INT8 },
104 };
105 
106 /** Dynamically change the debugging level for the current request
107  *
108  * Example:
109 @verbatim
110 %debug(3)
111 @endverbatim
112  *
113  * @ingroup xlat_functions
114  */
116  UNUSED xlat_ctx_t const *xctx,
117  request_t *request, fr_value_box_list_t *args)
118 {
119  int level = 0;
120  fr_value_box_t *vb, *lvl_vb;
121 
122  XLAT_ARGS(args, &lvl_vb);
123 
124  /*
125  * Expand to previous (or current) level
126  */
127  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_INT8, NULL));
128  vb->vb_int8 = request->log.lvl;
129  fr_dcursor_append(out, vb);
130 
131  /*
132  * Assume we just want to get the current value and NOT set it to 0
133  */
134  if (!lvl_vb) goto done;
135 
136  level = lvl_vb->vb_int8;
137  if (level == 0) {
138  request->log.lvl = RAD_REQUEST_LVL_NONE;
139  } else {
140  if (level > L_DBG_LVL_MAX) level = L_DBG_LVL_MAX;
141  request->log.lvl = level;
142  }
143 
144 done:
145  return XLAT_ACTION_DONE;
146 }
147 
148 
150  { .required = true, .single = true, .type = FR_TYPE_STRING },
152 };
153 
155 {
156  fr_dict_vendor_t const *vendor;
158  size_t i;
159 
160  switch (vp->vp_type) {
161  case FR_TYPE_STRUCTURAL:
162  if (vpt) {
163  RIDEBUG2("&%s.%s = {",
164  tmpl_list_name(tmpl_list(vpt), "<INVALID>"),
165  vp->da->name);
166  } else {
167  RIDEBUG2("%s = {", vp->da->name);
168  }
169  RINDENT();
170  xlat_debug_attr_list(request, &vp->vp_group);
171  REXDENT();
172  RIDEBUG2("}");
173  break;
174 
175  default:
176  if (vpt) {
177  RIDEBUG2("&%s.%s = %pV",
178  tmpl_list_name(tmpl_list(vpt), "<INVALID>"),
179  vp->da->name,
180  &vp->data);
181  } else {
182  RIDEBUG2("%s = %pV", vp->da->name, &vp->data);
183  }
184  }
185 
186  if (!RDEBUG_ENABLED3) return;
187 
188  RINDENT();
189  RIDEBUG3("da : %p", vp->da);
190  RIDEBUG3("is_raw : %pV", fr_box_bool(vp->vp_raw));
191  RIDEBUG3("is_unknown : %pV", fr_box_bool(vp->da->flags.is_unknown));
192 
193  if (RDEBUG_ENABLED3) {
194  RIDEBUG3("parent : %s (%p)", vp->da->parent->name, vp->da->parent);
195  } else {
196  RIDEBUG2("parent : %s", vp->da->parent->name);
197  }
198  RIDEBUG3("attr : %u", vp->da->attr);
199  vendor = fr_dict_vendor_by_da(vp->da);
200  if (vendor) RIDEBUG2("vendor : %i (%s)", vendor->pen, vendor->name);
201  RIDEBUG3("type : %s", fr_type_to_str(vp->vp_type));
202 
203  switch (vp->vp_type) {
204  case FR_TYPE_LEAF:
205  if (fr_box_is_variable_size(&vp->data)) {
206  RIDEBUG3("length : %zu", vp->vp_length);
207  }
208  RIDEBUG3("tainted : %pV", fr_box_bool(vp->data.tainted));
209  break;
210  default:
211  break;
212  }
213 
214  if (!RDEBUG_ENABLED4) {
215  REXDENT();
216  return;
217  }
218 
219  for (i = 0; i < fr_type_table_len; i++) {
220  int pad;
221 
222  fr_value_box_t *dst = NULL;
223 
224  type = &fr_type_table[i];
225 
226  if ((fr_type_t) type->value == vp->vp_type) goto next_type;
227 
228  /*
229  * Don't cast TO structural, or FROM structural types.
230  */
231  if (!fr_type_is_leaf(type->value) || !fr_type_is_leaf(vp->vp_type)) goto next_type;
232 
234  /* We expect some to fail */
235  if (fr_value_box_cast(dst, dst, type->value, NULL, &vp->data) < 0) {
236  goto next_type;
237  }
238 
239  if ((pad = (11 - type->name.len)) < 0) pad = 0;
240 
241  RINDENT();
242  RDEBUG4("as %s%*s: %pV", type->name.str, pad, " ", dst);
243  REXDENT();
244 
245  next_type:
246  talloc_free(dst);
247  }
248 
249  REXDENT();
250 }
251 
252 void xlat_debug_attr_list(request_t *request, fr_pair_list_t const *list)
253 {
254  fr_pair_t *vp;
255 
256  for (vp = fr_pair_list_next(list, NULL);
257  vp != NULL;
258  vp = fr_pair_list_next(list, vp)) {
259  xlat_debug_attr_vp(request, vp, NULL);
260  }
261 }
262 
263 /** Common function to move boxes form input list to output list
264  *
265  * This can be used to implement safe_for functions, as the xlat framework
266  * can be used for concatenation, casting, and marking up output boxes as
267  * safe_for.
268  */
270  UNUSED xlat_ctx_t const *xctx,
271  UNUSED request_t *request, fr_value_box_list_t *args)
272 {
274  fr_value_box_list_remove(args, vb);
275  fr_dcursor_append(out, vb);
276  }}
277 
279 }
280 
281 /** Print out attribute info
282  *
283  * Prints out all instances of a current attribute, or all attributes in a list.
284  *
285  * At higher debugging levels, also prints out alternative decodings of the same
286  * value. This is helpful to determine types for unknown attributes of long
287  * passed vendors, or just crazy/broken NAS.
288  *
289  * This expands to a zero length string.
290  *
291  * Example:
292 @verbatim
293 %debug_attr(&request)
294 @endverbatim
295  *
296  * @ingroup xlat_functions
297  */
299  UNUSED xlat_ctx_t const *xctx,
300  request_t *request, fr_value_box_list_t *args)
301 {
302  fr_pair_t *vp;
303  fr_dcursor_t cursor;
305  tmpl_t *vpt;
306  fr_value_box_t *attr;
307  char const *fmt;
308 
309  XLAT_ARGS(args, &attr);
310 
311  if (!RDEBUG_ENABLED2) return XLAT_ACTION_DONE; /* NOOP if debugging isn't enabled */
312 
313  fmt = attr->vb_strvalue;
314 
315  if (tmpl_afrom_attr_str(request, NULL, &vpt, fmt,
316  &(tmpl_rules_t){
317  .attr = {
318  .dict_def = request->dict,
319  .list_def = request_attr_request,
320  .allow_wildcard = true,
321  .prefix = TMPL_ATTR_REF_PREFIX_AUTO
322  }
323  }) <= 0) {
324  RPEDEBUG("Invalid input");
325  return XLAT_ACTION_FAIL;
326  }
327 
328  RIDEBUG("Attributes matching \"%s\"", fmt);
329 
330  RINDENT();
331  for (vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt);
332  vp;
333  vp = fr_dcursor_next(&cursor)) {
334  xlat_debug_attr_vp(request, vp, vpt);
335  }
336  tmpl_dcursor_clear(&cc);
337  REXDENT();
338 
339  talloc_free(vpt);
340 
341  return XLAT_ACTION_DONE;
342 }
343 
344 #ifdef __clang__
345 #pragma clang diagnostic ignored "-Wgnu-designator"
346 #endif
347 
349  .name = "filename",
350  .chr = '_',
351  .do_utf8 = true,
352  .do_hex = true,
353 
354  .esc = {
355  [ 0x00 ... 0x2d ] = true, // special characters, but not '.'
356  [ 0x2f ] = true, // /
357  [ 0x3A ... 0x3f ] = true, // :;<=>?, but not "@"
358  [ 0x5b ... 0x5e ] = true, // [\]^
359  [ 0x60 ] = true, // back-tick
360  [ 0x7b ... 0xff ] = true, // {|}, and all chars which have high bit set, but aren't UTF-8
361  },
362 };
363 
365  .name = "filename",
366  .chr = '_',
367  .do_utf8 = true,
368  .do_hex = true,
369 
370  .esc = {
371  [ 0x00 ... 0x2f ] = true, // special characters, '.', '/', etc.
372  [ 0x3A ... 0x3f ] = true, // :;<=>?, but not "@"
373  [ 0x5b ... 0x5e ] = true, // [\]^
374  [ 0x60 ] = true, // back-tick
375  [ 0x7b ... 0xff ] = true, // {|}, and all chars which have high bit set, but aren't UTF-8
376  },
377 };
378 
379 /** Escape the paths as necessary
380  *
381  */
383 {
384  fr_sbuff_t our_in = FR_SBUFF(in);
385  fr_sbuff_t out;
386  char buffer[256];
387 
388  if (vb->type == FR_TYPE_GROUP) {
389  fr_value_box_list_foreach(&vb->vb_group, box) {
390  if (xlat_file_escape_path(&our_in, box) < 0) return -1;
391  }
392 
393  goto done;
394  }
395 
396  fr_assert(fr_type_is_leaf(vb->type));
397 
398  /*
399  * Untainted values get passed through, as do base integer types.
400  */
401  if (!vb->tainted || (vb->type == FR_TYPE_OCTETS) || fr_type_is_integer(vb->type)) {
402  fr_value_box_print(&our_in, vb, NULL);
403  goto done;
404  }
405 
406  /*
407  * If the tainted string has a leading '.', then escape _all_ periods in it. This is so that we
408  * don't accidentally allow a "safe" value to end with '/', and then an "unsafe" value contains
409  * "..", and we now have a directory traversal attack.
410  *
411  * The escape rules will escape '/' in unsafe strings, so there's no possibility for an unsafe
412  * string to either end with a '/', or to contain "/.." itself.
413  *
414  * Allowing '.' in the middle of the string means we can have filenames based on realms, such as
415  * "log/aland@freeradius.org".
416  */
417  if (vb->type == FR_TYPE_STRING) {
418  if (vb->vb_length == 0) goto done;
419 
420  if (vb->vb_strvalue[0] == '.') {
422  } else {
424  }
425  goto done;
426  }
427 
428  /*
429  * Ethernet addresses have ':'. IP prefixes have '/'. Floats have '+' and '-' in them.
430  * Dates have pretty much all of that, plus spaces.
431  *
432  * Lesson: print dates as %Y() or %l().
433  *
434  * We use an intermediate buffer to print the type, and then copy it to the output
435  * buffer, escaping it along the way.
436  */
437  out = FR_SBUFF_OUT(buffer, sizeof(buffer));
438  fr_value_box_print(&out, vb, NULL);
440 
441 done:
442  FR_SBUFF_SET_RETURN(in, &our_in);
443 }
444 
445 static const char *xlat_file_name(fr_value_box_t *vb)
446 {
447  fr_sbuff_t *path;
448 
449  FR_SBUFF_TALLOC_THREAD_LOCAL(&path, 256, PATH_MAX + 1);
450 
451  if (xlat_file_escape_path(path, vb) < 0) return NULL;
452 
453  if (fr_sbuff_in_char(path, '\0') < 0) return NULL; /* file functions take NUL delimited strings */
454 
455  return fr_sbuff_start(path);
456 }
457 
459  { .required = true, .type = FR_TYPE_STRING },
461 };
462 
464  { .required = true, .type = FR_TYPE_STRING },
465  { .required = false, .type = FR_TYPE_UINT32 },
467 };
468 
469 
471  UNUSED xlat_ctx_t const *xctx,
472  UNUSED request_t *request, fr_value_box_list_t *args)
473 {
474  fr_value_box_t *dst, *vb;
475  char const *filename;
476 
477  XLAT_ARGS(args, &vb);
478  filename = xlat_file_name(vb);
479  if (!filename) return XLAT_ACTION_FAIL;
480 
481  MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL));
482  if (fr_value_box_bstrndup(dst, dst, NULL, filename, strlen(filename), false) < 0) {
483  talloc_free(dst);
484  return XLAT_ACTION_FAIL;
485  }
486 
487  fr_dcursor_append(out, dst);
488 
489  return XLAT_ACTION_DONE;
490 }
491 
492 
494  UNUSED xlat_ctx_t const *xctx,
495  UNUSED request_t *request, fr_value_box_list_t *args)
496 {
497  fr_value_box_t *dst, *vb;
498  char const *filename;
499  struct stat buf;
500 
501  XLAT_ARGS(args, &vb);
502  filename = xlat_file_name(vb);
503  if (!filename) return XLAT_ACTION_FAIL;
504 
505  MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
506  fr_dcursor_append(out, dst);
507 
508  dst->vb_bool = (stat(filename, &buf) == 0);
509 
510  return XLAT_ACTION_DONE;
511 }
512 
513 
515  UNUSED xlat_ctx_t const *xctx,
516  request_t *request, fr_value_box_list_t *in)
517 {
518  fr_value_box_t *dst, *vb;
519  char const *filename;
520  ssize_t len;
521  int fd;
522  char *p, buffer[256];
523 
524  XLAT_ARGS(in, &vb);
525  filename = xlat_file_name(vb);
526  if (!filename) return XLAT_ACTION_FAIL;
527 
528  fd = open(filename, O_RDONLY);
529  if (fd < 0) {
530  REDEBUG3("Failed opening file %s - %s", filename, fr_syserror(errno));
531  return XLAT_ACTION_FAIL;
532  }
533 
534  len = read(fd, buffer, sizeof(buffer));
535  if (len < 0) {
536  REDEBUG3("Failed reading file %s - %s", filename, fr_syserror(errno));
537  close(fd);
538  return XLAT_ACTION_FAIL;
539  }
540 
541  /*
542  * Find the first CR/LF, but bail if we get any weird characters.
543  */
544  for (p = buffer; p < (buffer + len); p++) {
545  if ((*p == '\r') || (*p == '\n')) {
546  break;
547  }
548 
549  if ((*p < ' ') && (*p != '\t')) {
550  invalid:
551  REDEBUG("Invalid text in file %s", filename);
552  close(fd);
553  return XLAT_ACTION_FAIL;
554  }
555  }
556 
557  if ((p - buffer) > len) goto invalid;
558  close(fd);
559 
560  MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL));
561  if (fr_value_box_bstrndup(dst, dst, NULL, buffer, p - buffer, false) < 0) {
562  talloc_free(dst);
563  return XLAT_ACTION_FAIL;
564  }
565 
566  fr_dcursor_append(out, dst);
567 
568  return XLAT_ACTION_DONE;
569 }
570 
571 
573  UNUSED xlat_ctx_t const *xctx,
574  request_t *request, fr_value_box_list_t *in)
575 {
576  fr_value_box_t *dst, *vb;
577  char const *filename;
578  struct stat buf;
579 
580  XLAT_ARGS(in, &vb);
581  filename = xlat_file_name(vb);
582  if (!filename) return XLAT_ACTION_FAIL;
583 
584  if (stat(filename, &buf) < 0) {
585  REDEBUG3("Failed checking file %s - %s", filename, fr_syserror(errno));
586  return XLAT_ACTION_FAIL;
587  }
588 
589  MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_UINT64, NULL)); /* off_t is signed, but file sizes shouldn't be negative */
590  fr_dcursor_append(out, dst);
591 
592  dst->vb_uint64 = buf.st_size;
593 
594  return XLAT_ACTION_DONE;
595 }
596 
597 
599  UNUSED xlat_ctx_t const *xctx,
600  request_t *request, fr_value_box_list_t *in)
601 {
602  fr_value_box_t *dst, *vb, *num = NULL;
603  char const *filename;
604  ssize_t len;
605  size_t count = 0;
606  off_t offset;
607  int fd;
608  int n, r, stop = 2;
609  char *p, *end, *found, buffer[256];
610 
611  XLAT_ARGS(in, &vb, &num);
612  filename = xlat_file_name(vb);
613  if (!filename) return XLAT_ACTION_FAIL;
614 
615  fd = open(filename, O_RDONLY);
616  if (fd < 0) {
617  REDEBUG3("Failed opening file %s - %s", filename, fr_syserror(errno));
618  return XLAT_ACTION_FAIL;
619  }
620 
621  offset = lseek(fd, 0, SEEK_END);
622  if (offset < 0) {
623  REDEBUG3("Failed seeking to end of file %s - %s", filename, fr_syserror(errno));
624  goto fail;
625  }
626 
627  if (offset > (off_t) sizeof(buffer)) {
628  offset -= sizeof(buffer);
629  } else {
630  offset = 0;
631  }
632 
633  if (lseek(fd, offset, SEEK_SET) < 0) {
634  REDEBUG3("Failed seeking backwards from end of file %s - %s", filename, fr_syserror(errno));
635  goto fail;
636  }
637 
638  len = read(fd, buffer, sizeof(buffer));
639  if (len < 0) {
640  fail:
641  REDEBUG3("Failed reading file %s - %s", filename, fr_syserror(errno));
642  close(fd);
643  return XLAT_ACTION_FAIL;
644  }
645 
646  if (len == 0) {
647  found = buffer; /* count is zero, so who cares */
648  goto done;
649  }
650 
651  n = r = 0; /* be agnostic over CR / LF */
652 
653  /*
654  * Clamp number of lines to a reasonable value. They
655  * still all have to fit into 256 characters, though.
656  *
657  * @todo - have a large thread-local temporary buffer for this stuff.
658  */
659  if (num) {
660  fr_assert(num->type == FR_TYPE_GROUP);
661  fr_assert(fr_value_box_list_num_elements(&num->vb_group) == 1);
662 
663  num = fr_value_box_list_head(&num->vb_group);
664  fr_assert(num->type == FR_TYPE_UINT32);
665 
666  if (!num->vb_uint32) {
667  stop = 2;
668  } else if (num->vb_uint32 < 15) {
669  stop = num->vb_uint64 + 1;
670  } else {
671  stop = 16;
672  }
673  } else {
674  stop = 2;
675  }
676 
677  end = NULL;
678  found = NULL;
679 
680  /*
681  * Nuke any trailing CR/LF
682  */
683  p = buffer + len - 1;
684  while (p >= buffer) {
685  if (*p == '\r') {
686  r++;
687 
688  if (r == stop) break;
689 
690  if (!end) end = p;
691 
692  } else if (*p == '\n') {
693  n++;
694 
695  if (n == stop) break;
696 
697  if (!end) end = p;
698 
699  } else {
700  if (!r) r++; /* if we didn't get a CR/LF at EOF, pretend we did */
701  if (!n) n++;
702 
703  found = p;
704  }
705 
706  p--;
707  }
708 
709  if (!end) end = buffer + len;
710 
711  /*
712  * The buffer was only one line of CR/LF.
713  */
714  if (!found) {
715  found = buffer;
716  goto done;
717  }
718 
719  count = (end - found);
720 
721 done:
722  close(fd);
723 
724  MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL));
725  if (fr_value_box_bstrndup(dst, dst, NULL, found, count, false) < 0) {
726  talloc_free(dst);
727  return XLAT_ACTION_FAIL;
728  }
729 
730  fr_dcursor_append(out, dst);
731 
732  return XLAT_ACTION_DONE;
733 }
734 
735 
737  UNUSED xlat_ctx_t const *xctx,
738  request_t *request, fr_value_box_list_t *in)
739 {
740  fr_value_box_t *dst, *vb;
741  char const *filename;
742 
743  XLAT_ARGS(in, &vb);
744  filename = xlat_file_name(vb);
745  if (!filename) return XLAT_ACTION_FAIL;
746 
747  MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
748  fr_dcursor_append(out, dst);
749 
750  dst->vb_bool = (unlink(filename) == 0);
751  if (!dst->vb_bool) {
752  REDEBUG3("Failed unlinking file %s - %s", filename, fr_syserror(errno));
753  }
754 
755  return XLAT_ACTION_DONE;
756 }
757 
758 
760  UNUSED xlat_ctx_t const *xctx,
761  UNUSED request_t *request, fr_value_box_list_t *in)
762 {
763  fr_value_box_t *vb;
764 
766  while ((vb = fr_value_box_list_pop_head(in)) != NULL) {
767  fr_dcursor_append(out, vb);
768  }
769 
770  return XLAT_ACTION_DONE;
771 }
772 
774  UNUSED xlat_ctx_t const *xctx,
775  UNUSED request_t *request, fr_value_box_list_t *in)
776 {
777  fr_value_box_t *vb;
778 
779  while ((vb = fr_value_box_list_pop_head(in)) != NULL) {
780  fr_value_box_t *child;
781 
782  fr_assert(vb->type == FR_TYPE_GROUP);
783 
784  while ((child = fr_value_box_list_pop_head(&vb->vb_group)) != NULL) {
785  child->tainted = true;
786 
787  fr_dcursor_append(out, child);
788  }
789  }
790 
791  return XLAT_ACTION_DONE;
792 }
793 
795  { .required = true, .type = FR_TYPE_STRING },
796  { .required = true, .concat = true, .type = FR_TYPE_STRING },
798 };
799 
800 /** Split a string into multiple new strings based on a delimiter
801  *
802 @verbatim
803 %explode(<string>, <delim>)
804 @endverbatim
805  *
806  * Example:
807 @verbatim
808 update request {
809  &Tmp-String-1 := "a,b,c"
810 }
811 "%concat(%explode(%{Tmp-String-1}, ','), '|')" == "a|b|c"g
812 @endverbatim
813  *
814  * @ingroup xlat_functions
815  */
817  UNUSED xlat_ctx_t const *xctx,
818  request_t *request, fr_value_box_list_t *args)
819 {
821  fr_value_box_list_t *list;
822  fr_value_box_t *delim_vb;
823  ssize_t delim_len;
824  char const *delim;
825  fr_value_box_t *string, *vb;
826 
827  XLAT_ARGS(args, &strings, &delim_vb);
828 
829  list = &strings->vb_group;
830 
831  /* coverity[dereference] */
832  if (delim_vb->vb_length == 0) {
833  REDEBUG("Delimiter must be greater than zero characters");
834  return XLAT_ACTION_FAIL;
835  }
836 
837  delim = delim_vb->vb_strvalue;
838  delim_len = delim_vb->vb_length;
839 
840  while((string = fr_value_box_list_pop_head(list))) {
841  fr_sbuff_t sbuff = FR_SBUFF_IN(string->vb_strvalue, string->vb_length);
842  fr_sbuff_marker_t m_start;
843 
844  /*
845  * If the delimiter is not in the string, just move to the output
846  */
847  if (!fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, delim, delim_len)) {
848  fr_dcursor_append(out, string);
849  continue;
850  }
851 
852  fr_sbuff_set_to_start(&sbuff);
853  fr_sbuff_marker(&m_start, &sbuff);
854 
855  while (fr_sbuff_remaining(&sbuff)) {
856  if (fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, delim, delim_len)) {
857  /*
858  * If there's nothing before the delimiter skip
859  */
860  if (fr_sbuff_behind(&m_start) == 0) goto advance;
861 
862  MEM(vb = fr_value_box_alloc_null(ctx));
863  fr_value_box_bstrndup(vb, vb, NULL, fr_sbuff_current(&m_start),
864  fr_sbuff_behind(&m_start), string->tainted);
865  fr_dcursor_append(out, vb);
866 
867  advance:
868  fr_sbuff_advance(&sbuff, delim_len);
869  fr_sbuff_set(&m_start, &sbuff);
870  continue;
871  }
872  fr_sbuff_set_to_end(&sbuff);
873  MEM(vb = fr_value_box_alloc_null(ctx));
874  fr_value_box_bstrndup(vb, vb, NULL, fr_sbuff_current(&m_start),
875  fr_sbuff_behind(&m_start), string->tainted);
876  fr_dcursor_append(out, vb);
877  break;
878  }
879  talloc_free(string);
880  }
881 
882  return XLAT_ACTION_DONE;
883 }
884 
886  { .required = true, .single = true, .type = FR_TYPE_STRING },
888 };
889 
890 /** Mark one or more attributes as immutable
891  *
892  * Example:
893 @verbatim
894 %immutable(&request.State[*])
895 @endverbatim
896  *
897  * @ingroup xlat_functions
898  */
900  UNUSED xlat_ctx_t const *xctx,
901  request_t *request, fr_value_box_list_t *args)
902 {
903  fr_pair_t *vp;
904  fr_dcursor_t cursor;
906  tmpl_t *vpt;
907  fr_value_box_t *attr;
908  char const *fmt;
909 
910  XLAT_ARGS(args, &attr);
911 
912  fmt = attr->vb_strvalue;
913 
914  if (tmpl_afrom_attr_str(request, NULL, &vpt, fmt,
915  &(tmpl_rules_t){
916  .attr = {
917  .dict_def = request->dict,
918  .list_def = request_attr_request,
919  .allow_wildcard = true,
920  .prefix = TMPL_ATTR_REF_PREFIX_AUTO
921  }
922  }) <= 0) {
923  RPEDEBUG("Invalid input");
924  return XLAT_ACTION_FAIL;
925  }
926 
927  RIDEBUG("Attributes matching \"%s\"", fmt);
928 
929  RINDENT();
930  for (vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt);
931  vp;
932  vp = fr_dcursor_next(&cursor)) {
933  if (fr_type_is_leaf(vp->vp_type)) fr_value_box_set_immutable(&vp->data);
934  }
935  tmpl_dcursor_clear(&cc);
936  REXDENT();
937 
938  talloc_free(vpt);
939 
940  return XLAT_ACTION_DONE;
941 }
942 
944  { .required = true, .single = true, .type = FR_TYPE_VOID },
946 };
947 
948 /** Print data as integer, not as VALUE.
949  *
950  * Example:
951 @verbatim
952 update request {
953  &Tmp-IP-Address-0 := "127.0.0.5"
954 }
955 %integer(%{Tmp-IP-Address-0}) == 2130706437
956 @endverbatim
957  * @ingroup xlat_functions
958  */
960  UNUSED xlat_ctx_t const *xctx,
961  request_t *request, fr_value_box_list_t *args)
962 {
963  fr_value_box_t *in_vb;
964  char const *p;
965 
966  XLAT_ARGS(args, &in_vb);
967 
968  fr_strerror_clear(); /* Make sure we don't print old errors */
969 
970  fr_value_box_list_remove(args, in_vb);
971 
972  switch (in_vb->type) {
973  default:
974  error:
975  RPEDEBUG("Failed converting %pV (%s) to an integer", in_vb,
976  fr_type_to_str(in_vb->type));
977  talloc_free(in_vb);
978  return XLAT_ACTION_FAIL;
979 
980  case FR_TYPE_NUMERIC:
981  /*
982  * Ensure enumeration is NULL so that the integer
983  * version of a box is returned
984  */
985  in_vb->enumv = NULL;
986 
987  /*
988  * FR_TYPE_DATE and FR_TYPE_TIME_DELTA need to be cast
989  * to int64_t so that they're printed in a
990  * numeric format.
991  */
992  if ((in_vb->type == FR_TYPE_DATE) || (in_vb->type == FR_TYPE_TIME_DELTA)) {
993  if (fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_INT64, NULL) < 0) goto error;
994  }
995  break;
996 
997  case FR_TYPE_STRING:
998  /*
999  * Strings are always zero terminated. They may
1000  * also have zeros in the middle, but if that
1001  * happens, the caller will only get the part up
1002  * to the first zero.
1003  *
1004  * We check for negative numbers, just to be
1005  * nice.
1006  */
1007  for (p = in_vb->vb_strvalue; *p != '\0'; p++) {
1008  if (*p == '-') break;
1009  }
1010 
1011  if (*p == '-') {
1012  if (fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_INT64, NULL) < 0) goto error;
1013  } else {
1014  if (fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT64, NULL) < 0) goto error;
1015  }
1016  break;
1017 
1018  case FR_TYPE_OCTETS:
1019  if (in_vb->vb_length > sizeof(uint64_t)) {
1020  fr_strerror_printf("Expected octets length <= %zu, got %zu", sizeof(uint64_t), in_vb->vb_length);
1021  goto error;
1022  }
1023 
1024  if (in_vb->vb_length > sizeof(uint32_t)) {
1025  if (unlikely(fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT64, NULL) < 0)) goto error;
1026  } else if (in_vb->vb_length > sizeof(uint16_t)) {
1027  if (unlikely(fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT32, NULL) < 0)) goto error;
1028  } else if (in_vb->vb_length > sizeof(uint8_t)) {
1029  if (unlikely(fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT16, NULL) < 0)) goto error;
1030  } else {
1031  if (unlikely(fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT8, NULL) < 0)) goto error;
1032  }
1033 
1034  break;
1035 
1036  case FR_TYPE_IPV4_ADDR:
1037  case FR_TYPE_IPV4_PREFIX:
1038  if (fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT32, NULL) < 0) goto error;
1039  break;
1040 
1041  case FR_TYPE_ETHERNET:
1042  if (fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT64, NULL) < 0) goto error;
1043  break;
1044 
1045  case FR_TYPE_IPV6_ADDR:
1046  case FR_TYPE_IPV6_PREFIX:
1047  {
1048  uint128_t ipv6int;
1049  char buff[40];
1050  fr_value_box_t *vb;
1051 
1052  /*
1053  * Needed for correct alignment (as flagged by ubsan)
1054  */
1055  memcpy(&ipv6int, &in_vb->vb_ip.addr.v6.s6_addr, sizeof(ipv6int));
1056 
1057  fr_snprint_uint128(buff, sizeof(buff), ntohlll(ipv6int));
1058 
1059  MEM(vb = fr_value_box_alloc_null(ctx));
1060  fr_value_box_bstrndup(vb, vb, NULL, buff, strlen(buff), false);
1061  fr_dcursor_append(out, vb);
1062  talloc_free(in_vb);
1063  return XLAT_ACTION_DONE;
1064  }
1065  }
1066 
1067  fr_dcursor_append(out, in_vb);
1068 
1069  return XLAT_ACTION_DONE;
1070 }
1071 
1073  { .concat = true, .type = FR_TYPE_STRING },
1075 };
1076 
1077 /** Log something at INFO level.
1078  *
1079  * Example:
1080 @verbatim
1081 %log("This is an informational message")
1082 @endverbatim
1083  *
1084  * @ingroup xlat_functions
1085  */
1087  UNUSED xlat_ctx_t const *xctx,
1088  request_t *request, fr_value_box_list_t *args)
1089 {
1090  fr_value_box_t *vb;
1091 
1092  XLAT_ARGS(args, &vb);
1093 
1094  if (!vb) return XLAT_ACTION_DONE;
1095 
1096  RINFO("%s", vb->vb_strvalue);
1097 
1098  return XLAT_ACTION_DONE;
1099 }
1100 
1101 
1102 /** Log something at DEBUG level.
1103  *
1104  * Example:
1105 @verbatim
1106 %log.debug("This is a message")
1107 @endverbatim
1108  *
1109  * @ingroup xlat_functions
1110  */
1112  UNUSED xlat_ctx_t const *xctx,
1113  request_t *request, fr_value_box_list_t *args)
1114 {
1115  fr_value_box_t *vb;
1116 
1117  XLAT_ARGS(args, &vb);
1118 
1119  if (!vb) return XLAT_ACTION_DONE;
1120 
1121  RDEBUG("%s", vb->vb_strvalue);
1122 
1123  return XLAT_ACTION_DONE;
1124 }
1125 
1126 
1127 /** Log something at DEBUG level.
1128  *
1129  * Example:
1130 @verbatim
1131 %log.err("Big error here")
1132 @endverbatim
1133  *
1134  * @ingroup xlat_functions
1135  */
1137  UNUSED xlat_ctx_t const *xctx,
1138  request_t *request, fr_value_box_list_t *args)
1139 {
1140  fr_value_box_t *vb;
1141 
1142  XLAT_ARGS(args, &vb);
1143 
1144  if (!vb) return XLAT_ACTION_DONE;
1145 
1146  REDEBUG("%s", vb->vb_strvalue);
1147 
1148  return XLAT_ACTION_DONE;
1149 }
1150 
1151 
1152 /** Log something at WARN level.
1153  *
1154  * Example:
1155 @verbatim
1156 %log.warn("Maybe something bad happened")
1157 @endverbatim
1158  *
1159  * @ingroup xlat_functions
1160  */
1162  UNUSED xlat_ctx_t const *xctx,
1163  request_t *request, fr_value_box_list_t *args)
1164 {
1165  fr_value_box_t *vb;
1166 
1167  XLAT_ARGS(args, &vb);
1168 
1169  if (!vb) return XLAT_ACTION_DONE;
1170 
1171  RWDEBUG("%s", vb->vb_strvalue);
1172 
1173  return XLAT_ACTION_DONE;
1174 }
1175 
1176 static int _log_dst_free(fr_log_t *log)
1177 {
1178  close(log->fd);
1179  return 0;
1180 }
1181 
1183  { .required = false, .type = FR_TYPE_STRING, .concat = true },
1184  { .required = false, .type = FR_TYPE_UINT32, .single = true },
1185  { .required = false, .type = FR_TYPE_STRING, .concat = true },
1187 };
1188 
1189 /** Change the log destination to the named one
1190  *
1191  * Example:
1192 @verbatim
1193 %log.destination('foo')
1194 @endverbatim
1195  *
1196  * @ingroup xlat_functions
1197  */
1199  UNUSED xlat_ctx_t const *xctx,
1200  request_t *request, fr_value_box_list_t *args)
1201 {
1202  fr_value_box_t *dst, *lvl, *file;
1203  fr_log_t *log, *dbg;
1204  uint32_t level = 2;
1205 
1206  XLAT_ARGS(args, &dst, &lvl, &file);
1207 
1208  if (!dst || !*dst->vb_strvalue) {
1209  request_log_prepend(request, NULL, L_DBG_LVL_DISABLE);
1210  return XLAT_ACTION_DONE;
1211  }
1212 
1213  log = log_dst_by_name(dst->vb_strvalue);
1214  if (!log) return XLAT_ACTION_FAIL;
1215 
1216  if (lvl) level = lvl->vb_uint32;
1217 
1218  if (!file || ((log->dst != L_DST_NULL) && (log->dst != L_DST_FILES))) {
1219  request_log_prepend(request, log, level);
1220  return XLAT_ACTION_DONE;
1221  }
1222 
1223  /*
1224  * Clone it.
1225  */
1226  MEM(dbg = talloc_memdup(request, log, sizeof(*log)));
1227  dbg->parent = log;
1228 
1229  /*
1230  * Open the new filename.
1231  */
1232  dbg->dst = L_DST_FILES;
1233  dbg->file = talloc_strdup(dbg, file->vb_strvalue);
1234  dbg->fd = open(dbg->file, O_WRONLY | O_CREAT | O_CLOEXEC, 0600);
1235  if (dbg->fd < 0) {
1236  REDEBUG("Failed opening %s - %s", dbg->file, fr_syserror(errno));
1237  talloc_free(dbg);
1238  return XLAT_ACTION_DONE;
1239  }
1240 
1241  /*
1242  * Ensure that we close the file handle when done.
1243  */
1244  talloc_set_destructor(dbg, _log_dst_free);
1245 
1246  request_log_prepend(request, dbg, level);
1247  return XLAT_ACTION_DONE;
1248 }
1249 
1250 
1252  { .required = true, .concat = true, .type = FR_TYPE_STRING },
1254 };
1255 
1256 /** Processes fmt as a map string and applies it to the current request
1257  *
1258  * e.g.
1259 @verbatim
1260 %map("&User-Name := 'foo'")
1261 @endverbatim
1262  *
1263  * Allows sets of modifications to be cached and then applied.
1264  * Useful for processing generic attributes from LDAP.
1265  *
1266  * @ingroup xlat_functions
1267  */
1268 static xlat_action_t xlat_func_map(TALLOC_CTX *ctx, fr_dcursor_t *out,
1269  UNUSED xlat_ctx_t const *xctx,
1270  request_t *request, fr_value_box_list_t *args)
1271 {
1272  map_t *map = NULL;
1273  int ret;
1274  fr_value_box_t *fmt_vb;
1275  fr_value_box_t *vb;
1276 
1277  tmpl_rules_t attr_rules = {
1278  .attr = {
1279  .dict_def = request->dict,
1280  .list_def = request_attr_request,
1281  .prefix = TMPL_ATTR_REF_PREFIX_AUTO
1282  },
1283  .xlat = {
1284  .runtime_el = unlang_interpret_event_list(request)
1285  }
1286  };
1287 
1288  XLAT_ARGS(args, &fmt_vb);
1289 
1290  if (map_afrom_attr_str(request, &map, fmt_vb->vb_strvalue, &attr_rules, &attr_rules) < 0) {
1291  RPEDEBUG("Failed parsing \"%s\" as map", fmt_vb->vb_strvalue);
1292  return XLAT_ACTION_FAIL;
1293  }
1294 
1295  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_INT8, NULL));
1296  vb->vb_int8 = 0; /* Default fail value - changed to 1 on success */
1297  fr_dcursor_append(out, vb);
1298 
1299  switch (map->lhs->type) {
1300  case TMPL_TYPE_ATTR:
1301  case TMPL_TYPE_XLAT:
1302  break;
1303 
1304  default:
1305  REDEBUG("Unexpected type %s in left hand side of expression",
1306  tmpl_type_to_str(map->lhs->type));
1307  return XLAT_ACTION_FAIL;
1308  }
1309 
1310  switch (map->rhs->type) {
1311  case TMPL_TYPE_ATTR:
1312  case TMPL_TYPE_EXEC:
1313  case TMPL_TYPE_DATA:
1316  case TMPL_TYPE_XLAT:
1317  break;
1318 
1319  default:
1320  REDEBUG("Unexpected type %s in right hand side of expression",
1321  tmpl_type_to_str(map->rhs->type));
1322  return XLAT_ACTION_FAIL;
1323  }
1324 
1325  RINDENT();
1326  ret = map_to_request(request, map, map_to_vp, NULL);
1327  REXDENT();
1328  talloc_free(map);
1329  if (ret < 0) return XLAT_ACTION_FAIL;
1330 
1331  vb->vb_int8 = 1;
1332  return XLAT_ACTION_DONE;
1333 }
1334 
1335 
1337  { .required = true, .concat = true, .type = FR_TYPE_STRING },
1339 };
1340 
1341 /** Calculate number of seconds until the next n hour(s), day(s), week(s), year(s).
1342  *
1343  * For example, if it were 16:18 %nexttime(1h) would expand to 2520.
1344  *
1345  * The envisaged usage for this function is to limit sessions so that they don't
1346  * cross billing periods. The output of the xlat should be combined with %rand() to create
1347  * some jitter, unless the desired effect is every subscriber on the network
1348  * re-authenticating at the same time.
1349  *
1350  * @ingroup xlat_functions
1351  */
1353  UNUSED xlat_ctx_t const *xctx,
1354  request_t *request, fr_value_box_list_t *args)
1355 {
1356  long num;
1357 
1358  char const *p;
1359  char *q;
1360  time_t now;
1361  struct tm *local, local_buff;
1362  fr_value_box_t *in_head;
1363  fr_value_box_t *vb;
1364 
1365  XLAT_ARGS(args, &in_head);
1366 
1367  /*
1368  * We want to limit based on _now_, not on when they logged in.
1369  */
1370  now = time(NULL);
1371  local = localtime_r(&now, &local_buff);
1372 
1373  p = in_head->vb_strvalue;
1374 
1375  num = strtoul(p, &q, 10);
1376  if (!q || *q == '\0') {
1377  REDEBUG("nexttime: <int> must be followed by period specifier (h|d|w|m|y)");
1378  return XLAT_ACTION_FAIL;
1379  }
1380 
1381  if (p == q) {
1382  num = 1;
1383  } else {
1384  p += q - p;
1385  }
1386 
1387  local->tm_sec = 0;
1388  local->tm_min = 0;
1389 
1390  switch (*p) {
1391  case 'h':
1392  local->tm_hour += num;
1393  break;
1394 
1395  case 'd':
1396  local->tm_hour = 0;
1397  local->tm_mday += num;
1398  break;
1399 
1400  case 'w':
1401  local->tm_hour = 0;
1402  local->tm_mday += (7 - local->tm_wday) + (7 * (num-1));
1403  break;
1404 
1405  case 'm':
1406  local->tm_hour = 0;
1407  local->tm_mday = 1;
1408  local->tm_mon += num;
1409  break;
1410 
1411  case 'y':
1412  local->tm_hour = 0;
1413  local->tm_mday = 1;
1414  local->tm_mon = 0;
1415  local->tm_year += num;
1416  break;
1417 
1418  default:
1419  REDEBUG("nexttime: Invalid period specifier '%c', must be h|d|w|m|y", *p);
1420  return XLAT_ACTION_FAIL;
1421  }
1422 
1423  MEM(vb = fr_value_box_alloc_null(ctx));
1424  fr_value_box_uint64(vb, NULL, (uint64_t)(mktime(local) - now), false);
1425  fr_dcursor_append(out, vb);
1426  return XLAT_ACTION_DONE;
1427 }
1428 
1429 typedef struct {
1433 
1434 /** Just serves to push the result up the stack
1435  *
1436  */
1438  xlat_ctx_t const *xctx,
1439  UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
1440 {
1441  xlat_eval_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_eval_rctx_t);
1443 
1444  talloc_free(rctx);
1445 
1446  return xa;
1447 }
1448 
1449 typedef struct {
1450  fr_dict_t const *namespace; //!< Namespace we use for evaluating runtime expansions
1452 
1454 {
1455  xlat_eval_inst_t *inst = talloc_get_type_abort(xctx->inst, xlat_eval_inst_t);
1456 
1457  inst->namespace = xctx->ex->call.dict;
1458 
1459  return 0;
1460 }
1461 
1463  { .required = true, .concat = true, .type = FR_TYPE_STRING },
1465 };
1466 
1467 /** Dynamically evaluate an expansion string
1468  *
1469  * @ingroup xlat_functions
1470  */
1472  xlat_ctx_t const *xctx,
1473  request_t *request, fr_value_box_list_t *args)
1474 {
1476 
1477  /*
1478  * These are escaping rules applied to the
1479  * input string. They're mostly here to
1480  * allow \% and \\ to work.
1481  *
1482  * Everything else should be passed in as
1483  * unescaped data.
1484  */
1485  static fr_sbuff_unescape_rules_t const escape_rules = {
1486  .name = "xlat",
1487  .chr = '\\',
1488  .subs = {
1489  ['%'] = '%',
1490  ['\\'] = '\\',
1491  },
1492  .do_hex = false,
1493  .do_oct = false
1494  };
1495 
1496  xlat_eval_rctx_t *rctx;
1497  fr_value_box_t *arg = fr_value_box_list_head(args);
1498 
1499  XLAT_ARGS(args, &arg);
1500 
1501  MEM(rctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), xlat_eval_rctx_t));
1502 
1503  /*
1504  * Parse the input as a literal expansion
1505  */
1506  if (xlat_tokenize(rctx,
1507  &rctx->ex,
1508  &FR_SBUFF_IN(arg->vb_strvalue, arg->vb_length),
1509  &(fr_sbuff_parse_rules_t){
1510  .escapes = &escape_rules
1511  },
1512  &(tmpl_rules_t){
1513  .attr = {
1514  .dict_def = inst->namespace,
1515  .list_def = request_attr_request,
1516  .allow_unknown = false,
1517  .allow_unresolved = false,
1518  .allow_foreign = false,
1519  },
1520  .xlat = {
1521  .runtime_el = unlang_interpret_event_list(request),
1522  },
1523  .at_runtime = true
1524  }, 0) < 0) {
1525  RPEDEBUG("Failed parsing expansion");
1526  error:
1527  talloc_free(rctx);
1528  return XLAT_ACTION_FAIL;
1529  }
1530 
1531  /*
1532  * Call the resolution function so we produce
1533  * good errors about what function was
1534  * unresolved.
1535  */
1536  if (rctx->ex->flags.needs_resolving &&
1537  (xlat_resolve(rctx->ex, &(xlat_res_rules_t){ .allow_unresolved = false }) < 0)) {
1538  RPEDEBUG("Unresolved expansion functions in expansion");
1539  goto error;
1540 
1541  }
1542 
1543  if (unlang_xlat_yield(request, xlat_eval_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
1544 
1545  if (unlang_xlat_push(ctx, &rctx->last_success, (fr_value_box_list_t *)out->dlist,
1546  request, rctx->ex, UNLANG_SUB_FRAME) < 0) goto error;
1547 
1548  return XLAT_ACTION_PUSH_UNLANG;
1549 }
1550 
1552  { .required = true, .type = FR_TYPE_STRING },
1553  { .required = true, .single = true, .type = FR_TYPE_UINT64 },
1554  { .concat = true, .type = FR_TYPE_STRING },
1556 };
1557 
1558 /** lpad a string
1559  *
1560 @verbatim
1561 %lpad(%{Attribute-Name}, <length> [, <fill>])
1562 @endverbatim
1563  *
1564  * Example: (User-Name = "foo")
1565 @verbatim
1566 %lpad(%{User-Name}, 5 'x') == "xxfoo"
1567 @endverbatim
1568  *
1569  * @ingroup xlat_functions
1570  */
1572  UNUSED xlat_ctx_t const *xctx,
1573  request_t *request, fr_value_box_list_t *args)
1574 {
1575  fr_value_box_t *values;
1576  fr_value_box_t *pad;
1578 
1579  fr_value_box_list_t *list;
1580 
1581  size_t pad_len;
1582 
1583  char const *fill_str = NULL;
1584  size_t fill_len = 0;
1585 
1586  fr_value_box_t *in = NULL;
1587 
1588  XLAT_ARGS(args, &values, &pad, &fill);
1589 
1590  /* coverity[dereference] */
1591  list = &values->vb_group;
1592  /* coverity[dereference] */
1593  pad_len = (size_t)pad->vb_uint64;
1594 
1595  /*
1596  * Fill is optional
1597  */
1598  if (fill) {
1599  fill_str = fill->vb_strvalue;
1600  fill_len = talloc_array_length(fill_str) - 1;
1601  }
1602 
1603  if (fill_len == 0) {
1604  fill_str = " ";
1605  fill_len = 1;
1606  }
1607 
1608  while ((in = fr_value_box_list_pop_head(list))) {
1609  size_t len = talloc_array_length(in->vb_strvalue) - 1;
1610  size_t remaining;
1611  char *buff;
1612  fr_sbuff_t sbuff;
1613  fr_sbuff_marker_t m_data;
1614 
1616 
1617  if (len >= pad_len) continue;
1618 
1619  if (fr_value_box_bstr_realloc(in, &buff, in, pad_len) < 0) {
1620  RPEDEBUG("Failed reallocing input data");
1621  return XLAT_ACTION_FAIL;
1622  }
1623 
1624  fr_sbuff_init_in(&sbuff, buff, pad_len);
1625  fr_sbuff_marker(&m_data, &sbuff);
1626 
1627  /*
1628  * ...nothing to move if the input
1629  * string is empty.
1630  */
1631  if (len > 0) {
1632  fr_sbuff_advance(&m_data, pad_len - len); /* Mark where we want the data to go */
1633  fr_sbuff_move(&FR_SBUFF(&m_data), &FR_SBUFF(&sbuff), len); /* Shift the data */
1634  }
1635 
1636  if (fill_len == 1) {
1637  memset(fr_sbuff_current(&sbuff), *fill_str, fr_sbuff_ahead(&m_data));
1638  continue;
1639  }
1640 
1641  /*
1642  * Copy fill as a repeating pattern
1643  */
1644  while ((remaining = fr_sbuff_ahead(&m_data))) {
1645  size_t to_copy = remaining >= fill_len ? fill_len : remaining;
1646  memcpy(fr_sbuff_current(&sbuff), fill_str, to_copy); /* avoid \0 termination */
1647  fr_sbuff_advance(&sbuff, to_copy);
1648  }
1649  fr_sbuff_set_to_end(&sbuff);
1650  fr_sbuff_terminate(&sbuff); /* Move doesn't re-terminate */
1651  }
1652 
1653  return XLAT_ACTION_DONE;
1654 }
1655 
1656 /** Right pad a string
1657  *
1658 @verbatim
1659 %rpad(%{Attribute-Name}, <length> [, <fill>])
1660 @endverbatim
1661  *
1662  * Example: (User-Name = "foo")
1663 @verbatim
1664 %rpad(%{User-Name}, 5 'x') == "fooxx"
1665 @endverbatim
1666  *
1667  * @ingroup xlat_functions
1668  */
1670  UNUSED xlat_ctx_t const *xctx,
1671  request_t *request, fr_value_box_list_t *args)
1672 {
1673  fr_value_box_t *values;
1674  fr_value_box_list_t *list;
1675  fr_value_box_t *pad;
1676  /* coverity[dereference] */
1677  size_t pad_len;
1679  char const *fill_str = NULL;
1680  size_t fill_len = 0;
1681 
1682  fr_value_box_t *in = NULL;
1683 
1684  XLAT_ARGS(args, &values, &pad, &fill);
1685 
1686  list = &values->vb_group;
1687  pad_len = (size_t)pad->vb_uint64;
1688 
1689  /*
1690  * Fill is optional
1691  */
1692  if (fill) {
1693  fill_str = fill->vb_strvalue;
1694  fill_len = talloc_array_length(fill_str) - 1;
1695  }
1696 
1697  if (fill_len == 0) {
1698  fill_str = " ";
1699  fill_len = 1;
1700  }
1701 
1702  while ((in = fr_value_box_list_pop_head(list))) {
1703  size_t len = talloc_array_length(in->vb_strvalue) - 1;
1704  size_t remaining;
1705  char *buff;
1706  fr_sbuff_t sbuff;
1707 
1709 
1710  if (len >= pad_len) continue;
1711 
1712  if (fr_value_box_bstr_realloc(in, &buff, in, pad_len) < 0) {
1713  fail:
1714  RPEDEBUG("Failed reallocing input data");
1715  return XLAT_ACTION_FAIL;
1716  }
1717 
1718  fr_sbuff_init_in(&sbuff, buff, pad_len);
1719  fr_sbuff_advance(&sbuff, len);
1720 
1721  if (fill_len == 1) {
1722  memset(fr_sbuff_current(&sbuff), *fill_str, fr_sbuff_remaining(&sbuff));
1723  continue;
1724  }
1725 
1726  /*
1727  * Copy fill as a repeating pattern
1728  */
1729  while ((remaining = fr_sbuff_remaining(&sbuff))) {
1730  if (fr_sbuff_in_bstrncpy(&sbuff, fill_str, remaining >= fill_len ? fill_len : remaining) < 0) {
1731  goto fail;
1732  }
1733  }
1734  }
1735 
1736  return XLAT_ACTION_DONE;
1737 }
1738 
1740  { .required = true, .concat = true, .type = FR_TYPE_OCTETS },
1742 };
1743 
1744 /** Encode string or attribute as base64
1745  *
1746  * Example:
1747 @verbatim
1748 %base64.encode("foo") == "Zm9v"
1749 @endverbatim
1750  *
1751  * @ingroup xlat_functions
1752  */
1754  UNUSED xlat_ctx_t const *xctx,
1755  request_t *request, fr_value_box_list_t *args)
1756 {
1757  size_t alen;
1758  ssize_t elen;
1759  char *buff;
1760  fr_value_box_t *vb;
1761  fr_value_box_t *in;
1762 
1763  XLAT_ARGS(args, &in);
1764 
1765  alen = FR_BASE64_ENC_LENGTH(in->vb_length);
1766 
1767  MEM(vb = fr_value_box_alloc_null(ctx));
1768  if (fr_value_box_bstr_alloc(vb, &buff, vb, NULL, alen, false) < 0) {
1769  talloc_free(vb);
1770  return XLAT_ACTION_FAIL;
1771  }
1772 
1773  elen = fr_base64_encode(&FR_SBUFF_OUT(buff, talloc_array_length(buff)),
1774  &FR_DBUFF_TMP(in->vb_octets, in->vb_length), true);
1775  if (elen < 0) {
1776  RPEDEBUG("Base64 encoding failed");
1777  talloc_free(vb);
1778  return XLAT_ACTION_FAIL;
1779  }
1780  fr_assert((size_t)elen <= alen);
1781  vb->tainted = in->tainted;
1783  fr_dcursor_append(out, vb);
1784 
1785  return XLAT_ACTION_DONE;
1786 }
1787 
1789  { .required = true, .concat = true, .type = FR_TYPE_OCTETS },
1791 };
1792 
1793 /** Decode base64 string
1794  *
1795  * Example:
1796 @verbatim
1797 %base64.decode("Zm9v") == "foo"
1798 @endverbatim
1799  *
1800  * @ingroup xlat_functions
1801  */
1803  UNUSED xlat_ctx_t const *xctx,
1804  request_t *request, fr_value_box_list_t *args)
1805 {
1806  size_t alen;
1807  ssize_t declen = 0;
1808  uint8_t *decbuf;
1809  fr_value_box_t *vb;
1810  fr_value_box_t *in;
1811 
1812  XLAT_ARGS(args, &in);
1813 
1814  /*
1815  * Pass empty arguments through
1816  *
1817  * FR_BASE64_DEC_LENGTH produces 2 for empty strings...
1818  */
1819  if (in->vb_length == 0) {
1820  fr_value_box_list_remove(args, in);
1822  return XLAT_ACTION_DONE;
1823  }
1824 
1825  alen = FR_BASE64_DEC_LENGTH(in->vb_length);
1826  MEM(vb = fr_value_box_alloc_null(ctx));
1827  if (alen > 0) {
1828  MEM(fr_value_box_mem_alloc(vb, &decbuf, vb, NULL, alen, in->tainted) == 0);
1829  declen = fr_base64_decode(&FR_DBUFF_TMP(decbuf, alen),
1830  &FR_SBUFF_IN(in->vb_strvalue, in->vb_length), true, true);
1831  if (declen < 0) {
1832  RPEDEBUG("Base64 string invalid");
1833  talloc_free(vb);
1834  return XLAT_ACTION_FAIL;
1835  }
1836 
1837  MEM(fr_value_box_mem_realloc(vb, NULL, vb, declen) == 0);
1838  }
1839 
1840  vb->tainted = in->tainted;
1842  fr_dcursor_append(out, vb);
1843 
1844  return XLAT_ACTION_DONE;
1845 }
1846 
1848  { .required = true, .type = FR_TYPE_STRING },
1850 };
1851 
1852 /** Convert hex string to binary
1853  *
1854  * Example:
1855 @verbatim
1856 %bin("666f6f626172") == "foobar"
1857 @endverbatim
1858  *
1859  * @see #xlat_func_hex
1860  *
1861  * @ingroup xlat_functions
1862  */
1863 static xlat_action_t xlat_func_bin(TALLOC_CTX *ctx, fr_dcursor_t *out,
1864  UNUSED xlat_ctx_t const *xctx,
1865  request_t *request, fr_value_box_list_t *args)
1866 {
1867  fr_value_box_t *result;
1868  char const *p, *end;
1869  uint8_t *bin;
1870  size_t len, outlen;
1872  fr_value_box_t *list, *hex;
1873 
1874  XLAT_ARGS(args, &list);
1875 
1876  while ((hex = fr_value_box_list_pop_head(&list->vb_group))) {
1877  len = hex->vb_length;
1878  if ((len > 1) && (len & 0x01)) {
1879  REDEBUG("Input data length must be >1 and even, got %zu", len);
1880  return XLAT_ACTION_FAIL;
1881  }
1882 
1883  p = hex->vb_strvalue;
1884  end = p + len;
1885 
1886  /*
1887  * Look for 0x at the start of the string
1888  */
1889  if ((p[0] == '0') && (p[1] == 'x')) {
1890  p += 2;
1891  len -=2;
1892  }
1893 
1894  /*
1895  * Zero length octets string
1896  */
1897  if (p == end) continue;
1898 
1899  outlen = len / 2;
1900 
1901  MEM(result = fr_value_box_alloc_null(ctx));
1902  MEM(fr_value_box_mem_alloc(result, &bin, result, NULL, outlen, fr_value_box_list_tainted(args)) == 0);
1903  fr_base16_decode(&err, &FR_DBUFF_TMP(bin, outlen), &FR_SBUFF_IN(p, end - p), true);
1904  if (err) {
1905  REDEBUG2("Invalid hex string");
1906  talloc_free(result);
1907  return XLAT_ACTION_FAIL;
1908  }
1909 
1910  fr_dcursor_append(out, result);
1911  }
1912 
1913  return XLAT_ACTION_DONE;
1914 }
1915 
1917  { .required = true, .single = true, .type = FR_TYPE_VOID },
1918  { .type = FR_TYPE_VOID },
1919  { .variadic = XLAT_ARG_VARIADIC_EMPTY_KEEP, .type = FR_TYPE_VOID },
1921 };
1922 
1923 /** Cast one or more output value-boxes to the given type
1924  *
1925  * First argument of is type to cast to.
1926  *
1927  * Example:
1928 @verbatim
1929 %cast('string', %{request[*]}) results in all of the input boxes being cast to string/
1930 @endverbatim
1931  *
1932  * @ingroup xlat_functions
1933  */
1935  UNUSED xlat_ctx_t const *xctx,
1936  request_t *request, fr_value_box_list_t *args)
1937 {
1939  fr_value_box_t *arg;
1940  fr_type_t type;
1941 
1942  XLAT_ARGS(args, &name);
1943 
1944  /*
1945  * Get the type, which can be in one of a few formats.
1946  */
1947  if (fr_type_is_numeric(name->type)) {
1949  RPEDEBUG("Failed parsing '%pV' as a numerical data type", name);
1950  return XLAT_ACTION_FAIL;
1951  }
1952  type = name->vb_uint8;
1953 
1954  } else {
1955  if (name->type != FR_TYPE_STRING) {
1957  RPEDEBUG("Failed parsing '%pV' as a string data type", name);
1958  return XLAT_ACTION_FAIL;
1959  }
1960  }
1961 
1963  if (type == FR_TYPE_NULL) {
1964  RDEBUG("Unknown data type '%s'", name->vb_strvalue);
1965  return XLAT_ACTION_FAIL;
1966  }
1967  }
1968 
1969  (void) fr_value_box_list_pop_head(args);
1970 
1971  /*
1972  * When we cast nothing to a string / octets, the result is an empty string/octets.
1973  */
1974  if (unlikely(!fr_value_box_list_head(args))) {
1975  if ((type == FR_TYPE_STRING) || (type == FR_TYPE_OCTETS)) {
1976  fr_value_box_t *dst;
1977 
1978  MEM(dst = fr_value_box_alloc(ctx, type, NULL));
1979  fr_dcursor_append(out, dst);
1980  VALUE_BOX_LIST_VERIFY((fr_value_box_list_t *)out->dlist);
1981 
1982  return XLAT_ACTION_DONE;
1983  }
1984 
1985  RDEBUG("No data for cast to '%s'", fr_type_to_str(type));
1986  return XLAT_ACTION_FAIL;
1987  }
1988 
1989  /*
1990  * Cast to string means *print* to string.
1991  */
1992  if (type == FR_TYPE_STRING) {
1993  fr_sbuff_t *agg;
1994  fr_value_box_t *dst;
1995 
1996  talloc_free(name);
1997 
1998  FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 256, SIZE_MAX);
1999 
2000  MEM(dst = fr_value_box_alloc_null(ctx));
2001  if (fr_value_box_list_concat_as_string(NULL, NULL, agg, args, NULL, 0, NULL,
2002  FR_VALUE_BOX_LIST_FREE_BOX, true) < 0) {
2003  RPEDEBUG("Failed concatenating string");
2004  return XLAT_ACTION_FAIL;
2005  }
2006 
2007  fr_value_box_bstrndup(dst, dst, NULL, fr_sbuff_start(agg), fr_sbuff_used(agg), false);
2008  fr_dcursor_append(out, dst);
2009  VALUE_BOX_LIST_VERIFY((fr_value_box_list_t *)out->dlist);
2010 
2011  return XLAT_ACTION_DONE;
2012  }
2013 
2014  /*
2015  * Copy inputs to outputs, casting them along the way.
2016  */
2017  arg = NULL;
2018  while ((arg = fr_value_box_list_next(args, arg)) != NULL) {
2019  fr_value_box_t *vb, *p;
2020 
2021  fr_assert(arg->type == FR_TYPE_GROUP);
2022 
2023  vb = fr_value_box_list_head(&arg->vb_group);
2024  while (vb) {
2025  p = fr_value_box_list_remove(&arg->vb_group, vb);
2026 
2027  if (fr_value_box_cast_in_place(vb, vb, type, NULL) < 0) {
2028  RPEDEBUG("Failed casting %pV to data type '%s'", vb, fr_type_to_str(type));
2029  return XLAT_ACTION_FAIL;
2030  }
2031  fr_dcursor_append(out, vb);
2032  vb = fr_value_box_list_next(&arg->vb_group, p);
2033  }
2034  }
2035  VALUE_BOX_LIST_VERIFY((fr_value_box_list_t *)out->dlist);
2036 
2037  return XLAT_ACTION_DONE;
2038 }
2039 
2041  { .required = true, .type = FR_TYPE_VOID },
2042  { .concat = true, .type = FR_TYPE_STRING },
2044 };
2045 
2046 /** Concatenate string representation of values of given attributes using separator
2047  *
2048  * First argument of is the list of attributes to concatenate, followed
2049  * by an optional separator
2050  *
2051  * Example:
2052 @verbatim
2053 %concat(%{request.[*]}, ',') == "<attr1value>,<attr2value>,<attr3value>,..."
2054 %concat(%{Tmp-String-0[*]}, '. ') == "<str1value>. <str2value>. <str3value>. ..."
2055 %concat(%join(%{User-Name}, %{Calling-Station-Id}), ', ') == "bob, aa:bb:cc:dd:ee:ff"
2056 @endverbatim
2057  *
2058  * @ingroup xlat_functions
2059  */
2061  UNUSED xlat_ctx_t const *xctx,
2062  request_t *request, fr_value_box_list_t *args)
2063 {
2064  fr_value_box_t *result;
2065  fr_value_box_t *list;
2066  fr_value_box_t *separator;
2067  fr_value_box_list_t *to_concat;
2068  char *buff;
2069  char const *sep;
2070 
2071  XLAT_ARGS(args, &list, &separator);
2072 
2073  sep = (separator) ? separator->vb_strvalue : "";
2074  to_concat = &list->vb_group;
2075 
2076  result = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL);
2077  if (!result) {
2078  error:
2079  RPEDEBUG("Failed concatenating input");
2080  return XLAT_ACTION_FAIL;
2081  }
2082 
2083  buff = fr_value_box_list_aprint(result, to_concat, sep, NULL);
2084  if (!buff) goto error;
2085 
2087 
2088  fr_dcursor_append(out, result);
2089 
2090  return XLAT_ACTION_DONE;
2091 }
2092 
2094  { .required = true, .type = FR_TYPE_OCTETS },
2096 };
2097 
2098 /** Print data as hex, not as VALUE.
2099  *
2100  * Example:
2101 @verbatim
2102 %hex("foobar") == "666f6f626172"
2103 @endverbatim
2104  *
2105  * @see #xlat_func_bin
2106  *
2107  * @ingroup xlat_functions
2108  */
2110  UNUSED xlat_ctx_t const *xctx,
2111  UNUSED request_t *request, fr_value_box_list_t *args)
2112 {
2113  char *new_buff;
2114  fr_value_box_t *list, *bin;
2115 
2116  XLAT_ARGS(args, &list);
2117 
2118  while ((bin = fr_value_box_list_pop_head(&list->vb_group))) {
2119  /*
2120  * Use existing box, but with new buffer
2121  */
2122  MEM(new_buff = talloc_zero_array(bin, char, (bin->vb_length * 2) + 1));
2123  if (bin->vb_length) {
2124  fr_base16_encode(&FR_SBUFF_OUT(new_buff, (bin->vb_length * 2) + 1),
2125  &FR_DBUFF_TMP(bin->vb_octets, bin->vb_length));
2127  fr_value_box_strdup_shallow(bin, NULL, new_buff, bin->tainted);
2128  /*
2129  * Zero length binary > zero length hex string
2130  */
2131  } else {
2133  fr_value_box_strdup(bin, bin, NULL, "", bin->tainted);
2134  }
2135  fr_dcursor_append(out, bin);
2136  }
2137 
2138  return XLAT_ACTION_DONE;
2139 }
2140 
2141 typedef enum {
2143  HMAC_SHA1
2145 
2146 static xlat_action_t xlat_hmac(TALLOC_CTX *ctx, fr_dcursor_t *out,
2147  fr_value_box_list_t *args, uint8_t *digest, int digest_len, hmac_type type)
2148 {
2149  fr_value_box_t *vb, *data, *key;
2150 
2151  XLAT_ARGS(args, &data, &key);
2152 
2153  if (type == HMAC_MD5) {
2154  /* coverity[dereference] */
2155  fr_hmac_md5(digest, data->vb_octets, data->vb_length, key->vb_octets, key->vb_length);
2156  } else if (type == HMAC_SHA1) {
2157  /* coverity[dereference] */
2158  fr_hmac_sha1(digest, data->vb_octets, data->vb_length, key->vb_octets, key->vb_length);
2159  }
2160 
2161  MEM(vb = fr_value_box_alloc_null(ctx));
2162  fr_value_box_memdup(vb, vb, NULL, digest, digest_len, false);
2163 
2164  fr_dcursor_append(out, vb);
2165 
2166  return XLAT_ACTION_DONE;
2167 }
2168 
2170  { .required = true, .concat = true, .type = FR_TYPE_STRING },
2171  { .required = true, .concat = true, .type = FR_TYPE_STRING },
2173 };
2174 
2175 /** Generate the HMAC-MD5 of a string or attribute
2176  *
2177  * Example:
2178 @verbatim
2179 %hmacmd5('foo', 'bar') == "0x31b6db9e5eb4addb42f1a6ca07367adc"
2180 @endverbatim
2181  *
2182  * @ingroup xlat_functions
2183  */
2185  UNUSED xlat_ctx_t const *xctx,
2186  UNUSED request_t *request, fr_value_box_list_t *in)
2187 {
2188  uint8_t digest[MD5_DIGEST_LENGTH];
2189  return xlat_hmac(ctx, out, in, digest, MD5_DIGEST_LENGTH, HMAC_MD5);
2190 }
2191 
2192 
2193 /** Generate the HMAC-SHA1 of a string or attribute
2194  *
2195  * Example:
2196 @verbatim
2197 %hmacsha1('foo', 'bar') == "0x85d155c55ed286a300bd1cf124de08d87e914f3a"
2198 @endverbatim
2199  *
2200  * @ingroup xlat_functions
2201  */
2203  UNUSED xlat_ctx_t const *xctx,
2204  UNUSED request_t *request, fr_value_box_list_t *in)
2205 {
2206  uint8_t digest[SHA1_DIGEST_LENGTH];
2207  return xlat_hmac(ctx, out, in, digest, SHA1_DIGEST_LENGTH, HMAC_SHA1);
2208 }
2209 
2211  { .required = true, .type = FR_TYPE_VOID },
2212  { .variadic = XLAT_ARG_VARIADIC_EMPTY_SQUASH, .type = FR_TYPE_VOID },
2214 };
2215 
2216 /** Join a series of arguments to form a single list
2217  *
2218  * null boxes are not preserved.
2219  */
2221  UNUSED xlat_ctx_t const *xctx,
2222  UNUSED request_t *request, fr_value_box_list_t *in)
2223 {
2225  fr_assert(arg->type == FR_TYPE_GROUP);
2226 
2227  fr_value_box_list_foreach_safe(&arg->vb_group, vb) {
2228  fr_value_box_list_remove(&arg->vb_group, vb);
2229  fr_dcursor_append(out, vb);
2230  }}
2231  }
2232  return XLAT_ACTION_DONE;
2233 }
2234 
2235 static void ungroup(fr_dcursor_t *out, fr_value_box_list_t *in)
2236 {
2237  fr_value_box_t *vb;
2238 
2239  while ((vb = fr_value_box_list_pop_head(in)) != NULL) {
2240  if (vb->type != FR_TYPE_GROUP) {
2241  fr_dcursor_append(out, vb);
2242  continue;
2243  }
2244  talloc_free(vb);
2245  }
2246 }
2247 
2248 /** Ungroups all of its arguments into one flat list.
2249  *
2250  */
2252  UNUSED xlat_ctx_t const *xctx,
2253  UNUSED request_t *request, fr_value_box_list_t *in)
2254 {
2255  fr_value_box_t *arg = NULL;
2256 
2257  while ((arg = fr_value_box_list_next(in, arg)) != NULL) {
2258  fr_assert(arg->type == FR_TYPE_GROUP);
2259 
2260  ungroup(out, &arg->vb_group);
2261  }
2262  return XLAT_ACTION_DONE;
2263 }
2264 
2266  { .single = true, .variadic = XLAT_ARG_VARIADIC_EMPTY_KEEP, .type = FR_TYPE_VOID },
2268 };
2269 
2270 /** Return the on-the-wire size of the boxes in bytes
2271  *
2272  * skips null values
2273  *
2274  * Example:
2275 @verbatim
2276 %length(foobar) == 6
2277 %length(%bin("0102030005060708")) == 8
2278 @endverbatim
2279  *
2280  * @see #xlat_func_strlen
2281  *
2282  * @ingroup xlat_functions
2283  */
2285  UNUSED xlat_ctx_t const *xctx,
2286  UNUSED request_t *request, fr_value_box_list_t *in)
2287 
2288 {
2290  fr_value_box_t *my;
2291 
2292  MEM(my = fr_value_box_alloc(ctx, FR_TYPE_SIZE, NULL));
2293  if (!fr_type_is_null(vb->type)) my->vb_size = fr_value_box_network_length(vb);
2294  fr_dcursor_append(out, my);
2295  }
2296 
2297  return XLAT_ACTION_DONE;
2298 }
2299 
2300 
2302  { .concat = true, .type = FR_TYPE_OCTETS },
2304 };
2305 
2306 /** Calculate the MD4 hash of a string or attribute.
2307  *
2308  * Example:
2309 @verbatim
2310 %md4("foo") == "0ac6700c491d70fb8650940b1ca1e4b2"
2311 @endverbatim
2312  *
2313  * @ingroup xlat_functions
2314  */
2315 static xlat_action_t xlat_func_md4(TALLOC_CTX *ctx, fr_dcursor_t *out,
2316  UNUSED xlat_ctx_t const *xctx,
2317  UNUSED request_t *request, fr_value_box_list_t *args)
2318 {
2319  uint8_t digest[MD4_DIGEST_LENGTH];
2320  fr_value_box_t *vb;
2321  fr_value_box_t *in_head;
2322 
2323  XLAT_ARGS(args, &in_head);
2324 
2325  if (in_head) {
2326  fr_md4_calc(digest, in_head->vb_octets, in_head->vb_length);
2327  } else {
2328  /* Digest of empty string */
2329  fr_md4_calc(digest, NULL, 0);
2330  }
2331 
2332  MEM(vb = fr_value_box_alloc_null(ctx));
2333  fr_value_box_memdup(vb, vb, NULL, digest, sizeof(digest), false);
2334 
2335  fr_dcursor_append(out, vb);
2336  VALUE_BOX_LIST_VERIFY((fr_value_box_list_t *)out->dlist);
2337 
2338  return XLAT_ACTION_DONE;
2339 }
2340 
2342  { .concat = true, .type = FR_TYPE_OCTETS },
2344 };
2345 
2346 /** Calculate the MD5 hash of a string or attribute.
2347  *
2348  * Example:
2349 @verbatim
2350 %md5("foo") == "acbd18db4cc2f85cedef654fccc4a4d8"
2351 @endverbatim
2352  *
2353  * @ingroup xlat_functions
2354  */
2355 static xlat_action_t xlat_func_md5(TALLOC_CTX *ctx, fr_dcursor_t *out,
2356  UNUSED xlat_ctx_t const *xctx,
2357  UNUSED request_t *request, fr_value_box_list_t *args)
2358 {
2359  uint8_t digest[MD5_DIGEST_LENGTH];
2360  fr_value_box_t *vb;
2361  fr_value_box_t *in_head;
2362 
2363  XLAT_ARGS(args, &in_head);
2364 
2365  if (in_head) {
2366  fr_md5_calc(digest, in_head->vb_octets, in_head->vb_length);
2367  } else {
2368  /* Digest of empty string */
2369  fr_md5_calc(digest, NULL, 0);
2370  }
2371 
2372  MEM(vb = fr_value_box_alloc_null(ctx));
2373  fr_value_box_memdup(vb, vb, NULL, digest, sizeof(digest), false);
2374 
2375  fr_dcursor_append(out, vb);
2376 
2377  return XLAT_ACTION_DONE;
2378 }
2379 
2380 
2382  { .required = true, .single = true, .type = FR_TYPE_STRING },
2384 };
2385 
2386 /** Encode attributes as a series of string attribute/value pairs
2387  *
2388  * This is intended to serialize one or more attributes as a comma
2389  * delimited string.
2390  *
2391  * Example:
2392 @verbatim
2393 %pairs(request.[*]) == 'User-Name = "foo"User-Password = "bar"'
2394 %concat(%pairs(request.[*]), ', ') == 'User-Name = "foo", User-Password = "bar"'
2395 @endverbatim
2396  *
2397  * @see #xlat_func_concat
2398  *
2399  * @ingroup xlat_functions
2400  */
2402  UNUSED xlat_ctx_t const *xctx,
2403  request_t *request, fr_value_box_list_t *args)
2404 {
2405  tmpl_t *vpt = NULL;
2406  fr_dcursor_t cursor;
2407  tmpl_dcursor_ctx_t cc;
2408  fr_value_box_t *vb;
2409  fr_value_box_t *in_head;
2410 
2411  fr_pair_t *vp;
2412 
2413  XLAT_ARGS(args, &in_head);
2414 
2415  if (tmpl_afrom_attr_str(ctx, NULL, &vpt, in_head->vb_strvalue,
2416  &(tmpl_rules_t){
2417  .attr = {
2418  .dict_def = request->dict,
2419  .list_def = request_attr_request,
2420  .allow_wildcard = true,
2421  .prefix = TMPL_ATTR_REF_PREFIX_AUTO
2422  }
2423  }) <= 0) {
2424  RPEDEBUG("Invalid input");
2425  return XLAT_ACTION_FAIL;
2426  }
2427 
2428  for (vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt);
2429  vp;
2430  vp = fr_dcursor_next(&cursor)) {
2431  char *buff;
2432 
2433  MEM(vb = fr_value_box_alloc_null(ctx));
2434  if (unlikely(fr_pair_aprint(vb, &buff, NULL, vp) < 0)) {
2435  RPEDEBUG("Failed printing pair");
2436  talloc_free(vb);
2437  tmpl_dcursor_clear(&cc);
2438  return XLAT_ACTION_FAIL;
2439  }
2440 
2441  fr_value_box_bstrdup_buffer_shallow(NULL, vb, NULL, buff, false);
2442  fr_dcursor_append(out, vb);
2443  }
2444  tmpl_dcursor_clear(&cc);
2445  talloc_free(vpt);
2446 
2447  return XLAT_ACTION_DONE;
2448 }
2449 
2451  { .required = true, .single = true, .type = FR_TYPE_UINT32 },
2453 };
2454 
2455 /** Generate a random integer value
2456  *
2457  * For "N = %rand(MAX)", 0 <= N < MAX
2458  *
2459  * Example:
2460 @verbatim
2461 %rand(100) == 42
2462 @endverbatim
2463  *
2464  * @ingroup xlat_functions
2465  */
2467  UNUSED xlat_ctx_t const *xctx,
2468  UNUSED request_t *request, fr_value_box_list_t *in)
2469 {
2470  int64_t result;
2471  fr_value_box_t *vb;
2472  fr_value_box_t *in_head = fr_value_box_list_head(in);
2473 
2474  result = in_head->vb_uint32;
2475 
2476  /* Make sure it isn't too big */
2477  if (result > (1 << 30)) result = (1 << 30);
2478 
2479  result *= fr_rand(); /* 0..2^32-1 */
2480  result >>= 32;
2481 
2482  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_UINT64, NULL));
2483  vb->vb_uint64 = result;
2484 
2485  fr_dcursor_append(out, vb);
2486 
2487  return XLAT_ACTION_DONE;
2488 }
2489 
2491  { .required = true, .concat = true, .type = FR_TYPE_STRING },
2493 };
2494 
2495 /** Generate a string of random chars
2496  *
2497  * Build strings of random chars, useful for generating tokens and passcodes
2498  * Format similar to String::Random.
2499  *
2500  * Format characters may include the following, and may be
2501  * preceded by a repetition count:
2502  * - "c" lowercase letters
2503  * - "C" uppercase letters
2504  * - "n" numbers
2505  * - "a" alphanumeric
2506  * - "!" punctuation
2507  * - "." alphanumeric + punctuation
2508  * - "s" alphanumeric + "./"
2509  * - "o" characters suitable for OTP (easily confused removed)
2510  * - "b" binary data
2511  *
2512  * Example:
2513 @verbatim
2514 %randstr("CCCC!!cccnnn") == "IPFL>{saf874"
2515 %randstr("42o") == "yHdupUwVbdHprKCJRYfGbaWzVwJwUXG9zPabdGAhM9"
2516 %hex(%randstr("bbbb")) == "a9ce04f3"
2517 %hex(%randstr("8b")) == "fe165529f9f66839"
2518 @endverbatim
2519  * @ingroup xlat_functions
2520  */
2522  UNUSED xlat_ctx_t const *xctx,
2523  request_t *request, fr_value_box_list_t *args)
2524 {
2525  /*
2526  * Lookup tables for randstr char classes
2527  */
2528  static char randstr_punc[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
2529  static char randstr_salt[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz/.";
2530 
2531  /*
2532  * Characters humans rarely confuse. Reduces char set considerably
2533  * should only be used for things such as one time passwords.
2534  */
2535  static char randstr_otp[] = "469ACGHJKLMNPQRUVWXYabdfhijkprstuvwxyz";
2536 
2537  char const *p, *start, *end;
2538  char *endptr;
2539  char *buff_p;
2540  unsigned int result;
2541  unsigned int reps;
2542  size_t outlen = 0;
2543  fr_value_box_t* vb;
2544  fr_value_box_t *in_head;
2545 
2546  XLAT_ARGS(args, &in_head);
2547 
2548  /** Max repetitions of a single character class
2549  *
2550  */
2551 #define REPETITION_MAX 1024
2552 
2553  start = p = in_head->vb_strvalue;
2554  end = p + in_head->vb_length;
2555 
2556  /*
2557  * Calculate size of output
2558  */
2559  while (p < end) {
2560  /*
2561  * Repetition modifiers.
2562  *
2563  * We limit it to REPETITION_MAX, because we don't want
2564  * utter stupidity.
2565  */
2566  if (isdigit((uint8_t) *p)) {
2567  reps = strtol(p, &endptr, 10);
2568  if (reps > REPETITION_MAX) reps = REPETITION_MAX;
2569  outlen += reps;
2570  p = endptr;
2571  } else {
2572  outlen++;
2573  }
2574  p++;
2575  }
2576 
2577  MEM(vb = fr_value_box_alloc_null(ctx));
2578  MEM(fr_value_box_bstr_alloc(vb, &buff_p, vb, NULL, outlen, false) == 0);
2579 
2580  /* Reset p to start position */
2581  p = start;
2582 
2583  while (p < end) {
2584  size_t i;
2585 
2586  if (isdigit((uint8_t) *p)) {
2587  reps = strtol(p, &endptr, 10);
2588  if (reps > REPETITION_MAX) {
2589  reps = REPETITION_MAX;
2590  RMARKER(L_WARN, L_DBG_LVL_2, start, start - p,
2591  "Forcing repetition to %u", (unsigned int)REPETITION_MAX);
2592  }
2593  p = endptr;
2594  } else {
2595  reps = 1;
2596  }
2597 
2598  for (i = 0; i < reps; i++) {
2599  result = fr_rand();
2600  switch (*p) {
2601  /*
2602  * Lowercase letters
2603  */
2604  case 'c':
2605  *buff_p++ = 'a' + (result % 26);
2606  break;
2607 
2608  /*
2609  * Uppercase letters
2610  */
2611  case 'C':
2612  *buff_p++ = 'A' + (result % 26);
2613  break;
2614 
2615  /*
2616  * Numbers
2617  */
2618  case 'n':
2619  *buff_p++ = '0' + (result % 10);
2620  break;
2621 
2622  /*
2623  * Alpha numeric
2624  */
2625  case 'a':
2626  *buff_p++ = randstr_salt[result % (sizeof(randstr_salt) - 3)];
2627  break;
2628 
2629  /*
2630  * Punctuation
2631  */
2632  case '!':
2633  *buff_p++ = randstr_punc[result % (sizeof(randstr_punc) - 1)];
2634  break;
2635 
2636  /*
2637  * Alpha numeric + punctuation
2638  */
2639  case '.':
2640  *buff_p++ = '!' + (result % 95);
2641  break;
2642 
2643  /*
2644  * Alpha numeric + salt chars './'
2645  */
2646  case 's':
2647  *buff_p++ = randstr_salt[result % (sizeof(randstr_salt) - 1)];
2648  break;
2649 
2650  /*
2651  * Chars suitable for One Time Password tokens.
2652  * Alpha numeric with easily confused char pairs removed.
2653  */
2654  case 'o':
2655  *buff_p++ = randstr_otp[result % (sizeof(randstr_otp) - 1)];
2656  break;
2657 
2658  /*
2659  * Binary data - Copy between 1-4 bytes at a time
2660  */
2661  case 'b':
2662  {
2663  size_t copy = (reps - i) > sizeof(result) ? sizeof(result) : reps - i;
2664 
2665  memcpy(buff_p, (uint8_t *)&result, copy);
2666  buff_p += copy;
2667  i += (copy - 1); /* Loop +1 */
2668  }
2669  break;
2670 
2671  default:
2672  REDEBUG("Invalid character class '%c'", *p);
2673  talloc_free(vb);
2674 
2675  return XLAT_ACTION_FAIL;
2676  }
2677  }
2678 
2679  p++;
2680  }
2681 
2682  *buff_p++ = '\0';
2683 
2684  fr_dcursor_append(out, vb);
2685 
2686  return XLAT_ACTION_DONE;
2687 }
2688 
2689 
2690 #if defined(HAVE_REGEX_PCRE) || defined(HAVE_REGEX_PCRE2)
2691 /** Get named subcapture value from previous regex
2692  *
2693  * Example:
2694 @verbatim
2695 if ("foo" =~ /^(?<name>.*)/) {
2696  noop
2697 }
2698 %regex(name) == "foo"
2699 @endverbatim
2700  *
2701  * @ingroup xlat_functions
2702  */
2703 static xlat_action_t xlat_func_regex(TALLOC_CTX *ctx, fr_dcursor_t *out,
2704  UNUSED xlat_ctx_t const *xctx,
2705  request_t *request, fr_value_box_list_t *in)
2706 {
2707  fr_value_box_t *in_head = fr_value_box_list_head(in);
2708 
2709  /*
2710  * Find the first child of the first argument group
2711  */
2712  fr_value_box_t *arg = fr_value_box_list_head(&in_head->vb_group);
2713 
2714  /*
2715  * Return the complete capture if no other capture is specified
2716  */
2717  if (!arg) {
2718  fr_value_box_t *vb;
2719  char *p;
2720 
2721  MEM(vb = fr_value_box_alloc_null(ctx));
2722  if (regex_request_to_sub(vb, &p, request, 0) < 0) {
2723  REDEBUG2("No previous regex capture");
2724  talloc_free(vb);
2725  return XLAT_ACTION_FAIL;
2726  }
2727 
2728  fr_assert(p);
2729  fr_value_box_bstrdup_buffer_shallow(NULL, vb, NULL, p, false);
2730  fr_dcursor_append(out, vb);
2731 
2732  return XLAT_ACTION_DONE;
2733  }
2734 
2735  switch (arg->type) {
2736  /*
2737  * If the input is an integer value then get an
2738  * arbitrary subcapture index.
2739  */
2740  case FR_TYPE_NUMERIC:
2741  {
2742  fr_value_box_t idx;
2743  fr_value_box_t *vb;
2744  char *p;
2745 
2746  if (fr_value_box_list_next(in, in_head)) {
2747  REDEBUG("Only one subcapture argument allowed");
2748  return XLAT_ACTION_FAIL;
2749  }
2750 
2751  if (fr_value_box_cast(NULL, &idx, FR_TYPE_UINT32, NULL, arg) < 0) {
2752  RPEDEBUG("Bad subcapture index");
2753  return XLAT_ACTION_FAIL;
2754  }
2755 
2756  MEM(vb = fr_value_box_alloc_null(ctx));
2757  if (regex_request_to_sub(vb, &p, request, idx.vb_uint32) < 0) {
2758  REDEBUG2("No previous numbered regex capture group");
2759  talloc_free(vb);
2760  return XLAT_ACTION_FAIL;
2761  }
2762  fr_assert(p);
2763  fr_value_box_bstrdup_buffer_shallow(NULL, vb, NULL, p, false);
2764  fr_dcursor_append(out, vb);
2765 
2766  return XLAT_ACTION_DONE;
2767  }
2768 
2769  default:
2770  {
2771  fr_value_box_t *vb;
2772  char *p;
2773 
2774  /*
2775  * Concatenate all input
2776  */
2778  arg, &in_head->vb_group, FR_TYPE_STRING,
2779  FR_VALUE_BOX_LIST_FREE, true,
2780  SIZE_MAX) < 0) {
2781  RPEDEBUG("Failed concatenating input");
2782  return XLAT_ACTION_FAIL;
2783  }
2784 
2785  MEM(vb = fr_value_box_alloc_null(ctx));
2786  if (regex_request_to_sub_named(vb, &p, request, arg->vb_strvalue) < 0) {
2787  REDEBUG2("No previous named regex capture group");
2788  talloc_free(vb);
2789  return XLAT_ACTION_FAIL;
2790  }
2791 
2792  fr_assert(p);
2793  fr_value_box_bstrdup_buffer_shallow(NULL, vb, NULL, p, false);
2794  fr_dcursor_append(out, vb);
2795 
2796  return XLAT_ACTION_DONE;
2797  }
2798  }
2799 }
2800 #endif
2801 
2803  { .concat = true, .type = FR_TYPE_OCTETS },
2805 };
2806 
2807 /** Calculate the SHA1 hash of a string or attribute.
2808  *
2809  * Example:
2810 @verbatim
2811 %sha1(foo) == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
2812 @endverbatim
2813  *
2814  * @ingroup xlat_functions
2815  */
2817  UNUSED xlat_ctx_t const *xctx,
2818  UNUSED request_t *request, fr_value_box_list_t *args)
2819 {
2820  uint8_t digest[SHA1_DIGEST_LENGTH];
2821  fr_sha1_ctx sha1_ctx;
2822  fr_value_box_t *vb;
2823  fr_value_box_t *in_head;
2824 
2825  XLAT_ARGS(args, &in_head);
2826 
2827  fr_sha1_init(&sha1_ctx);
2828  if (in_head) {
2829  fr_sha1_update(&sha1_ctx, in_head->vb_octets, in_head->vb_length);
2830  } else {
2831  /* sha1 of empty string */
2832  fr_sha1_update(&sha1_ctx, NULL, 0);
2833  }
2834  fr_sha1_final(digest, &sha1_ctx);
2835 
2836  MEM(vb = fr_value_box_alloc_null(ctx));
2837  fr_value_box_memdup(vb, vb, NULL, digest, sizeof(digest), false);
2838 
2839  fr_dcursor_append(out, vb);
2840 
2841  return XLAT_ACTION_DONE;
2842 }
2843 
2844 /** Calculate any digest supported by OpenSSL EVP_MD
2845  *
2846  * Example:
2847 @verbatim
2848 %sha2_256(foo) == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
2849 @endverbatim
2850  *
2851  * @ingroup xlat_functions
2852  */
2853 #ifdef HAVE_OPENSSL_EVP_H
2854 static xlat_action_t xlat_evp_md(TALLOC_CTX *ctx, fr_dcursor_t *out,
2855  UNUSED xlat_ctx_t const *xctx,
2856  UNUSED request_t *request, fr_value_box_list_t *args, EVP_MD const *md)
2857 {
2858  uint8_t digest[EVP_MAX_MD_SIZE];
2859  unsigned int digestlen;
2860  EVP_MD_CTX *md_ctx;
2861  fr_value_box_t *vb;
2862  fr_value_box_t *in_head;
2863 
2864  XLAT_ARGS(args, &in_head);
2865 
2866  md_ctx = EVP_MD_CTX_create();
2867  EVP_DigestInit_ex(md_ctx, md, NULL);
2868  if (in_head) {
2869  EVP_DigestUpdate(md_ctx, in_head->vb_octets, in_head->vb_length);
2870  } else {
2871  EVP_DigestUpdate(md_ctx, NULL, 0);
2872  }
2873  EVP_DigestFinal_ex(md_ctx, digest, &digestlen);
2874  EVP_MD_CTX_destroy(md_ctx);
2875 
2876  MEM(vb = fr_value_box_alloc_null(ctx));
2877  fr_value_box_memdup(vb, vb, NULL, digest, digestlen, false);
2878 
2879  fr_dcursor_append(out, vb);
2880 
2881  return XLAT_ACTION_DONE;
2882 }
2883 
2884 # define EVP_MD_XLAT(_md, _md_func) \
2885 static xlat_action_t xlat_func_##_md(TALLOC_CTX *ctx, fr_dcursor_t *out,\
2886  xlat_ctx_t const *xctx, \
2887  request_t *request,\
2888  fr_value_box_list_t *in)\
2889 {\
2890  return xlat_evp_md(ctx, out, xctx, request, in, EVP_##_md_func());\
2891 }
2892 
2893 EVP_MD_XLAT(sha2_224, sha224)
2894 EVP_MD_XLAT(sha2_256, sha256)
2895 EVP_MD_XLAT(sha2_384, sha384)
2896 EVP_MD_XLAT(sha2_512, sha512)
2897 
2898 EVP_MD_XLAT(blake2s_256, blake2s256)
2899 EVP_MD_XLAT(blake2b_512, blake2b512)
2900 
2901 # if OPENSSL_VERSION_NUMBER >= 0x10101000L
2902 EVP_MD_XLAT(sha3_224, sha3_224)
2903 EVP_MD_XLAT(sha3_256, sha3_256)
2904 EVP_MD_XLAT(sha3_384, sha3_384)
2905 EVP_MD_XLAT(sha3_512, sha3_512)
2906 # endif
2907 #endif
2908 
2909 
2911  { .required = true, .concat = true, .type = FR_TYPE_STRING },
2913 };
2914 
2915 /** Print data as string, if possible.
2916  *
2917  * Concat and cast one or more input boxes to a single output box string.
2918  *
2919  * @ingroup xlat_functions
2920  */
2922  UNUSED xlat_ctx_t const *xctx,
2923  UNUSED request_t *request, fr_value_box_list_t *in)
2924 {
2925  fr_value_box_t *in_head = fr_value_box_list_pop_head(in);
2926 
2927  /*
2928  * Casting and concat is done by arg processing
2929  * so just move the value box to the output
2930  */
2931  fr_dcursor_append(out, in_head);
2932 
2933  return XLAT_ACTION_DONE;
2934 }
2935 
2936 
2938  { .concat = true, .type = FR_TYPE_STRING },
2940 };
2941 
2942 /** Print length of given string
2943  *
2944  * Example:
2945 @verbatim
2946 %strlen(foo) == 3
2947 @endverbatim
2948  *
2949  * @see #xlat_func_length
2950  *
2951  * @ingroup xlat_functions
2952  */
2954  UNUSED xlat_ctx_t const *xctx,
2955  UNUSED request_t *request, fr_value_box_list_t *args)
2956 {
2957  fr_value_box_t *vb;
2958  fr_value_box_t *in_head;
2959 
2960  XLAT_ARGS(args, &in_head);
2961 
2962  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_SIZE, NULL));
2963 
2964  if (!in_head) {
2965  vb->vb_size = 0;
2966  } else {
2967  vb->vb_size = strlen(in_head->vb_strvalue);
2968  }
2969 
2970  fr_dcursor_append(out, vb);
2971 
2972  return XLAT_ACTION_DONE;
2973 }
2974 
2976  { .single = true, .required = true, .type = FR_TYPE_VOID },
2977  { .single = true, .required = true, .type = FR_TYPE_INT32 },
2978  { .single = true, .type = FR_TYPE_INT32 },
2980 };
2981 
2982 /** Extract a substring from string / octets data
2983  *
2984  * Non string / octets data is cast to a string.
2985  *
2986  * Second parameter is start position, optional third parameter is length
2987  * Negative start / length count from RHS of data.
2988  *
2989  * Example: (User-Name = "hello")
2990 @verbatim
2991 %substr(&User-Name, 1, 3) == 'ell'
2992 @endverbatim
2993  *
2994  * @ingroup xlat_functions
2995  */
2996 static xlat_action_t xlat_func_substr(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx,
2997  request_t *request, fr_value_box_list_t *args)
2998 {
2999  fr_value_box_t *in = NULL, *start_vb, *len_vb, *vb;
3000  int32_t start, end, len;
3001 
3002  XLAT_ARGS(args, &in, &start_vb, &len_vb);
3003 
3004  switch (in->type) {
3005  case FR_TYPE_OCTETS:
3006  case FR_TYPE_STRING:
3007  break;
3008 
3009  default:
3010  if (fr_value_box_cast_in_place(in, in, FR_TYPE_STRING, NULL) < 0) {
3011  RPEDEBUG("Failed casting value to string");
3012  return XLAT_ACTION_FAIL;
3013  }
3014  break;
3015  }
3016 
3017  if (start_vb->vb_int32 > (int32_t)in->vb_length) return XLAT_ACTION_DONE;
3018 
3019  if (start_vb->vb_int32 < 0) {
3020  start = in->vb_length + start_vb->vb_int32;
3021  if (start < 0) start = 0;
3022  } else {
3023  start = start_vb->vb_int32;
3024  }
3025 
3026  if (len_vb) {
3027  if (len_vb->vb_int32 < 0) {
3028  end = in->vb_length + len_vb->vb_int32;
3029  if (end < 0) return XLAT_ACTION_DONE;
3030  } else {
3031  end = start + len_vb->vb_int32;
3032  if (end > (int32_t)in->vb_length) end = in->vb_length;
3033  }
3034  } else {
3035  end = in->vb_length;
3036  }
3037 
3038  if (start >= end) return XLAT_ACTION_DONE;
3039 
3040  MEM(vb = fr_value_box_alloc(ctx, in->type, NULL));
3041 
3042  len = end - start;
3043  switch (in->type) {
3044  case FR_TYPE_STRING:
3045  fr_value_box_bstrndup(vb, vb, NULL, &in->vb_strvalue[start], len, in->tainted);
3046  break;
3047  case FR_TYPE_OCTETS:
3048  {
3049  uint8_t *buf;
3050  fr_value_box_mem_alloc(vb, &buf, vb, NULL, len, in->tainted);
3051  memcpy(buf, &in->vb_octets[start], len);
3052  }
3053  break;
3054  default:
3055  fr_assert(0);
3056  }
3057  fr_dcursor_append(out, vb);
3058 
3059  return XLAT_ACTION_DONE;
3060 }
3061 
3062 #ifdef HAVE_REGEX_PCRE2
3063 /** Cache statically compiled expressions
3064  */
3065 typedef struct {
3066  regex_t *pattern;
3067  fr_regex_flags_t flags;
3068 } xlat_subst_regex_inst_t;
3069 
3070 /** Pre-compile regexes where possible
3071  */
3072 static int xlat_instantiate_subst_regex(xlat_inst_ctx_t const *xctx)
3073 {
3074  xlat_subst_regex_inst_t *inst = talloc_get_type_abort(xctx->inst, xlat_subst_regex_inst_t);
3075  xlat_exp_t *patt_exp;
3076  fr_sbuff_t sbuff;
3077  fr_sbuff_marker_t start_m, end_m;
3078 
3079  /* args #2 (pattern) */
3080  patt_exp = fr_dlist_next(&xctx->ex->call.args->dlist, fr_dlist_head(&xctx->ex->call.args->dlist));
3081  fr_assert(patt_exp && patt_exp->type == XLAT_GROUP); /* args must be groups */
3082 
3083  /* If there are dynamic expansions, we can't pre-compile */
3084  if (!xlat_is_literal(patt_exp->group)) return 0;
3085  fr_assert(fr_dlist_num_elements(&patt_exp->group->dlist) == 1);
3086 
3087  patt_exp = fr_dlist_head(&patt_exp->group->dlist);
3088 
3089  /* We can only pre-compile strings */
3090  if (!fr_type_is_string(patt_exp->data.type)) return 0;
3091 
3092  sbuff = FR_SBUFF_IN(patt_exp->data.vb_strvalue, patt_exp->data.vb_length);
3093 
3094  /* skip any whitesapce */
3095  fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, 0);
3096 
3097  /* Is the next char a forward slash? */
3098  if (fr_sbuff_next_if_char(&sbuff, '/')) {
3099  fr_slen_t slen;
3100 
3101  fr_sbuff_marker(&start_m, &sbuff);
3102 
3103  if (!fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '/')) return 0; /* Not a regex */
3104 
3105  fr_sbuff_marker(&end_m, &sbuff);
3106  fr_sbuff_next(&sbuff); /* skip trailing slash */
3107 
3108  if (fr_sbuff_remaining(&sbuff)) {
3109  slen = regex_flags_parse(NULL, &inst->flags,
3110  &sbuff,
3111  NULL, true);
3112  if (slen < 0) {
3113  PERROR("Failed parsing regex flags in \"%s\"", patt_exp->data.vb_strvalue);
3114  return -1;
3115  }
3116  }
3117 
3118  if (regex_compile(inst, &inst->pattern,
3119  fr_sbuff_current(&start_m), fr_sbuff_current(&end_m) - fr_sbuff_current(&start_m),
3120  &inst->flags, true, false) <= 0) {
3121  PERROR("Failed compiling regex \"%s\"", patt_exp->data.vb_strvalue);
3122  return -1;
3123  }
3124  }
3125  /* No... then it's not a regex */
3126 
3127  return 0;
3128 }
3129 
3130 /** Perform regex substitution TODO CHECK
3131  *
3132  * Called when %subst() pattern begins with "/"
3133  *
3134 @verbatim
3135 %subst(<subject>, /<regex>/[flags], <replace>)
3136 @endverbatim
3137  *
3138  * Example: (User-Name = "foo")
3139 @verbatim
3140 %subst(%{User-Name}, /oo.*$/, 'un') == "fun"
3141 @endverbatim
3142  *
3143  * @note References can be specified in the replacement string with $<ref>
3144  *
3145  * @see #xlat_func_subst
3146  *
3147  * @ingroup xlat_functions
3148  */
3149 static int xlat_func_subst_regex(TALLOC_CTX *ctx, fr_dcursor_t *out,
3150  xlat_ctx_t const *xctx, request_t *request,
3151  fr_value_box_list_t *args)
3152 {
3153  xlat_subst_regex_inst_t const *inst = talloc_get_type_abort_const(xctx->inst, xlat_subst_regex_inst_t);
3154  fr_sbuff_t sbuff;
3155  fr_sbuff_marker_t start_m, end_m;
3156  char *buff;
3157  ssize_t slen;
3158  regex_t *pattern, *our_pattern = NULL;
3159  fr_regex_flags_t const *flags;
3160  fr_regex_flags_t our_flags = {};
3161  fr_value_box_t *vb;
3162  fr_value_box_t *subject_vb;
3163  fr_value_box_t *regex_vb;
3164  fr_value_box_t *rep_vb;
3165 
3166  XLAT_ARGS(args, &subject_vb, &regex_vb, &rep_vb);
3167 
3168  /*
3169  * Was not pre-compiled, so we need to compile it now
3170  */
3171  if (!inst->pattern) {
3172  sbuff = FR_SBUFF_IN(regex_vb->vb_strvalue, regex_vb->vb_length);
3173  if (fr_sbuff_len(&sbuff) == 0) {
3174  REDEBUG("Regex must not be empty");
3175  return XLAT_ACTION_FAIL;
3176  }
3177 
3178  fr_sbuff_next(&sbuff); /* skip leading slash */
3179  fr_sbuff_marker(&start_m, &sbuff);
3180 
3181  if (!fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '/')) return 1; /* Not a regex */
3182 
3183  fr_sbuff_marker(&end_m, &sbuff);
3184  fr_sbuff_next(&sbuff); /* skip trailing slash */
3185 
3186  slen = regex_flags_parse(NULL, &our_flags, &sbuff, NULL, true);
3187  if (slen < 0) {
3188  RPEDEBUG("Failed parsing regex flags");
3189  return -1;
3190  }
3191 
3192  /*
3193  * Process the substitution
3194  */
3195  if (regex_compile(NULL, &our_pattern,
3196  fr_sbuff_current(&start_m), fr_sbuff_current(&end_m) - fr_sbuff_current(&start_m),
3197  &our_flags, true, true) <= 0) {
3198  RPEDEBUG("Failed compiling regex");
3199  return -1;
3200  }
3201  pattern = our_pattern;
3202  flags = &our_flags;
3203  } else {
3204  pattern = inst->pattern;
3205  flags = &inst->flags;
3206  }
3207 
3208  MEM(vb = fr_value_box_alloc_null(ctx));
3209  if (regex_substitute(vb, &buff, 0, pattern, flags,
3210  subject_vb->vb_strvalue, subject_vb->vb_length,
3211  rep_vb->vb_strvalue, rep_vb->vb_length, NULL) < 0) {
3212  RPEDEBUG("Failed performing substitution");
3213  talloc_free(vb);
3214  talloc_free(pattern);
3215  return -1;
3216  }
3217  fr_value_box_bstrdup_buffer_shallow(NULL, vb, NULL, buff, subject_vb->tainted);
3219 
3220  fr_dcursor_append(out, vb);
3221 
3222  talloc_free(our_pattern);
3223 
3224  return 0;
3225 }
3226 #endif
3227 
3229  { .required = true, .concat = true, .type = FR_TYPE_STRING },
3230  { .required = true, .concat = true, .type = FR_TYPE_STRING },
3231  { .required = true, .concat = true, .type = FR_TYPE_STRING },
3233 };
3234 
3235 /** Perform regex substitution
3236  *
3237 @verbatim
3238 %subst(<subject>, <pattern>, <replace>)
3239 @endverbatim
3240  *
3241  * Example: (User-Name = "foobar")
3242 @verbatim
3243 %subst(%{User-Name}, 'oo', 'un') == "funbar"
3244 @endverbatim
3245  *
3246  * @see xlat_func_subst_regex
3247  *
3248  * @ingroup xlat_functions
3249  */
3251 #ifdef HAVE_REGEX_PCRE2
3252  xlat_ctx_t const *xctx,
3253 #else
3254  UNUSED xlat_ctx_t const *xctx,
3255 #endif
3256  request_t *request, fr_value_box_list_t *args)
3257 {
3258  char const *p, *q, *end;
3259  char *vb_str;
3260 
3261  char const *pattern, *rep;
3262  size_t pattern_len, rep_len;
3263 
3264  fr_value_box_t *rep_vb, *vb;
3265  fr_value_box_t *subject_vb;
3266  fr_value_box_t *pattern_vb;
3267 
3268  XLAT_ARGS(args, &subject_vb, &pattern_vb, &rep_vb);
3269 
3270  /* coverity[dereference] */
3271  pattern = pattern_vb->vb_strvalue;
3272  if (*pattern == '/') {
3273 #ifdef HAVE_REGEX_PCRE2
3274  switch (xlat_func_subst_regex(ctx, out, xctx, request, args)) {
3275  case 0:
3276  return XLAT_ACTION_DONE;
3277 
3278  case 1:
3279  /* Not a regex, fall through */
3280  break;
3281 
3282  case -1:
3283  return XLAT_ACTION_FAIL;
3284  }
3285 #else
3286  if (memchr(pattern, '/', pattern_vb->vb_length - 1)) {
3287  REDEBUG("regex based substitutions require libpcre2. "
3288  "Check ${features.regex-pcre2} to determine support");
3289  }
3290  return XLAT_ACTION_FAIL;
3291 #endif
3292  }
3293 
3294  /*
3295  * Check for empty pattern
3296  */
3297  pattern_len = pattern_vb->vb_length;
3298  if (pattern_len == 0) {
3299  REDEBUG("Empty pattern");
3300  return XLAT_ACTION_FAIL;
3301  }
3302 
3303  rep = rep_vb->vb_strvalue;
3304  rep_len = rep_vb->vb_length;
3305 
3306  p = subject_vb->vb_strvalue;
3307  end = p + subject_vb->vb_length;
3308 
3309  MEM(vb = fr_value_box_alloc_null(ctx));
3310  vb_str = talloc_bstrndup(vb, "", 0);
3311 
3312  while (p < end) {
3313  q = memmem(p, end - p, pattern, pattern_len);
3314  if (!q) {
3315  MEM(vb_str = talloc_bstr_append(vb, vb_str, p, end - p));
3316  break;
3317  }
3318 
3319  if (q > p) MEM(vb_str = talloc_bstr_append(vb, vb_str, p, q - p));
3320  if (rep_len) MEM(vb_str = talloc_bstr_append(vb, vb_str, rep, rep_len));
3321  p = q + pattern_len;
3322  }
3323 
3324  if (fr_value_box_bstrdup_buffer_shallow(NULL, vb, NULL, vb_str, subject_vb->tainted) < 0) {
3325  RPEDEBUG("Failed creating output box");
3326  talloc_free(vb);
3327  return XLAT_ACTION_FAIL;
3328  }
3329 
3330  fr_assert(vb && (vb->type != FR_TYPE_NULL));
3332  fr_dcursor_append(out, vb);
3333 
3334  return XLAT_ACTION_DONE;
3335 }
3336 
3338  { .required = false, .single = true, .type = FR_TYPE_STRING },
3340 };
3341 
3342 /** Return the time as a #FR_TYPE_DATE
3343  *
3344  * Note that all operations are UTC.
3345  *
3346 @verbatim
3347 %time()
3348 @endverbatim
3349  *
3350  * Example:
3351 @verbatim
3352 update reply {
3353  &Reply-Message := "%{%time(now) - %time(request)}"
3354 }
3355 @endverbatim
3356  *
3357  * @ingroup xlat_functions
3358  */
3360  UNUSED xlat_ctx_t const *xctx,
3361  request_t *request, fr_value_box_list_t *args)
3362 {
3363  fr_value_box_t *arg;
3364  fr_value_box_t *vb;
3366 
3367  XLAT_ARGS(args, &arg);
3368 
3369  if (!arg || (strcmp(arg->vb_strvalue, "now") == 0)) {
3371 
3372  } else if (strcmp(arg->vb_strvalue, "request") == 0) {
3373  value = fr_time_to_unix_time(request->packet->timestamp);
3374 
3375  } else if (strcmp(arg->vb_strvalue, "offset") == 0) {
3376  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
3377  vb->vb_time_delta = fr_time_gmtoff();
3378  goto append;
3379 
3380  } else if (strcmp(arg->vb_strvalue, "dst") == 0) {
3381  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
3382  vb->vb_bool = fr_time_is_dst();
3383  goto append;
3384 
3385  } else if (strcmp(arg->vb_strvalue, "mday_offset") == 0) {
3386  struct tm tm;
3387  fr_unix_time_t unix_time = fr_time_to_unix_time(request->packet->timestamp);
3388  time_t when = fr_unix_time_to_sec(unix_time);
3389  int64_t nsec;
3390 
3391  gmtime_r(&when, &tm);
3392 
3393  nsec = (int64_t) 86400 * (tm.tm_mday - 1);
3394  nsec += when % 86400;
3395  nsec *= NSEC;
3396  nsec += fr_unix_time_unwrap(unix_time) % NSEC;
3397 
3398  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
3399  vb->vb_time_delta = fr_time_delta_wrap(nsec);
3400  goto append;
3401 
3402  } else if (strcmp(arg->vb_strvalue, "wday_offset") == 0) {
3403  struct tm tm;
3404  fr_unix_time_t unix_time = fr_time_to_unix_time(request->packet->timestamp);
3405  time_t when = fr_unix_time_to_sec(unix_time);
3406  int64_t nsec;
3407 
3408  gmtime_r(&when, &tm);
3409 
3410  nsec = (int64_t) 86400 * tm.tm_wday;
3411  nsec += when % 86400;
3412  nsec *= NSEC;
3413  nsec += fr_unix_time_unwrap(unix_time) % NSEC;
3414 
3415  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
3416  vb->vb_time_delta = fr_time_delta_wrap(nsec);
3417 
3418  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
3419  vb->vb_time_delta = fr_time_delta_wrap(nsec);
3420  goto append;
3421 
3422  } else if (fr_unix_time_from_str(&value, arg->vb_strvalue, FR_TIME_RES_SEC) < 0) {
3423  REDEBUG("Invalid time specification '%s'", arg->vb_strvalue);
3424  return XLAT_ACTION_FAIL;
3425  }
3426 
3427  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_DATE, NULL));
3428  vb->vb_date = value;
3429 
3430 append:
3431  fr_dcursor_append(out, vb);
3432 
3433  return XLAT_ACTION_DONE;
3434 }
3435 
3436 
3437 /** Change case of a string
3438  *
3439  * If upper is true, change to uppercase, otherwise, change to lowercase
3440  */
3442  UNUSED request_t *request, fr_value_box_list_t *args, bool upper)
3443 {
3444  char *p;
3445  char const *end;
3446  fr_value_box_t *vb;
3447 
3448  XLAT_ARGS(args, &vb);
3449 
3450  p = UNCONST(char *, vb->vb_strvalue);
3451  end = p + vb->vb_length;
3452 
3453  while (p < end) {
3454  *(p) = upper ? toupper ((int) *(p)) : tolower((uint8_t) *(p));
3455  p++;
3456  }
3457 
3458  fr_value_box_list_remove(args, vb); /* Can't leave it in both lists */
3459  fr_dcursor_append(out, vb);
3460 
3461  return XLAT_ACTION_DONE;
3462 }
3463 
3465  { .required = true, .concat = true, .type = FR_TYPE_STRING },
3467 };
3468 
3469 
3470 /** Convert a string to lowercase
3471  *
3472  * Example:
3473 @verbatim
3474 %tolower("Bar") == "bar"
3475 @endverbatim
3476  *
3477  * Probably only works for ASCII
3478  *
3479  * @ingroup xlat_functions
3480  */
3482  UNUSED xlat_ctx_t const *xctx,
3483  request_t *request, fr_value_box_list_t *in)
3484 {
3485  return xlat_change_case(ctx, out, request, in, false);
3486 }
3487 
3488 
3489 /** Convert a string to uppercase
3490  *
3491  * Example:
3492 @verbatim
3493 %toupper("Foo") == "FOO"
3494 @endverbatim
3495  *
3496  * Probably only works for ASCII
3497  *
3498  * @ingroup xlat_functions
3499  */
3501  UNUSED xlat_ctx_t const *xctx,
3502  request_t *request, fr_value_box_list_t *in)
3503 {
3504  return xlat_change_case(ctx, out, request, in, true);
3505 }
3506 
3507 
3509  { .required = true, .concat = true, .type = FR_TYPE_STRING },
3511 };
3512 
3513 /** URLencode special characters
3514  *
3515  * Example:
3516 @verbatim
3517 %urlquote("http://example.org/") == "http%3A%47%47example.org%47"
3518 @endverbatim
3519  *
3520  * @ingroup xlat_functions
3521  */
3523  UNUSED xlat_ctx_t const *xctx,
3524  UNUSED request_t *request, fr_value_box_list_t *args)
3525 {
3526  char const *p, *end;
3527  char *buff_p;
3528  size_t outlen = 0;
3529  fr_value_box_t *vb;
3530  fr_value_box_t *in_head;
3531 
3532  XLAT_ARGS(args, &in_head);
3533 
3534  p = in_head->vb_strvalue;
3535  end = p + in_head->vb_length;
3536 
3537  /*
3538  * Calculate size of output
3539  */
3540  while (p < end) {
3541  if (isalnum(*p) ||
3542  *p == '-' ||
3543  *p == '_' ||
3544  *p == '.' ||
3545  *p == '~') {
3546  outlen++;
3547  } else {
3548  outlen += 3;
3549  }
3550  p++;
3551  }
3552 
3553  MEM(vb = fr_value_box_alloc_null(ctx));
3554  MEM(fr_value_box_bstr_alloc(vb, &buff_p, vb, NULL, outlen, false) == 0);
3556 
3557  /* Reset p to start position */
3558  p = in_head->vb_strvalue;
3559 
3560  while (p < end) {
3561  if (isalnum(*p)) {
3562  *buff_p++ = *p++;
3563  continue;
3564  }
3565 
3566  switch (*p) {
3567  case '-':
3568  case '_':
3569  case '.':
3570  case '~':
3571  *buff_p++ = *p++;
3572  break;
3573 
3574  default:
3575  /* MUST be upper case hex to be compliant */
3576  snprintf(buff_p, 4, "%%%02X", (uint8_t) *p++); /* %XX */
3577 
3578  buff_p += 3;
3579  }
3580  }
3581 
3582  *buff_p = '\0';
3583 
3584  fr_dcursor_append(out, vb);
3585 
3586  return XLAT_ACTION_DONE;
3587 }
3588 
3589 
3591  { .required = true, .concat = true, .type = FR_TYPE_STRING },
3593 };
3594 
3595 /** URLdecode special characters
3596  *
3597  * @note Remember to escape % with %% in strings, else xlat will try to parse it.
3598  *
3599  * Example:
3600 @verbatim
3601 %urlunquote("http%%3A%%47%%47example.org%%47") == "http://example.org/"
3602 @endverbatim
3603  *
3604  * @ingroup xlat_functions
3605  */
3607  UNUSED xlat_ctx_t const *xctx,
3608  request_t *request, fr_value_box_list_t *args)
3609 {
3610  char const *p, *end;
3611  char *buff_p;
3612  char *c1, *c2;
3613  size_t outlen = 0;
3614  fr_value_box_t *vb;
3615  fr_value_box_t *in_head;
3616 
3617  XLAT_ARGS(args, &in_head);
3618 
3619  p = in_head->vb_strvalue;
3620  end = p + in_head->vb_length;
3621 
3622  /*
3623  * Calculate size of output
3624  */
3625  while (p < end) {
3626  if (*p == '%') {
3627  p += 3;
3628  } else {
3629  p++;
3630  }
3631  outlen++;
3632  }
3633 
3634  MEM(vb = fr_value_box_alloc_null(ctx));
3635  MEM(fr_value_box_bstr_alloc(vb, &buff_p, vb, NULL, outlen, false) == 0);
3637 
3638  /* Reset p to start position */
3639  p = in_head->vb_strvalue;
3640 
3641  while (p < end) {
3642  if (*p != '%') {
3643  *buff_p++ = *p++;
3644  continue;
3645  }
3646  /* Is a % char */
3647 
3648  /* Don't need \0 check, as it won't be in the hextab */
3649  if (!(c1 = memchr(hextab, tolower((uint8_t) *++p), 16)) ||
3650  !(c2 = memchr(hextab, tolower((uint8_t) *++p), 16))) {
3651  REMARKER(in_head->vb_strvalue, p - in_head->vb_strvalue, "Non-hex char in %% sequence");
3652  talloc_free(vb);
3653 
3654  return XLAT_ACTION_FAIL;
3655  }
3656  p++;
3657  *buff_p++ = ((c1 - hextab) << 4) + (c2 - hextab);
3658  }
3659 
3660  *buff_p = '\0';
3661  fr_dcursor_append(out, vb);
3662 
3663  return XLAT_ACTION_DONE;
3664 }
3665 
3667  { .single = true, .variadic = XLAT_ARG_VARIADIC_EMPTY_SQUASH, .type = FR_TYPE_VOID },
3669 };
3670 
3671 /** Decode any protocol attribute / options
3672  *
3673  * Creates protocol-specific attributes based on the given binary option data
3674  *
3675  * Example:
3676 @verbatim
3677 %dhcpv4.decode(%{Tmp-Octets-0})
3678 @endverbatim
3679  *
3680  * @ingroup xlat_functions
3681  */
3683  xlat_ctx_t const *xctx,
3684  request_t *request, fr_value_box_list_t *in)
3685 {
3686  int decoded;
3687  fr_value_box_t *vb;
3688  void *decode_ctx = NULL;
3689  fr_test_point_pair_decode_t const *tp_decode = *(void * const *)xctx->inst;
3690 
3691  if (tp_decode->test_ctx) {
3692  if (tp_decode->test_ctx(&decode_ctx, ctx) < 0) {
3693  return XLAT_ACTION_FAIL;
3694  }
3695  }
3696 
3697  decoded = xlat_decode_value_box_list(request->request_ctx, &request->request_pairs,
3698  request, decode_ctx, tp_decode->func, in);
3699  if (decoded <= 0) {
3700  talloc_free(decode_ctx);
3701  RPERROR("Protocol decoding failed");
3702  return XLAT_ACTION_FAIL;
3703  }
3704 
3705  /*
3706  * Create a value box to hold the decoded count, and add
3707  * it to the output list.
3708  */
3709  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_UINT32, NULL));
3710  vb->vb_uint32 = decoded;
3711  fr_dcursor_append(out, vb);
3712 
3713  talloc_free(decode_ctx);
3714  return XLAT_ACTION_DONE;
3715 }
3716 
3718 {
3719  *(void **) mctx->inst = mctx->uctx;
3720  return 0;
3721 }
3722 
3724  { .required = true, .single = true, .type = FR_TYPE_STRING },
3726 };
3727 
3728 /** Encode protocol attributes / options
3729  *
3730  * Returns octet string created from the provided pairs
3731  *
3732  * Example:
3733 @verbatim
3734 %dhcpv4.encode(&request[*])
3735 @endverbatim
3736  *
3737  * @ingroup xlat_functions
3738  */
3740  xlat_ctx_t const *xctx,
3741  request_t *request, fr_value_box_list_t *args)
3742 {
3743  tmpl_t *vpt;
3744  fr_pair_t *vp;
3745  fr_dcursor_t cursor;
3746  tmpl_dcursor_ctx_t cc;
3747  bool tainted = false;
3748  fr_value_box_t *encoded;
3749 
3750  uint8_t binbuf[2048];
3751  uint8_t *p = binbuf, *end = p + sizeof(binbuf);
3752  ssize_t len = 0;
3753  fr_value_box_t *in_head;
3754  void *encode_ctx = NULL;
3755  fr_test_point_pair_encode_t const *tp_encode;
3756 
3757  XLAT_ARGS(args, &in_head);
3758 
3759  memcpy(&tp_encode, xctx->inst, sizeof(tp_encode)); /* const issues */
3760 
3761  if (tmpl_afrom_attr_str(ctx, NULL, &vpt, in_head->vb_strvalue,
3762  &(tmpl_rules_t){
3763  .attr = {
3764  .dict_def = request->dict,
3765  .list_def = request_attr_request,
3766  .allow_wildcard = true,
3767  .prefix = TMPL_ATTR_REF_PREFIX_AUTO
3768  }
3769  }) <= 0) {
3770  RPEDEBUG("Failed parsing attribute reference");
3771  return XLAT_ACTION_FAIL;
3772  }
3773 
3774  /*
3775  * Create the encoding context.
3776  */
3777  if (tp_encode->test_ctx) {
3778  if (tp_encode->test_ctx(&encode_ctx, vpt) < 0) {
3779  talloc_free(vpt);
3780  return XLAT_ACTION_FAIL;
3781  }
3782  }
3783 
3784  /*
3785  * Loop over the attributes, encoding them.
3786  */
3787  for (vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt);
3788  vp != NULL;
3789  vp = fr_dcursor_next(&cursor)) {
3790  if (vp->da->flags.internal) continue;
3791 
3792  /*
3793  * Don't check the dictionaries. By definition,
3794  * vp->da->dict==request->dict, OR else we're
3795  * using the internal encoder and encoding a real
3796  * protocol.
3797  *
3798  * However, we likely still want a
3799  * dictionary-specific "is encodable" function,
3800  * as AKA/SIM and DHCPv6 encode "bool"s only if
3801  * their value is true.
3802  */
3803 
3804  len = tp_encode->func(&FR_DBUFF_TMP(p, end), &cursor, encode_ctx);
3805  if (len < 0) {
3806  RPEDEBUG("Protocol encoding failed");
3807  tmpl_dcursor_clear(&cc);
3808  talloc_free(vpt);
3809  return XLAT_ACTION_FAIL;
3810  }
3811 
3812  tainted |= vp->vp_tainted;
3813  p += len;
3814  }
3815 
3816  tmpl_dcursor_clear(&cc);
3817  talloc_free(vpt);
3818 
3819  /*
3820  * Pass the options string back to the caller.
3821  */
3822  MEM(encoded = fr_value_box_alloc_null(ctx));
3823  fr_value_box_memdup(encoded, encoded, NULL, binbuf, (size_t)len, tainted);
3824  fr_dcursor_append(out, encoded);
3825 
3826  return XLAT_ACTION_DONE;
3827 }
3828 
3830 {
3831  fr_test_point_pair_decode_t *tp_decode;
3832  fr_test_point_pair_encode_t *tp_encode;
3833  xlat_t *xlat;
3834  dl_t *dl = fr_dict_dl(dict);
3835  char *p, buffer[256+32], name[256];
3836 
3837  /*
3838  * No library for this protocol, skip it.
3839  *
3840  * Protocol TEST has no libfreeradius-test, so that's OK.
3841  */
3842  if (!dl) return 0;
3843 
3844  strlcpy(name, fr_dict_root(dict)->name, sizeof(name));
3845  for (p = name; *p != '\0'; p++) {
3846  *p = tolower((uint8_t) *p);
3847  }
3848 
3849  /*
3850  * See if there's a decode function for it.
3851  */
3852  snprintf(buffer, sizeof(buffer), "%s_tp_decode_pair", name);
3853  tp_decode = dlsym(dl->handle, buffer);
3854  if (tp_decode) {
3855  snprintf(buffer, sizeof(buffer), "%s.decode", name);
3856 
3857  /* May be called multiple times, so just skip protocols we've already registered */
3858  if (xlat_func_find(buffer, -1)) return 1;
3859 
3860  if (unlikely((xlat = xlat_func_register(NULL, buffer, protocol_decode_xlat, FR_TYPE_UINT32)) == NULL)) return -1;
3862  /* coverity[suspicious_sizeof] */
3865  }
3866 
3867  /*
3868  * See if there's an encode function for it.
3869  */
3870  snprintf(buffer, sizeof(buffer), "%s_tp_encode_pair", name);
3871  tp_encode = dlsym(dl->handle, buffer);
3872  if (tp_encode) {
3873  snprintf(buffer, sizeof(buffer), "%s.encode", name);
3874 
3875  if (xlat_func_find(buffer, -1)) return 1;
3876 
3877  if (unlikely((xlat = xlat_func_register(NULL, buffer, protocol_encode_xlat, FR_TYPE_OCTETS)) == NULL)) return -1;
3879  /* coverity[suspicious_sizeof] */
3882  }
3883 
3884  return 0;
3885 }
3886 
3887 /** Register xlats for any loaded dictionaries
3888  */
3890 {
3891  fr_dict_t *dict;
3893 
3894  for (dict = fr_dict_global_ctx_iter_init(&iter);
3895  dict != NULL;
3897  if (xlat_protocol_register(dict) < 0) return -1;
3898  }
3899 
3900  /*
3901  * And the internal protocol, too.
3902  */
3903  if (xlat_protocol_register(fr_dict_internal()) < 0) return -1;
3904 
3905  return 0;
3906 }
3907 
3908 
3909 /** Global initialisation for xlat
3910  *
3911  * @note Free memory with #xlat_free
3912  *
3913  * @return
3914  * - 0 on success.
3915  * - -1 on failure.
3916  *
3917  * @hidecallgraph
3918  */
3919 int xlat_global_init(TALLOC_CTX *ctx)
3920 {
3921  xlat_t *xlat;
3922 
3923  if (xlat_func_init() < 0) return -1;
3924 
3925  /*
3926  * Lookup attributes used by virtual xlat expansions.
3927  */
3928  if (xlat_eval_init() < 0) return -1;
3929 
3930  /*
3931  * Registers async xlat operations in the `unlang` interpreter.
3932  */
3933  unlang_xlat_init();
3934 
3935  /*
3936  * These are all "pure" functions.
3937  */
3938 #define XLAT_REGISTER_ARGS(_xlat, _func, _return_type, _args) \
3939 do { \
3940  if (unlikely((xlat = xlat_func_register(ctx, _xlat, _func, _return_type)) == NULL)) return -1; \
3941  xlat_func_args_set(xlat, _args); \
3942  xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
3943 } while (0)
3944 
3963 
3964  /*
3965  * The inputs to these functions are variable.
3966  */
3967 #undef XLAT_REGISTER_ARGS
3968 #define XLAT_REGISTER_ARGS(_xlat, _func, _return_type, _args) \
3969 do { \
3970  if (unlikely((xlat = xlat_func_register(ctx, _xlat, _func, _return_type)) == NULL)) return -1; \
3971  xlat_func_args_set(xlat, _args); \
3972  xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_INTERNAL); \
3973 } while (0)
3974 
3986 #ifdef HAVE_REGEX_PCRE2
3987  xlat_func_instantiate_set(xlat, xlat_instantiate_subst_regex, xlat_subst_regex_inst_t, NULL, NULL);
3988 #endif
3993 
3994  if (unlikely((xlat = xlat_func_register(ctx, "untaint", xlat_func_untaint, FR_TYPE_VOID)) == NULL)) return -1;
3996 
3997  if (unlikely((xlat = xlat_func_register(ctx, "taint", xlat_func_taint, FR_TYPE_VOID)) == NULL)) return -1;
3999 
4000  /*
4001  * All of these functions are pure.
4002  */
4003 #define XLAT_REGISTER_MONO(_xlat, _func, _return_type, _arg) \
4004 do { \
4005  if (unlikely((xlat = xlat_func_register(ctx, _xlat, _func, _return_type)) == NULL)) return -1; \
4006  xlat_func_mono_set(xlat, _arg); \
4007  xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
4008 } while (0)
4009 
4010 
4016 #if defined(HAVE_REGEX_PCRE) || defined(HAVE_REGEX_PCRE2)
4017  if (unlikely((xlat = xlat_func_register(ctx, "regex", xlat_func_regex, FR_TYPE_STRING)) == NULL)) return -1;
4019 #endif
4021 
4022 #ifdef HAVE_OPENSSL_EVP_H
4023  XLAT_REGISTER_MONO("sha2_224", xlat_func_sha2_224, FR_TYPE_OCTETS, xlat_func_sha_arg);
4024  XLAT_REGISTER_MONO("sha2_256", xlat_func_sha2_256, FR_TYPE_OCTETS, xlat_func_sha_arg);
4025  XLAT_REGISTER_MONO("sha2_384", xlat_func_sha2_384, FR_TYPE_OCTETS, xlat_func_sha_arg);
4026  XLAT_REGISTER_MONO("sha2_512", xlat_func_sha2_512, FR_TYPE_OCTETS, xlat_func_sha_arg);
4027 
4028  XLAT_REGISTER_MONO("blake2s_256", xlat_func_blake2s_256, FR_TYPE_OCTETS, xlat_func_sha_arg);
4029  XLAT_REGISTER_MONO("blake2b_512", xlat_func_blake2b_512, FR_TYPE_OCTETS, xlat_func_sha_arg);
4030 
4031 # if OPENSSL_VERSION_NUMBER >= 0x10101000L
4032  XLAT_REGISTER_MONO("sha3_224", xlat_func_sha3_224, FR_TYPE_OCTETS, xlat_func_sha_arg);
4033  XLAT_REGISTER_MONO("sha3_256", xlat_func_sha3_256, FR_TYPE_OCTETS, xlat_func_sha_arg);
4034  XLAT_REGISTER_MONO("sha3_384", xlat_func_sha3_384, FR_TYPE_OCTETS, xlat_func_sha_arg);
4035  XLAT_REGISTER_MONO("sha3_512", xlat_func_sha3_512, FR_TYPE_OCTETS, xlat_func_sha_arg);
4036 # endif
4037 #endif
4038 
4047 
4048 #undef XLAT_REGISTER_MONO
4049 #define XLAT_REGISTER_MONO(_xlat, _func, _return_type, _arg) \
4050 do { \
4051  if (unlikely((xlat = xlat_func_register(ctx, _xlat, _func, _return_type)) == NULL)) return -1; \
4052  xlat_func_mono_set(xlat, _arg); \
4053  xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_INTERNAL); \
4054 } while (0)
4055 
4058 
4059  return xlat_register_expressions();
4060 }
4061 
4062 /** De-register all xlat functions we created
4063  *
4064  */
4066 {
4067  xlat_func_free();
4068 
4069  xlat_eval_free();
4070 }
static int const char char buffer[256]
Definition: acutest.h:574
int const char * file
Definition: acutest.h:702
int n
Definition: acutest.h:577
va_list args
Definition: acutest.h:770
static int const char * fmt
Definition: acutest.h:573
#define fr_base16_encode(_out, _in)
Definition: base16.h:57
#define fr_base16_decode(_err, _out, _in, _no_trailing)
Definition: base16.h:95
#define fr_base64_decode(_out, _in, _expect_padding, _no_trailing)
Definition: base64.h:81
#define FR_BASE64_DEC_LENGTH(_inlen)
Definition: base64.h:44
#define FR_BASE64_ENC_LENGTH(_inlen)
Encode/decode binary data using printable characters (base64 format)
Definition: base64.h:43
size_t fr_base64_encode(char *restrict out, size_t outlen, uint8_t const *restrict in, size_t inlen)
static dl_t * dl
Definition: fuzzer.c:42
static fr_dict_t * dict
Definition: fuzzer.c:46
static bool stop
Definition: radmin.c:70
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define RCSID(id)
Definition: build.h:444
#define unlikely(_x)
Definition: build.h:378
#define UNUSED
Definition: build.h:313
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:509
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_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
fr_dict_t * fr_dict_global_ctx_iter_init(fr_dict_global_ctx_iter_t *iter)
Iterate protocols by name.
Definition: dict_util.c:4161
dl_t * fr_dict_dl(fr_dict_t const *dict)
Definition: dict_util.c:2007
char const * name
Vendor name.
Definition: dict.h:232
static fr_slen_t err
Definition: dict.h:645
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
uint32_t pen
Private enterprise number.
Definition: dict.h:228
fr_dict_t const * fr_dict_internal(void)
Definition: dict_util.c:4204
fr_dict_vendor_t const * fr_dict_vendor_by_da(fr_dict_attr_t const *da)
Look up a vendor by one of its child attributes.
Definition: dict_util.c:2232
fr_dict_t * fr_dict_global_ctx_iter_next(fr_dict_global_ctx_iter_t *iter)
Definition: dict_util.c:4168
static fr_slen_t in
Definition: dict.h:645
Private enterprise.
Definition: dict.h:227
Test enumeration values.
Definition: dict_test.h:92
void * handle
Handle returned by dlopen.
Definition: dl.h:62
Module handle.
Definition: dl.h:58
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition: dlist.h:555
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
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition: dlist.h:486
static xlat_action_t xlat_func_next_time(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Calculate number of seconds until the next n hour(s), day(s), week(s), year(s).
static xlat_action_t xlat_func_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Dynamically evaluate an expansion string.
static xlat_action_t xlat_func_lpad(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
lpad a string
static xlat_action_t xlat_func_bin(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Convert hex string to binary.
static xlat_action_t xlat_func_subst(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Perform regex substitution.
static xlat_action_t xlat_func_urlunquote(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
URLdecode special characters.
static xlat_action_t xlat_func_base64_decode(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Decode base64 string.
static xlat_action_t xlat_func_hmac_md5(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in)
Generate the HMAC-MD5 of a string or attribute.
static xlat_action_t xlat_func_base64_encode(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Encode string or attribute as base64.
static xlat_action_t xlat_func_log_info(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Log something at INFO level.
static xlat_action_t xlat_func_log_warn(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Log something at WARN level.
static xlat_action_t xlat_func_map(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Processes fmt as a map string and applies it to the current request.
static xlat_action_t protocol_decode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Decode any protocol attribute / options.
static xlat_action_t xlat_func_debug(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Dynamically change the debugging level for the current request.
Definition: xlat_builtin.c:115
static xlat_action_t xlat_func_log_debug(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Log something at DEBUG level.
static xlat_action_t xlat_func_log_dst(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Change the log destination to the named one.
static xlat_arg_parser_t const xlat_func_string_arg[]
Calculate any digest supported by OpenSSL EVP_MD.
static xlat_action_t xlat_func_concat(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Concatenate string representation of values of given attributes using separator.
static xlat_action_t xlat_func_urlquote(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *args)
URLencode special characters.
static xlat_action_t xlat_func_rpad(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Right pad a string.
static xlat_action_t xlat_func_md4(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *args)
Calculate the MD4 hash of a string or attribute.
static xlat_action_t xlat_func_explode(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Split a string into multiple new strings based on a delimiter.
Definition: xlat_builtin.c:816
static xlat_action_t xlat_func_string(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in)
Print data as string, if possible.
static xlat_action_t xlat_func_substr(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Extract a substring from string / octets data.
static xlat_action_t xlat_func_length(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in)
Return the on-the-wire size of the boxes in bytes.
static xlat_action_t xlat_func_immutable_attr(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Mark one or more attributes as immutable.
Definition: xlat_builtin.c:899
static xlat_action_t xlat_func_rand(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in)
Generate a random integer value.
static xlat_action_t xlat_func_log_err(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Log something at DEBUG level.
static xlat_action_t xlat_func_hmac_sha1(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in)
Generate the HMAC-SHA1 of a string or attribute.
static xlat_action_t xlat_func_integer(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Print data as integer, not as VALUE.
Definition: xlat_builtin.c:959
static xlat_action_t xlat_func_time(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Return the time as a FR_TYPE_DATE.
static xlat_action_t xlat_func_toupper(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Convert a string to uppercase.
static xlat_action_t xlat_func_cast(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Cast one or more output value-boxes to the given type.
static xlat_action_t xlat_func_hex(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *args)
Print data as hex, not as VALUE.
static xlat_action_t xlat_func_md5(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *args)
Calculate the MD5 hash of a string or attribute.
static xlat_action_t xlat_func_sha1(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *args)
Calculate the SHA1 hash of a string or attribute.
static xlat_action_t xlat_func_randstr(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Generate a string of random chars.
static xlat_action_t xlat_func_tolower(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Convert a string to lowercase.
static xlat_action_t xlat_func_debug_attr(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Print out attribute info.
Definition: xlat_builtin.c:298
static xlat_action_t xlat_func_pairs(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Encode attributes as a series of string attribute/value pairs.
static xlat_action_t xlat_func_strlen(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *args)
Print length of given string.
static xlat_action_t protocol_encode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Encode protocol attributes / options.
Stores the state of the current iteration operation.
Definition: hash.h:41
int fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen, uint8_t const *key, size_t key_len)
Calculate HMAC using internal MD5 implementation.
Definition: hmac_md5.c:119
int fr_hmac_sha1(uint8_t digest[static SHA1_DIGEST_LENGTH], uint8_t const *in, size_t inlen, uint8_t const *key, size_t key_len)
Calculate HMAC using internal SHA1 implementation.
Definition: hmac_sha1.c:124
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition: interpret.c:1745
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
#define UNLANG_SUB_FRAME
Definition: interpret.h:36
fr_log_t * log_dst_by_name(char const *name)
Get a logging destination by name.
Definition: log.c:1063
#define PERROR(_fmt,...)
Definition: log.h:228
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:443
#define RWDEBUG(fmt,...)
Definition: log.h:361
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition: log.h:335
#define REDEBUG3(fmt,...)
Definition: log.h:373
#define RPERROR(fmt,...)
Definition: log.h:302
#define REMARKER(_str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
Definition: log.h:498
#define RINFO(fmt,...)
Definition: log.h:296
#define RMARKER(_type, _lvl, _str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
Definition: log.h:469
#define RPEDEBUG(fmt,...)
Definition: log.h:376
#define RDEBUG4(fmt,...)
Definition: log.h:344
#define RDEBUG_ENABLED4
True if request debug level 1-4 messages are enabled.
Definition: log.h:336
#define RIDEBUG2(fmt,...)
Definition: log.h:352
#define REDEBUG2(fmt,...)
Definition: log.h:372
#define RIDEBUG3(fmt,...)
Definition: log.h:353
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:430
int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t const *map, UNUSED void *uctx)
Convert a map to a fr_pair_t.
Definition: map.c:1489
int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert map_t to fr_pair_t (s) and add them to a request_t.
Definition: map.c:1783
int map_afrom_attr_str(TALLOC_CTX *ctx, map_t **out, char const *vp_str, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules)
Convert a value pair string to valuepair map.
Definition: map.c:1320
talloc_free(reap)
@ L_DST_NULL
Discard log messages.
Definition: log.h:83
@ L_DST_FILES
Log to a file on disk.
Definition: log.h:79
@ L_DBG_LVL_DISABLE
Don't print messages.
Definition: log.h:68
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
Definition: log.h:71
@ L_DBG_LVL_MAX
Lowest priority debug messages (-xxxxx | -Xxxx).
Definition: log.h:74
@ L_WARN
Warning.
Definition: log.h:57
void fr_md4_calc(uint8_t out[static MD4_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
Calculate the MD4 hash of the contents of a buffer.
Definition: md4.c:489
#define MD4_DIGEST_LENGTH
Definition: md4.h:25
@ TMPL_ATTR_REF_PREFIX_AUTO
Attribute refs may have a '&' prefix.
Definition: merged_model.c:231
#define MD5_DIGEST_LENGTH
Definition: merged_model.c:248
unsigned short uint16_t
Definition: merged_model.c:31
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
Definition: merged_model.c:113
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
Definition: merged_model.c:86
@ FR_TYPE_INT8
8 Bit signed integer.
Definition: merged_model.c:103
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
Definition: merged_model.c:93
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
Definition: merged_model.c:89
@ 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_INT64
64 Bit signed integer.
Definition: merged_model.c:106
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
Definition: merged_model.c:111
@ 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_INT32
32 Bit signed integer.
Definition: merged_model.c:105
@ FR_TYPE_UINT64
64 Bit unsigned integer.
Definition: merged_model.c:100
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
Definition: merged_model.c:88
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
Definition: merged_model.c:87
@ FR_TYPE_VOID
User data.
Definition: merged_model.c:127
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
Definition: merged_model.c:115
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
void fr_md5_calc(uint8_t out[static MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
Perform a single digest operation on a single input buffer.
Definition: merged_model.c:251
unsigned char uint8_t
Definition: merged_model.c:30
ssize_t fr_slen_t
Definition: merged_model.c:35
long long int off_t
Definition: merged_model.c:22
unsigned long int size_t
Definition: merged_model.c:25
fr_sbuff_parse_error_t
Definition: merged_model.c:45
size_t fr_snprint_uint128(char *out, size_t outlen, uint128_t const num)
Write 128bit unsigned integer to buffer.
Definition: misc.c:360
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
static fr_internal_encode_ctx_t encode_ctx
static bool done
Definition: radclient.c:80
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG_ENABLED2()
Definition: radclient.h:50
#define RDEBUG(fmt,...)
Definition: radclient.h:53
#define RIDEBUG(fmt,...)
Definition: radsniff.h:65
#define fill(_expr)
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
fr_dict_attr_t const * request_attr_request
Definition: request.c:41
void request_log_prepend(request_t *request, fr_log_t *log_dst, fr_log_lvl_t lvl)
Prepend another logging destination to the list.
Definition: request.c:96
#define RAD_REQUEST_LVL_NONE
No debug messages should be printed.
Definition: request.h:278
static char const * name
ssize_t fr_sbuff_in_escape(fr_sbuff_t *sbuff, char const *in, size_t inlen, fr_sbuff_escape_rules_t const *e_rules)
Print an escaped string to an sbuff.
Definition: sbuff.c:1579
char * fr_sbuff_adv_to_str(fr_sbuff_t *sbuff, size_t len, char const *needle, size_t needle_len)
Wind position to the first instance of the specified needle.
Definition: sbuff.c:1951
char * fr_sbuff_adv_to_chr(fr_sbuff_t *sbuff, size_t len, char c)
Wind position to first instance of specified char.
Definition: sbuff.c:1915
ssize_t fr_sbuff_in_bstrncpy(fr_sbuff_t *sbuff, char const *str, size_t len)
Copy bytes into the sbuff up to the first \0.
Definition: sbuff.c:1445
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
Definition: sbuff.c:2047
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_set(_dst, _src)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_adv_past_whitespace(_sbuff, _len, _tt)
#define fr_sbuff_current(_sbuff_or_marker)
char const * name
Name for rule set to aid we debugging.
Definition: sbuff.h:177
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_init_in(_out, _start, _len_or_end)
#define fr_sbuff_remaining(_sbuff_or_marker)
#define fr_sbuff_len(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_move(_out, _in, _len)
#define fr_sbuff_used(_sbuff_or_marker)
#define fr_sbuff_behind(_sbuff_or_marker)
#define fr_sbuff_ahead(_sbuff_or_marker)
#define fr_sbuff_in_char(_sbuff,...)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Set of parsing rules for *unescape_until functions.
Definition: merged_model.c:163
int tmpl_find_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt))
Returns the first VP matching a tmpl_t.
Definition: tmpl_eval.c:887
static fr_slen_t vpt
Definition: tmpl.h:1260
static char const * tmpl_list_name(fr_dict_attr_t const *list, char const *def)
Return the name of a tmpl list or def if list not provided.
Definition: tmpl.h:910
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.
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
Definition: tmpl.h:146
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
Definition: tmpl.h:150
@ TMPL_TYPE_EXEC
Callout to an external script or program.
Definition: tmpl.h:154
@ TMPL_TYPE_REGEX_XLAT_UNRESOLVED
A regular expression with unresolved xlat functions or attribute references.
Definition: tmpl.h:201
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition: tmpl.h:142
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
Definition: tmpl.h:183
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition: tmpl.h:344
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
Definition: tmpl.h:899
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
Definition: tmpl.h:629
Optional arguments passed to vp_tmpl functions.
Definition: tmpl.h:341
void fr_sha1_init(fr_sha1_ctx *context)
Definition: sha1.c:93
void fr_sha1_final(uint8_t digest[static SHA1_DIGEST_LENGTH], fr_sha1_ctx *context)
Definition: sha1.c:141
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *in, size_t len)
Definition: sha1.c:105
#define SHA1_DIGEST_LENGTH
Definition: sha1.h:29
static char buff[sizeof("18446744073709551615")+3]
Definition: size_tests.c:41
static char const hex[]
Definition: smbencrypt.c:35
PRIVATE void strings(struct DATA *p, char *tmp)
Definition: snprintf.c:330
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:689
return count
Definition: module.c:175
if(!subtype_vp) goto fail
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
fr_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition: state_test.c:8
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:34
Definition: log.h:96
fr_log_t * parent
Log destination this was cloned from.
Definition: log.h:121
fr_log_dst_t dst
Log destination.
Definition: log.h:97
int fd
File descriptor to write messages to.
Definition: log.h:112
char const * file
Path to log file.
Definition: log.h:113
Value pair map.
Definition: map.h:77
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
Definition: map.h:78
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
Definition: map.h:79
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition: tmpl.h:285
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
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:134
An element in an arbitrarily ordered array of name to num mappings.
Definition: table.h:53
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition: talloc.c:452
char * talloc_bstr_append(TALLOC_CTX *ctx, char *to, char const *from, size_t from_len)
Append a bstr to a bstr.
Definition: talloc.c:480
#define talloc_get_type_abort_const
Definition: talloc.h:270
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition: test_point.h:84
fr_pair_decode_t func
Decoder for pairs.
Definition: test_point.h:85
Entry point for pair decoders.
Definition: test_point.h:83
Entry point for pair encoders.
Definition: test_point.h:91
bool fr_time_is_dst(void)
Whether or not we're daylight savings.
Definition: time.c:1241
int fr_unix_time_from_str(fr_unix_time_t *date, char const *date_str, fr_time_res_t hint)
Convert string in various formats to a fr_unix_time_t.
Definition: time.c:827
fr_time_delta_t fr_time_gmtoff(void)
Get the offset to gmt.
Definition: time.c:1233
static int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
Definition: time.h:504
#define fr_time_delta_wrap(_time)
Definition: time.h:152
@ FR_TIME_RES_SEC
Definition: time.h:50
#define NSEC
Definition: time.h:377
static uint64_t fr_unix_time_unwrap(fr_unix_time_t time)
Definition: time.h:161
static fr_unix_time_t fr_time_to_unix_time(fr_time_t when)
Convert an fr_time_t (internal time) to our version of unix time (wallclock time)
Definition: time.h:686
"Unix" time.
Definition: time.h:95
void tmpl_dcursor_clear(tmpl_dcursor_ctx_t *cc)
Clear any temporary state allocations.
Definition: tmpl_dcursor.c:419
#define tmpl_dcursor_init(_err, _ctx, _cc, _cursor, _request, _vpt)
Definition: tmpl_dcursor.h:99
Maintains state between cursor calls.
Definition: tmpl_dcursor.h:61
VALUE_BOX_LIST_VERIFY(list)
xlat_arg_parser_t const trigger_xlat_args[]
Definition: trigger.c:56
xlat_action_t trigger_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Retrieve attributes from a special trigger list.
Definition: trigger.c:64
close(uq->fd)
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
void unlang_xlat_init(void)
Register xlat operation with the interpreter.
Definition: xlat.c:586
bool xlat_is_literal(xlat_exp_head_t const *head)
Check to see if the expansion consists entirely of value-box elements.
bool required
Argument must be present, and non-empty.
Definition: xlat.h:146
@ 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
bool concat
Concat boxes together.
Definition: xlat.h:147
bool single
Argument must only contain a single box.
Definition: xlat.h:148
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition: xlat.h:365
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.
int xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules)
Walk over an xlat tree recursively, resolving any unresolved functions or references.
#define XLAT_ARG_PARSER_TERMINATOR
Definition: xlat.h:166
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
Definition for a single argument consumend by an xlat function.
Definition: xlat.h:145
static fr_slen_t fr_pair_aprint(TALLOC_CTX *ctx, char **out, fr_dict_attr_t const *parent, fr_pair_t const *vp) 1(fr_pair_print
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition: pair_inline.c:70
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition: strerror.c:577
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
Definition: types.c:31
size_t fr_type_table_len
Definition: types.c:84
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_string(_x)
Definition: types.h:327
#define fr_type_is_numeric(_x)
Definition: types.h:361
#define FR_TYPE_STRUCTURAL
Definition: types.h:296
#define fr_type_is_null(_x)
Definition: types.h:326
#define fr_type_is_leaf(_x)
Definition: types.h:372
#define fr_type_is_integer(_x)
Definition: types.h:360
#define FR_TYPE_LEAF
Definition: types.h:297
#define FR_TYPE_NUMERIC
Definition: types.h:286
size_t fr_value_box_network_length(fr_value_box_t const *value)
Get the size of the value held by the fr_value_box_t.
Definition: value.c:1280
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
Definition: value.c:5301
int fr_value_box_mem_alloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv, size_t len, bool tainted)
Pre-allocate an octets buffer for filling by the caller.
Definition: value.c:4320
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:3301
int fr_value_box_mem_realloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, size_t len)
Change the length of a buffer already allocated to a value box.
Definition: value.c:4353
void fr_value_box_list_untaint(fr_value_box_list_t *head)
Untaint every list member (and their children)
Definition: value.c:6164
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
ssize_t fr_value_box_list_concat_as_string(bool *tainted, bool *secret, fr_sbuff_t *sbuff, fr_value_box_list_t *list, char const *sep, size_t sep_len, fr_sbuff_escape_rules_t const *e_rules, fr_value_box_list_action_t proc_action, bool flatten)
Concatenate a list of value boxes together.
Definition: value.c:5532
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
FR_SBUFF_SET_RETURN(sbuff, &our_sbuff)
void fr_value_box_strdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a buffer containing a nul terminated string to a box, but don't copy it.
Definition: value.c:3985
int fr_value_box_bstr_alloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv, size_t len, bool tainted)
Alloc and assign an empty \0 terminated string to a fr_value_box_t.
Definition: value.c:4020
bool fr_value_box_list_tainted(fr_value_box_list_t const *head)
Check to see if any list members (or their children) are tainted.
Definition: value.c:6134
int fr_value_box_bstr_realloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, size_t len)
Change the length of a buffer already allocated to a value box.
Definition: value.c:4053
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_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Copy a buffer to a fr_value_box_t.
Definition: value.c:4417
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
@ FR_VALUE_BOX_LIST_FREE_BOX
Free each processed box.
Definition: value.h:211
#define fr_value_box_list_foreach_safe(_list_head, _iter)
Definition: value.h:200
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:608
static bool fr_value_box_is_secret(fr_value_box_t const *box)
Definition: value.h:1047
static fr_slen_t data
Definition: value.h:1259
static void fr_value_box_set_secret(fr_value_box_t *box, bool secret)
Definition: value.h:1067
#define fr_box_is_variable_size(_x)
Definition: value.h:434
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition: value.h:619
static void fr_value_box_set_immutable(fr_value_box_t *box)
Definition: value.h:1073
#define fr_value_box_list_foreach(_list_head, _iter)
Definition: value.h:199
static size_t char ** out
Definition: value.h:984
#define fr_box_bool(_val)
Definition: value.h:301
static xlat_arg_parser_t const xlat_func_bin_arg[]
static xlat_arg_parser_t const xlat_func_map_arg[]
static xlat_arg_parser_t const xlat_func_log_dst_args[]
static xlat_arg_parser_t const protocol_decode_xlat_args[]
static xlat_arg_parser_t const xlat_func_time_args[]
static xlat_arg_parser_t const xlat_func_base64_encode_arg[]
static xlat_arg_parser_t const xlat_func_debug_attr_args[]
Definition: xlat_builtin.c:149
static int _log_dst_free(fr_log_t *log)
static xlat_action_t xlat_func_file_size(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Definition: xlat_builtin.c:572
static xlat_action_t xlat_hmac(TALLOC_CTX *ctx, fr_dcursor_t *out, fr_value_box_list_t *args, uint8_t *digest, int digest_len, hmac_type type)
int xlat_fmt_get_vp(fr_pair_t **out, request_t *request, char const *name)
Return a VP from the specified request.
Definition: xlat_builtin.c:76
static xlat_arg_parser_t const xlat_func_log_arg[]
static xlat_arg_parser_t const xlat_func_sha_arg[]
static xlat_arg_parser_t const xlat_func_cast_args[]
int xlat_global_init(TALLOC_CTX *ctx)
Global initialisation for xlat.
hmac_type
@ HMAC_MD5
@ HMAC_SHA1
xlat_action_t xlat_transparent(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *args)
Common function to move boxes form input list to output list.
Definition: xlat_builtin.c:269
static xlat_arg_parser_t const xlat_func_hex_arg[]
static xlat_arg_parser_t const xlat_func_pairs_args[]
static ssize_t xlat_file_escape_path(fr_sbuff_t *in, fr_value_box_t *vb)
Escape the paths as necessary.
Definition: xlat_builtin.c:382
static xlat_arg_parser_t const xlat_func_substr_args[]
static xlat_action_t xlat_func_file_exists(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *args)
Definition: xlat_builtin.c:493
static const char * xlat_file_name(fr_value_box_t *vb)
Definition: xlat_builtin.c:445
static xlat_action_t xlat_func_join(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in)
Join a series of arguments to form a single list.
static xlat_arg_parser_t const xlat_func_randstr_arg[]
static xlat_arg_parser_t const xlat_func_eval_arg[]
static xlat_arg_parser_t const xlat_func_subst_args[]
static xlat_arg_parser_t const xlat_func_explode_args[]
Definition: xlat_builtin.c:794
int xlat_protocols_register(void)
Register xlats for any loaded dictionaries.
#define REPETITION_MAX
void xlat_debug_attr_list(request_t *request, fr_pair_list_t const *list)
Definition: xlat_builtin.c:252
static const fr_sbuff_escape_rules_t xlat_filename_escape_dots
Definition: xlat_builtin.c:364
static xlat_arg_parser_t const xlat_change_case_arg[]
static xlat_arg_parser_t const xlat_func_strlen_arg[]
static int xlat_protocol_register(fr_dict_t const *dict)
static xlat_arg_parser_t const xlat_func_md5_arg[]
static xlat_arg_parser_t const xlat_func_urlquote_arg[]
static void ungroup(fr_dcursor_t *out, fr_value_box_list_t *in)
static xlat_arg_parser_t const xlat_func_md4_arg[]
static xlat_arg_parser_t const xlat_func_immutable_attr_args[]
Definition: xlat_builtin.c:885
static xlat_arg_parser_t const xlat_func_join_args[]
static xlat_action_t xlat_eval_resume(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
Just serves to push the result up the stack.
static xlat_action_t xlat_func_taint(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in)
Definition: xlat_builtin.c:773
static xlat_arg_parser_t const xlat_func_debug_args[]
Definition: xlat_builtin.c:101
static char const hextab[]
Definition: xlat_builtin.c:62
static xlat_action_t xlat_func_file_head(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Definition: xlat_builtin.c:514
static xlat_arg_parser_t const xlat_func_pad_args[]
static xlat_arg_parser_t const protocol_encode_xlat_args[]
static int xlat_eval_instantiate(xlat_inst_ctx_t const *xctx)
static xlat_arg_parser_t const xlat_func_urlunquote_arg[]
static xlat_action_t xlat_func_file_escape(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *args)
Definition: xlat_builtin.c:470
void xlat_debug_attr_vp(request_t *request, fr_pair_t *vp, tmpl_t const *vpt)
Definition: xlat_builtin.c:154
static xlat_arg_parser_t const xlat_func_rand_arg[]
static xlat_action_t xlat_func_file_tail(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Definition: xlat_builtin.c:598
static xlat_arg_parser_t const xlat_func_concat_args[]
static xlat_arg_parser_t const xlat_func_file_name_count_args[]
Definition: xlat_builtin.c:463
static xlat_arg_parser_t const xlat_func_integer_args[]
Definition: xlat_builtin.c:943
#define XLAT_REGISTER_ARGS(_xlat, _func, _return_type, _args)
static xlat_action_t xlat_func_untaint(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in)
Definition: xlat_builtin.c:759
#define XLAT_REGISTER_MONO(_xlat, _func, _return_type, _arg)
xlat_exp_head_t * ex
static xlat_arg_parser_t const xlat_func_length_args[]
static xlat_action_t xlat_change_case(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED request_t *request, fr_value_box_list_t *args, bool upper)
Change case of a string.
static xlat_action_t xlat_func_ungroup(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *in)
Ungroups all of its arguments into one flat list.
static int protocol_xlat_instantiate(xlat_inst_ctx_t const *mctx)
return XLAT_ACTION_DONE
Definition: xlat_builtin.c:278
static xlat_arg_parser_t const xlat_func_file_name_args[]
Definition: xlat_builtin.c:458
static xlat_arg_parser_t const xlat_func_next_time_args[]
static const fr_sbuff_escape_rules_t xlat_filename_escape
Definition: xlat_builtin.c:348
static xlat_arg_parser_t const xlat_func_base64_decode_arg[]
static xlat_arg_parser_t const xlat_hmac_args[]
void xlat_global_free(void)
De-register all xlat functions we created.
static xlat_action_t xlat_func_file_rm(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Definition: xlat_builtin.c:736
void * rctx
Resume context.
Definition: xlat_ctx.h:47
void * inst
xlat instance data to populate.
Definition: xlat_ctx.h:55
void const * inst
xlat instance data.
Definition: xlat_ctx.h:43
xlat_exp_t * ex
Tokenized expression to use in expansion.
Definition: xlat_ctx.h:56
void * uctx
Passed to the registration function.
Definition: xlat_ctx.h:58
An xlat calling ctx.
Definition: xlat_ctx.h:42
An xlat instantiation ctx.
Definition: xlat_ctx.h:54
int xlat_eval_init(void)
Definition: xlat_eval.c:1639
void xlat_eval_free(void)
Definition: xlat_eval.c:1664
int xlat_register_expressions(void)
Definition: xlat_expr.c:1807
void xlat_func_free(void)
Definition: xlat_func.c:578
void xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags)
Specify flags that alter the xlat's behaviour.
Definition: xlat_func.c:415
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition: xlat_func.c:360
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition: xlat_func.c:195
xlat_t * xlat_func_find(char const *in, ssize_t inlen)
Definition: xlat_func.c:56
int xlat_func_init(void)
Definition: xlat_func.c:562
#define xlat_func_instantiate_set(_xlat, _instantiate, _inst_struct, _detach, _uctx)
Set a callback for global instantiation of xlat functions.
Definition: xlat_func.h:91
@ XLAT_FUNC_FLAG_PURE
Definition: xlat_func.h:38
@ XLAT_FUNC_FLAG_INTERNAL
Definition: xlat_func.h:39
int xlat_decode_value_box_list(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, void *decode_ctx, fr_pair_decode_t decode, fr_value_box_list_t *in)
Decode all of the value boxes into the output cursor.
Definition: xlat_pair.c:90
@ XLAT_GROUP
encapsulated string of xlats
Definition: xlat_priv.h:113
xlat_type_t _CONST type
type of this expansion.
Definition: xlat_priv.h:154
An xlat expansion node.
Definition: xlat_priv.h:147