The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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: 651e9a567975dc6be12970a837e10d26fc54ca1b $
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 */
26RCSID("$Id: 651e9a567975dc6be12970a837e10d26fc54ca1b $")
27
28/**
29 * @defgroup xlat_functions xlat expansion functions
30 */
31#include <freeradius-devel/server/base.h>
32#include <freeradius-devel/server/tmpl_dcursor.h>
33#include <freeradius-devel/unlang/interpret.h>
34#include <freeradius-devel/unlang/xlat_priv.h>
35
36#include <freeradius-devel/unlang/xlat.h>
37#include <freeradius-devel/io/test_point.h>
38
39#include <freeradius-devel/util/base16.h>
40#include <freeradius-devel/util/dbuff.h>
41#include <freeradius-devel/util/dcursor.h>
42#include <freeradius-devel/util/pair.h>
43#include <freeradius-devel/util/table.h>
44
45#ifdef HAVE_OPENSSL_EVP_H
46# include <freeradius-devel/tls/openssl_user_macros.h>
47# include <openssl/evp.h>
48#endif
49
50#include <sys/stat.h>
51#include <fcntl.h>
52
53static char const hextab[] = "0123456789abcdef";
54static TALLOC_CTX *xlat_ctx;
55
56typedef struct {
58 fr_dict_t const *dict; //!< Restrict xlat to this namespace
60
61/*
62 * Regular xlat functions
63 */
65 { .single = true, .type = FR_TYPE_INT8 },
67};
68
69/** Dynamically change the debugging level for the current request
70 *
71 * Example:
72@verbatim
73%debug(3)
74@endverbatim
75 *
76 * @ingroup xlat_functions
77 */
79 UNUSED xlat_ctx_t const *xctx,
80 request_t *request, fr_value_box_list_t *args)
81{
82 int level = 0;
83 fr_value_box_t *vb, *lvl_vb;
84
85 XLAT_ARGS(args, &lvl_vb);
86
87 /*
88 * Expand to previous (or current) level
89 */
90 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_INT8, NULL));
91 vb->vb_int8 = request->log.lvl;
93
94 /*
95 * Assume we just want to get the current value and NOT set it to 0
96 */
97 if (!lvl_vb) goto done;
98
99 level = lvl_vb->vb_int8;
100 if (level == 0) {
101 request->log.lvl = RAD_REQUEST_LVL_NONE;
102 } else {
103 if (level > L_DBG_LVL_MAX) level = L_DBG_LVL_MAX;
104 request->log.lvl = level;
105 }
106
107done:
108 return XLAT_ACTION_DONE;
109}
110
111
116
118{
119 fr_dict_vendor_t const *vendor;
121 size_t i;
122
123 switch (vp->vp_type) {
125 if (vpt) {
126 RIDEBUG2("%s.%s = {",
127 tmpl_list_name(tmpl_list(vpt), "<INVALID>"),
128 vp->da->name);
129 } else {
130 RIDEBUG2("%s = {", vp->da->name);
131 }
132 RINDENT();
133 xlat_debug_attr_list(request, &vp->vp_group);
134 REXDENT();
135 RIDEBUG2("}");
136 break;
137
138 default:
139 if (vpt) {
140 RIDEBUG2("%s.%s = %pV",
141 tmpl_list_name(tmpl_list(vpt), "<INVALID>"),
142 vp->da->name,
143 &vp->data);
144 } else {
145 RIDEBUG2("%s = %pV", vp->da->name, &vp->data);
146 }
147 }
148
149 if (!RDEBUG_ENABLED3) return;
150
151 RINDENT();
152 RIDEBUG3("da : %p", vp->da);
153 RIDEBUG3("is_raw : %pV", fr_box_bool(vp->vp_raw));
154 RIDEBUG3("is_unknown : %pV", fr_box_bool(vp->da->flags.is_unknown));
155
156 if (RDEBUG_ENABLED3) {
157 RIDEBUG3("parent : %s (%p)", vp->da->parent->name, vp->da->parent);
158 } else {
159 RIDEBUG2("parent : %s", vp->da->parent->name);
160 }
161 RIDEBUG3("attr : %u", vp->da->attr);
162 vendor = fr_dict_vendor_by_da(vp->da);
163 if (vendor) RIDEBUG2("vendor : %u (%s)", vendor->pen, vendor->name);
164 RIDEBUG3("type : %s", fr_type_to_str(vp->vp_type));
165
166 switch (vp->vp_type) {
167 case FR_TYPE_LEAF:
168 if (fr_box_is_variable_size(&vp->data)) {
169 RIDEBUG3("length : %zu", vp->vp_length);
170 }
171 RIDEBUG3("tainted : %pV", fr_box_bool(vp->data.tainted));
172 break;
173 default:
174 break;
175 }
176
177 if (!RDEBUG_ENABLED4) {
178 REXDENT();
179 return;
180 }
181
182 for (i = 0; i < fr_type_table_len; i++) {
183 int pad;
184
185 fr_value_box_t *dst = NULL;
186
187 type = &fr_type_table[i];
188
189 if ((fr_type_t) type->value == vp->vp_type) goto next_type;
190
191 /*
192 * Don't cast TO structural, or FROM structural types.
193 */
194 if (!fr_type_is_leaf(type->value) || !fr_type_is_leaf(vp->vp_type)) goto next_type;
195
197 /* We expect some to fail */
198 if (fr_value_box_cast(dst, dst, type->value, NULL, &vp->data) < 0) {
199 goto next_type;
200 }
201
202 if ((pad = (11 - type->name.len)) < 0) pad = 0;
203
204 RINDENT();
205 RDEBUG4("as %s%*s: %pV", type->name.str, pad, " ", dst);
206 REXDENT();
207
208 next_type:
209 talloc_free(dst);
210 }
211
212 REXDENT();
213}
214
216{
217 fr_pair_t *vp;
218
219 for (vp = fr_pair_list_next(list, NULL);
220 vp != NULL;
221 vp = fr_pair_list_next(list, vp)) {
222 xlat_debug_attr_vp(request, vp, NULL);
223 }
224}
225
226/** Common function to move boxes from input list to output list
227 *
228 * This can be used to implement safe_for functions, as the xlat framework
229 * can be used for concatenation, casting, and marking up output boxes as
230 * safe_for.
231 */
233 UNUSED xlat_ctx_t const *xctx,
234 UNUSED request_t *request, fr_value_box_list_t *args)
235{
237 fr_value_box_list_remove(args, vb);
239 }}
240
242}
243
244/** Print out attribute info
245 *
246 * Prints out all instances of a current attribute, or all attributes in a list.
247 *
248 * At higher debugging levels, also prints out alternative decodings of the same
249 * value. This is helpful to determine types for unknown attributes of long
250 * passed vendors, or just crazy/broken NAS.
251 *
252 * This expands to a zero length string.
253 *
254 * Example:
255@verbatim
256%debug.attr(&request)
257@endverbatim
258 *
259 * @ingroup xlat_functions
260 */
262 UNUSED xlat_ctx_t const *xctx,
263 request_t *request, fr_value_box_list_t *args)
264{
265 fr_pair_t *vp;
266 fr_dcursor_t *cursor;
267 fr_value_box_t *in_head;
268
269 XLAT_ARGS(args, &in_head);
270
271 if (!RDEBUG_ENABLED2) return XLAT_ACTION_DONE; /* NOOP if debugging isn't enabled */
272
273 cursor = fr_value_box_get_cursor(in_head);
274
275 RDEBUG("Attributes matching \"%s\"", in_head->vb_cursor_name);
276
277 RINDENT();
278 for (vp = fr_dcursor_current(cursor);
279 vp;
280 vp = fr_dcursor_next(cursor)) {
281 xlat_debug_attr_vp(request, vp, NULL); /* @todo - pass in vpt, too, via the vb_cursor stuff */
282 }
283 REXDENT();
284
285 return XLAT_ACTION_DONE;
286}
287
288#ifdef __clang__
289#pragma clang diagnostic ignored "-Wgnu-designator"
290#endif
291
293 .name = "filename",
294 .chr = '_',
295 .do_utf8 = true,
296 .do_hex = true,
297
298 .esc = {
299 [ 0x00 ... 0x2d ] = true, // special characters, but not '.'
300 [ 0x2f ] = true, // /
301 [ 0x3A ... 0x3f ] = true, // :;<=>?, but not "@"
302 [ 0x5b ... 0x5e ] = true, // [\]^
303 [ 0x60 ] = true, // back-tick
304 [ 0x7b ... 0xff ] = true, // {|}, and all chars which have high bit set, but aren't UTF-8
305 },
306};
307
309 .name = "filename",
310 .chr = '_',
311 .do_utf8 = true,
312 .do_hex = true,
313
314 .esc = {
315 [ 0x00 ... 0x2f ] = true, // special characters, '.', '/', etc.
316 [ 0x3A ... 0x3f ] = true, // :;<=>?, but not "@"
317 [ 0x5b ... 0x5e ] = true, // [\]^
318 [ 0x60 ] = true, // back-tick
319 [ 0x7b ... 0xff ] = true, // {|}, and all chars which have high bit set, but aren't UTF-8
320 },
321};
322
323#define FR_FILENAME_SAFE_FOR ((uintptr_t) filename_xlat_escape)
324
325static int CC_HINT(nonnull(2,3)) filename_xlat_escape(UNUSED request_t *request, fr_value_box_t *vb, UNUSED void *uctx)
326{
327 fr_sbuff_t *out = NULL;
328 fr_value_box_entry_t entry;
329
331
332 /*
333 * Integers are just numbers, so they don't need to be escaped.
334 *
335 * Except that FR_TYPE_INTEGER includes 'date' and 'time_delta', which is annoying.
336 *
337 * 'octets' get printed as hex, so they don't need to be escaped.
338 */
339 switch (vb->type) {
340 case FR_TYPE_BOOL:
341 case FR_TYPE_UINT8:
342 case FR_TYPE_UINT16:
343 case FR_TYPE_UINT32:
344 case FR_TYPE_UINT64:
345 case FR_TYPE_INT8:
346 case FR_TYPE_INT16:
347 case FR_TYPE_INT32:
348 case FR_TYPE_INT64:
349 case FR_TYPE_SIZE:
350 case FR_TYPE_OCTETS:
351 return 0;
352
353 case FR_TYPE_NON_LEAF:
354 fr_assert(0);
355 return -1;
356
357 case FR_TYPE_DATE:
359 case FR_TYPE_IFID:
360 case FR_TYPE_ETHERNET:
361 case FR_TYPE_FLOAT32:
362 case FR_TYPE_FLOAT64:
369 case FR_TYPE_ATTR:
370 /*
371 * Printing prefixes etc. does NOT result in the escape function being called! So
372 * instead, we cast the results to a string, and then escape the string.
373 */
374 if (fr_value_box_cast_in_place(vb, vb, FR_TYPE_STRING, NULL) < 0) return -1;
375
377 break;
378
379 case FR_TYPE_STRING:
380 /*
381 * Note that we set ".always_escape" in the function arguments, so that we get called for
382 * IP addresses. Otherwise, the xlat evaluator and/or the list_concat_as_string
383 * functions won't call us. And the expansion will return IP addresses with '/' in them.
384 * Which is not what we want.
385 */
387
388 /*
389 * If the tainted string has a leading '.', then escape _all_ periods in it. This is so that we
390 * don't accidentally allow a "safe" value to end with '/', and then an "unsafe" value contains
391 * "..", and we now have a directory traversal attack.
392 *
393 * The escape rules will escape '/' in unsafe strings, so there's no possibility for an unsafe
394 * string to either end with a '/', or to contain "/.." itself.
395 *
396 * Allowing '.' in the middle of the string means we can have filenames based on realms, such as
397 * "log/aland@freeradius.org".
398 */
399 if (vb->vb_strvalue[0] == '.') {
401 } else {
403 }
404
405 break;
406 }
407
408 entry = vb->entry;
410 (void) fr_value_box_bstrndup(vb, vb, NULL, fr_sbuff_start(out), fr_sbuff_used(out), false);
411 vb->entry = entry;
412
413 return 0;
414}
415
417 { .required = true, .concat = true, .type = FR_TYPE_STRING,
418 .func = filename_xlat_escape, .safe_for = FR_FILENAME_SAFE_FOR, .always_escape = true },
420};
421
423 { .required = true, .concat = true, .type = FR_TYPE_STRING,
424 .func = filename_xlat_escape, .safe_for = FR_FILENAME_SAFE_FOR, .always_escape = true },
425 { .required = false, .type = FR_TYPE_UINT32 },
427};
428
429
431 UNUSED xlat_ctx_t const *xctx,
432 UNUSED request_t *request, fr_value_box_list_t *args)
433{
434 fr_value_box_t *dst, *vb;
435 char const *filename;
436 struct stat buf;
437
438 XLAT_ARGS(args, &vb);
439 fr_assert(vb->type == FR_TYPE_STRING);
440 filename = vb->vb_strvalue;
441
442 MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
444
445 dst->vb_bool = (stat(filename, &buf) == 0);
446
447 return XLAT_ACTION_DONE;
448}
449
450
452 UNUSED xlat_ctx_t const *xctx,
453 request_t *request, fr_value_box_list_t *args)
454{
455 fr_value_box_t *dst, *vb;
456 char const *filename;
457 ssize_t len;
458 int fd;
459 char *p, buffer[256];
460
461 XLAT_ARGS(args, &vb);
462 fr_assert(vb->type == FR_TYPE_STRING);
463 filename = vb->vb_strvalue;
464
465 fd = open(filename, O_RDONLY);
466 if (fd < 0) {
467 REDEBUG3("Failed opening file %s - %s", filename, fr_syserror(errno));
468 return XLAT_ACTION_FAIL;
469 }
470
471 len = read(fd, buffer, sizeof(buffer));
472 if (len < 0) {
473 REDEBUG3("Failed reading file %s - %s", filename, fr_syserror(errno));
474 close(fd);
475 return XLAT_ACTION_FAIL;
476 }
477
478 /*
479 * Find the first CR/LF, but bail if we get any weird characters.
480 */
481 for (p = buffer; p < (buffer + len); p++) {
482 if ((*p == '\r') || (*p == '\n')) {
483 break;
484 }
485
486 if ((*p < ' ') && (*p != '\t')) {
487 invalid:
488 REDEBUG("Invalid text in file %s", filename);
489 close(fd);
490 return XLAT_ACTION_FAIL;
491 }
492 }
493
494 if ((p - buffer) > len) goto invalid;
495 close(fd);
496
497 MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL));
498 if (fr_value_box_bstrndup(dst, dst, NULL, buffer, p - buffer, false) < 0) {
499 talloc_free(dst);
500 return XLAT_ACTION_FAIL;
501 }
502
504
505 return XLAT_ACTION_DONE;
506}
507
508
510 UNUSED xlat_ctx_t const *xctx,
511 request_t *request, fr_value_box_list_t *args)
512{
513 fr_value_box_t *dst, *vb;
514 char const *filename;
515 struct stat buf;
516
517 XLAT_ARGS(args, &vb);
518 fr_assert(vb->type == FR_TYPE_STRING);
519 filename = vb->vb_strvalue;
520
521 if (stat(filename, &buf) < 0) {
522 REDEBUG3("Failed checking file %s - %s", filename, fr_syserror(errno));
523 return XLAT_ACTION_FAIL;
524 }
525
526 MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_UINT64, NULL)); /* off_t is signed, but file sizes shouldn't be negative */
528
529 dst->vb_uint64 = buf.st_size;
530
531 return XLAT_ACTION_DONE;
532}
533
534
536 UNUSED xlat_ctx_t const *xctx,
537 request_t *request, fr_value_box_list_t *args)
538{
539 fr_value_box_t *dst, *vb, *num = NULL;
540 char const *filename;
541 ssize_t len;
542 off_t offset;
543 int fd;
544 int crlf, stop = 1;
545 char *p, *end, *found, buffer[256];
546
547 XLAT_ARGS(args, &vb, &num);
548 fr_assert(vb->type == FR_TYPE_STRING);
549 filename = vb->vb_strvalue;
550
551 fd = open(filename, O_RDONLY);
552 if (fd < 0) {
553 REDEBUG3("Failed opening file %s - %s", filename, fr_syserror(errno));
554 return XLAT_ACTION_FAIL;
555 }
556
557 offset = lseek(fd, 0, SEEK_END);
558 if (offset < 0) {
559 REDEBUG3("Failed seeking to end of file %s - %s", filename, fr_syserror(errno));
560 goto fail;
561 }
562
563 if (offset > (off_t) sizeof(buffer)) {
564 offset -= sizeof(buffer);
565 } else {
566 offset = 0;
567 }
568
569 if (lseek(fd, offset, SEEK_SET) < 0) {
570 REDEBUG3("Failed seeking backwards from end of file %s - %s", filename, fr_syserror(errno));
571 goto fail;
572 }
573
574 len = read(fd, buffer, sizeof(buffer));
575 if (len < 0) {
576 fail:
577 REDEBUG3("Failed reading file %s - %s", filename, fr_syserror(errno));
578 close(fd);
579 return XLAT_ACTION_FAIL;
580 }
581 close(fd);
582
583 found = buffer;
584 end = buffer + len;
585
586 /*
587 * No data, OR just one CR / LF, we print it all out.
588 */
589 if (len <= 1) goto done;
590
591 /*
592 * Clamp number of lines to a reasonable value. They
593 * still all have to fit into 256 characters, though.
594 *
595 * @todo - have a large thread-local temporary buffer for this stuff.
596 */
597 if (num) {
598 fr_assert(num->type == FR_TYPE_GROUP);
599 fr_assert(fr_value_box_list_num_elements(&num->vb_group) == 1);
600
601 num = fr_value_box_list_head(&num->vb_group);
602 fr_assert(num->type == FR_TYPE_UINT32);
603
604 if (!num->vb_uint32) {
605 stop = 1;
606
607 } else if (num->vb_uint32 <= 16) {
608 stop = num->vb_uint64;
609
610 } else {
611 stop = 16;
612 }
613 } else {
614 stop = 1;
615 }
616
617 p = end - 1;
618 crlf = 0;
619
620 /*
621 * Skip any trailing CRLF first.
622 */
623 while (p > buffer) {
624 /*
625 * Could be CRLF, or just LF.
626 */
627 if (*p == '\n') {
628 end = p;
629 p--;
630 if (p == buffer) {
631 goto done;
632 }
633 if (*p >= ' ') {
634 break;
635 }
636 }
637
638 if (*p == '\r') {
639 end = p;
640 p--;
641 break;
642 }
643
644 /*
645 * We've found CR, LF, or CRLF. The previous
646 * thing is either raw text, or is another CR/LF.
647 */
648 break;
649 }
650
651 found = p;
652
653 while (p > buffer) {
654 crlf++;
655
656 /*
657 * If the current line is empty, we can stop.
658 */
659 if ((crlf == stop) && (*found < ' ')) {
660 found++;
661 goto done;
662 }
663
664 while (*p >= ' ') {
665 found = p;
666 p--;
667 if (p == buffer) {
668 found = buffer;
669 goto done;
670 }
671 }
672 if (crlf == stop) {
673 break;
674 }
675
676 /*
677 * Check again for CRLF.
678 */
679 if (*p == '\n') {
680 p--;
681 if (p == buffer) {
682 break;
683 }
684 if (*p >= ' ') {
685 continue;
686 }
687 }
688
689 if (*p == '\r') {
690 p--;
691 if (p == buffer) {
692 break;
693 }
694 continue;
695 }
696 }
697
698done:
699
700 /*
701 * @todo - return a _list_ of value-boxes, one for each line in the file.
702 * Which means chopping off each CRLF in the file
703 */
704
705 MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL));
706 if (fr_value_box_bstrndup(dst, dst, NULL, found, (size_t) (end - found), false) < 0) {
707 talloc_free(dst);
708 return XLAT_ACTION_FAIL;
709 }
710
712
713 return XLAT_ACTION_DONE;
714}
715
717 { .required = true, .concat = true, .type = FR_TYPE_STRING,
718 .func = filename_xlat_escape, .safe_for = FR_FILENAME_SAFE_FOR, .always_escape = true },
719 { .required = true, .type = FR_TYPE_SIZE, .single = true },
721};
722
724 UNUSED xlat_ctx_t const *xctx,
725 request_t *request, fr_value_box_list_t *args)
726{
727 fr_value_box_t *dst, *vb, *max_size;
728 char const *filename;
729 ssize_t len;
730 int fd;
731 struct stat buf;
733
734 XLAT_ARGS(args, &vb, &max_size);
735 fr_assert(vb->type == FR_TYPE_STRING);
736 filename = vb->vb_strvalue;
737
738 fd = open(filename, O_RDONLY);
739 if (fd < 0) {
740 RPERROR("Failed opening file %s - %s", filename, fr_syserror(errno));
741 return XLAT_ACTION_FAIL;
742 }
743
744 if (fstat(fd, &buf) < 0) {
745 RPERROR("Failed checking file %s - %s", filename, fr_syserror(errno));
746 fail:
747 close(fd);
748 return XLAT_ACTION_FAIL;
749 }
750
751 if ((size_t)buf.st_size > max_size->vb_size) {
752 RPERROR("File larger than specified maximum (%"PRIu64" vs %zu)", buf.st_size, max_size->vb_size);
753 goto fail;
754 }
755
756 MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_OCTETS, NULL));
757 fr_value_box_mem_alloc(dst, &buffer, dst, NULL, buf.st_size, true);
758
759 len = read(fd, buffer, buf.st_size);
760 if (len < 0) {
761 RPERROR("Failed reading file %s - %s", filename, fr_syserror(errno));
762 talloc_free(dst);
763 goto fail;
764 }
765 close(fd);
766
768
769 return XLAT_ACTION_DONE;
770}
771
773 UNUSED xlat_ctx_t const *xctx,
774 request_t *request, fr_value_box_list_t *args)
775{
776 fr_value_box_t *dst, *vb;
777 char const *filename;
778
779 XLAT_ARGS(args, &vb);
780 fr_assert(vb->type == FR_TYPE_STRING);
781 filename = vb->vb_strvalue;
782
783 MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
785
786 dst->vb_bool = (unlink(filename) == 0);
787 if (!dst->vb_bool) {
788 REDEBUG3("Failed unlinking file %s - %s", filename, fr_syserror(errno));
789 }
790
791 return XLAT_ACTION_DONE;
792}
793
795 request_t *request, fr_value_box_list_t *args)
796{
797 fr_value_box_t *dst, *vb;
798 char const *filename;
799 int fd;
800
801 XLAT_ARGS(args, &vb);
802 fr_assert(vb->type == FR_TYPE_STRING);
803 filename = vb->vb_strvalue;
804
805 MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
807
808 fd = open(filename, O_CREAT | S_IRUSR | S_IWUSR, 0600);
809 if (fd == -1) {
810 dst->vb_bool = false;
811 REDEBUG3("Failed touching file %s - %s", filename, fr_syserror(errno));
812 }
813 dst->vb_bool = true;
814
815 close(fd);
816
817 return XLAT_ACTION_DONE;
818}
819
821 { .required = true, .type = FR_TYPE_VOID },
822 { .variadic = XLAT_ARG_VARIADIC_EMPTY_KEEP, .type = FR_TYPE_VOID },
824};
825
827 UNUSED xlat_ctx_t const *xctx,
828 UNUSED request_t *request, fr_value_box_list_t *in)
829{
830 fr_value_box_t *vb;
831
833 while ((vb = fr_value_box_list_pop_head(in)) != NULL) {
835 }
836
837 return XLAT_ACTION_DONE;
838}
839
841 UNUSED xlat_ctx_t const *xctx,
842 UNUSED request_t *request, fr_value_box_list_t *in)
843{
844 fr_value_box_t *vb;
845
846 while ((vb = fr_value_box_list_pop_head(in)) != NULL) {
847 fr_value_box_t *child;
848
849 fr_assert(vb->type == FR_TYPE_GROUP);
850
851 while ((child = fr_value_box_list_pop_head(&vb->vb_group)) != NULL) {
852 child->tainted = true;
854
855 fr_dcursor_append(out, child);
856 }
857 }
858
859 return XLAT_ACTION_DONE;
860}
861
863 { .required = true, .type = FR_TYPE_STRING },
864 { .required = true, .concat = true, .type = FR_TYPE_STRING },
866};
867
868/** Split a string into multiple new strings based on a delimiter
869 *
870@verbatim
871%explode(<string>, <delim>)
872@endverbatim
873 *
874 * Example:
875@verbatim
876update request {
877 &Tmp-String-1 := "a,b,c"
878}
879"%concat(%explode(%{Tmp-String-1}, ','), '|')" == "a|b|c"g
880@endverbatim
881 *
882 * @ingroup xlat_functions
883 */
885 UNUSED xlat_ctx_t const *xctx,
886 request_t *request, fr_value_box_list_t *args)
887{
889 fr_value_box_list_t *list;
890 fr_value_box_t *delim_vb;
891 ssize_t delim_len;
892 char const *delim;
893 fr_value_box_t *string, *vb;
894
895 XLAT_ARGS(args, &strings, &delim_vb);
896
897 list = &strings->vb_group;
898
899 /* coverity[dereference] */
900 if (delim_vb->vb_length == 0) {
901 REDEBUG("Delimiter must be greater than zero characters");
902 return XLAT_ACTION_FAIL;
903 }
904
905 delim = delim_vb->vb_strvalue;
906 delim_len = delim_vb->vb_length;
907
908 while ((string = fr_value_box_list_pop_head(list))) {
909 fr_sbuff_t sbuff = FR_SBUFF_IN(string->vb_strvalue, string->vb_length);
910 fr_sbuff_marker_t m_start;
911
912 /*
913 * If the delimiter is not in the string, just move to the output
914 */
915 if (!fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, delim, delim_len)) {
916 fr_dcursor_append(out, string);
917 continue;
918 }
919
920 fr_sbuff_set_to_start(&sbuff);
921 fr_sbuff_marker(&m_start, &sbuff);
922
923 while (fr_sbuff_remaining(&sbuff)) {
924 if (fr_sbuff_adv_to_str(&sbuff, SIZE_MAX, delim, delim_len)) {
925 /*
926 * If there's nothing before the delimiter skip
927 */
928 if (fr_sbuff_behind(&m_start) == 0) goto advance;
929
930 MEM(vb = fr_value_box_alloc_null(ctx));
931 fr_value_box_bstrndup(vb, vb, NULL, fr_sbuff_current(&m_start),
932 fr_sbuff_behind(&m_start), false);
933 fr_value_box_safety_copy(vb, string);
935
936 advance:
937 fr_sbuff_advance(&sbuff, delim_len);
938 fr_sbuff_set(&m_start, &sbuff);
939 continue;
940 }
941
942 fr_sbuff_set_to_end(&sbuff);
943 MEM(vb = fr_value_box_alloc_null(ctx));
944 fr_value_box_bstrndup(vb, vb, NULL, fr_sbuff_current(&m_start),
945 fr_sbuff_behind(&m_start), false);
946
947 fr_value_box_safety_copy(vb, string);
949 break;
950 }
951 talloc_free(string);
952 }
953
954 return XLAT_ACTION_DONE;
955}
956
957/** Mark one or more attributes as immutable
958 *
959 * Example:
960@verbatim
961%pairs.immutable(request.State[*])
962@endverbatim
963 *
964 * @ingroup xlat_functions
965 */
967 UNUSED xlat_ctx_t const *xctx,
968 request_t *request, fr_value_box_list_t *args)
969{
970 fr_pair_t *vp;
971 fr_dcursor_t *cursor;
972 fr_value_box_t *in_head;
973
974 XLAT_ARGS(args, &in_head);
975
976 cursor = fr_value_box_get_cursor(in_head);
977
978 RDEBUG("Attributes matching \"%s\"", in_head->vb_cursor_name);
979
980 RINDENT();
981 for (vp = fr_dcursor_current(cursor);
982 vp;
983 vp = fr_dcursor_next(cursor)) {
985 }
986 REXDENT();
987
988 return XLAT_ACTION_DONE;
989}
990
992 { .required = true, .single = true, .type = FR_TYPE_VOID },
994};
995
996/** Print data as integer, not as VALUE.
997 *
998 * Example:
999@verbatim
1000update request {
1001 &Tmp-IP-Address-0 := "127.0.0.5"
1002}
1003%integer(%{Tmp-IP-Address-0}) == 2130706437
1004@endverbatim
1005 * @ingroup xlat_functions
1006 */
1008 UNUSED xlat_ctx_t const *xctx,
1009 request_t *request, fr_value_box_list_t *args)
1010{
1011 fr_value_box_t *in_vb;
1012 char const *p;
1013
1014 XLAT_ARGS(args, &in_vb);
1015
1016 fr_strerror_clear(); /* Make sure we don't print old errors */
1017
1018 fr_value_box_list_remove(args, in_vb);
1019
1020 switch (in_vb->type) {
1021 default:
1022 error:
1023 RPEDEBUG("Failed converting %pV (%s) to an integer", in_vb,
1024 fr_type_to_str(in_vb->type));
1025 talloc_free(in_vb);
1026 return XLAT_ACTION_FAIL;
1027
1028 case FR_TYPE_NUMERIC:
1029 /*
1030 * Ensure enumeration is NULL so that the integer
1031 * version of a box is returned
1032 */
1033 in_vb->enumv = NULL;
1034
1035 /*
1036 * FR_TYPE_DATE and FR_TYPE_TIME_DELTA need to be cast
1037 * to int64_t so that they're printed in a
1038 * numeric format.
1039 */
1040 if ((in_vb->type == FR_TYPE_DATE) || (in_vb->type == FR_TYPE_TIME_DELTA)) {
1041 if (fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_INT64, NULL) < 0) goto error;
1042 }
1043 break;
1044
1045 case FR_TYPE_STRING:
1046 /*
1047 * Strings are always zero terminated. They may
1048 * also have zeros in the middle, but if that
1049 * happens, the caller will only get the part up
1050 * to the first zero.
1051 *
1052 * We check for negative numbers, just to be
1053 * nice.
1054 */
1055 for (p = in_vb->vb_strvalue; *p != '\0'; p++) {
1056 if (*p == '-') break;
1057 }
1058
1059 if (*p == '-') {
1060 if (fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_INT64, NULL) < 0) goto error;
1061 } else {
1062 if (fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT64, NULL) < 0) goto error;
1063 }
1064 break;
1065
1066 case FR_TYPE_OCTETS:
1067 if (in_vb->vb_length > sizeof(uint64_t)) {
1068 fr_strerror_printf("Expected octets length <= %zu, got %zu", sizeof(uint64_t), in_vb->vb_length);
1069 goto error;
1070 }
1071
1072 if (in_vb->vb_length > sizeof(uint32_t)) {
1073 if (unlikely(fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT64, NULL) < 0)) goto error;
1074 } else if (in_vb->vb_length > sizeof(uint16_t)) {
1075 if (unlikely(fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT32, NULL) < 0)) goto error;
1076 } else if (in_vb->vb_length > sizeof(uint8_t)) {
1077 if (unlikely(fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT16, NULL) < 0)) goto error;
1078 } else {
1079 if (unlikely(fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT8, NULL) < 0)) goto error;
1080 }
1081
1082 break;
1083
1084 case FR_TYPE_IPV4_ADDR:
1086 if (fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT32, NULL) < 0) goto error;
1087 break;
1088
1089 case FR_TYPE_ETHERNET:
1090 if (fr_value_box_cast_in_place(ctx, in_vb, FR_TYPE_UINT64, NULL) < 0) goto error;
1091 break;
1092
1093 case FR_TYPE_IPV6_ADDR:
1095 {
1096 uint128_t ipv6int;
1097 char buff[40];
1098 fr_value_box_t *vb;
1099
1100 /*
1101 * Needed for correct alignment (as flagged by ubsan)
1102 */
1103 memcpy(&ipv6int, &in_vb->vb_ip.addr.v6.s6_addr, sizeof(ipv6int));
1104
1105 fr_snprint_uint128(buff, sizeof(buff), ntohlll(ipv6int));
1106
1107 MEM(vb = fr_value_box_alloc_null(ctx));
1108 fr_value_box_bstrndup(vb, vb, NULL, buff, strlen(buff), false);
1110 talloc_free(in_vb);
1111 return XLAT_ACTION_DONE;
1112 }
1113 }
1114
1115 fr_dcursor_append(out, in_vb);
1116
1117 return XLAT_ACTION_DONE;
1118}
1119
1121 { .concat = true, .type = FR_TYPE_STRING },
1123};
1124
1125/** Log something at INFO level.
1126 *
1127 * Example:
1128@verbatim
1129%log("This is an informational message")
1130@endverbatim
1131 *
1132 * @ingroup xlat_functions
1133 */
1135 UNUSED xlat_ctx_t const *xctx,
1136 request_t *request, fr_value_box_list_t *args)
1137{
1138 fr_value_box_t *vb;
1139
1140 XLAT_ARGS(args, &vb);
1141
1142 if (!vb) return XLAT_ACTION_DONE;
1143
1144 RINFO("%s", vb->vb_strvalue);
1145
1146 return XLAT_ACTION_DONE;
1147}
1148
1149
1150/** Log something at DEBUG level.
1151 *
1152 * Example:
1153@verbatim
1154%log.debug("This is a message")
1155@endverbatim
1156 *
1157 * @ingroup xlat_functions
1158 */
1160 UNUSED xlat_ctx_t const *xctx,
1161 request_t *request, fr_value_box_list_t *args)
1162{
1163 fr_value_box_t *vb;
1164
1165 XLAT_ARGS(args, &vb);
1166
1167 if (!vb) return XLAT_ACTION_DONE;
1168
1169 RDEBUG("%s", vb->vb_strvalue);
1170
1171 return XLAT_ACTION_DONE;
1172}
1173
1174
1175/** Log something at DEBUG level.
1176 *
1177 * Example:
1178@verbatim
1179%log.err("Big error here")
1180@endverbatim
1181 *
1182 * @ingroup xlat_functions
1183 */
1185 UNUSED xlat_ctx_t const *xctx,
1186 request_t *request, fr_value_box_list_t *args)
1187{
1188 fr_value_box_t *vb;
1189
1190 XLAT_ARGS(args, &vb);
1191
1192 if (!vb) return XLAT_ACTION_DONE;
1193
1194 REDEBUG("%s", vb->vb_strvalue);
1195
1196 return XLAT_ACTION_DONE;
1197}
1198
1199
1200/** Log something at WARN level.
1201 *
1202 * Example:
1203@verbatim
1204%log.warn("Maybe something bad happened")
1205@endverbatim
1206 *
1207 * @ingroup xlat_functions
1208 */
1210 UNUSED xlat_ctx_t const *xctx,
1211 request_t *request, fr_value_box_list_t *args)
1212{
1213 fr_value_box_t *vb;
1214
1215 XLAT_ARGS(args, &vb);
1216
1217 if (!vb) return XLAT_ACTION_DONE;
1218
1219 RWDEBUG("%s", vb->vb_strvalue);
1220
1221 return XLAT_ACTION_DONE;
1222}
1223
1224static int _log_dst_free(fr_log_t *log)
1225{
1226 close(log->fd);
1227 return 0;
1228}
1229
1231 { .required = false, .type = FR_TYPE_STRING, .concat = true },
1232 { .required = false, .type = FR_TYPE_UINT32, .single = true },
1233 { .required = false, .type = FR_TYPE_STRING, .concat = true },
1235};
1236
1237/** Change the log destination to the named one
1238 *
1239 * Example:
1240@verbatim
1241%log.destination('foo')
1242@endverbatim
1243 *
1244 * @ingroup xlat_functions
1245 */
1247 UNUSED xlat_ctx_t const *xctx,
1248 request_t *request, fr_value_box_list_t *args)
1249{
1250 fr_value_box_t *dst, *lvl, *file;
1251 fr_log_t *log, *dbg;
1252 uint32_t level = 2;
1253
1254 XLAT_ARGS(args, &dst, &lvl, &file);
1255
1256 if (!dst || !*dst->vb_strvalue) {
1257 request_log_prepend(request, NULL, L_DBG_LVL_DISABLE);
1258 return XLAT_ACTION_DONE;
1259 }
1260
1261 log = log_dst_by_name(dst->vb_strvalue);
1262 if (!log) return XLAT_ACTION_FAIL;
1263
1264 if (lvl) level = lvl->vb_uint32;
1265
1266 if (!file || ((log->dst != L_DST_NULL) && (log->dst != L_DST_FILES))) {
1267 request_log_prepend(request, log, level);
1268 return XLAT_ACTION_DONE;
1269 }
1270
1271 /*
1272 * Clone it.
1273 */
1274 MEM(dbg = talloc_memdup(request, log, sizeof(*log)));
1275 dbg->parent = log;
1276
1277 /*
1278 * Open the new filename.
1279 */
1280 dbg->dst = L_DST_FILES;
1281 dbg->file = talloc_strdup(dbg, file->vb_strvalue);
1282 dbg->fd = open(dbg->file, O_WRONLY | O_CREAT | O_CLOEXEC, 0600);
1283 if (dbg->fd < 0) {
1284 REDEBUG("Failed opening %s - %s", dbg->file, fr_syserror(errno));
1285 talloc_free(dbg);
1286 return XLAT_ACTION_DONE;
1287 }
1288
1289 /*
1290 * Ensure that we close the file handle when done.
1291 */
1292 talloc_set_destructor(dbg, _log_dst_free);
1293
1294 request_log_prepend(request, dbg, level);
1295 return XLAT_ACTION_DONE;
1296}
1297
1298
1300 { .required = true, .type = FR_TYPE_STRING },
1302};
1303
1304/** Processes fmt as a map string and applies it to the current request
1305 *
1306 * e.g.
1307@verbatim
1308%map("User-Name := 'foo'")
1309@endverbatim
1310 *
1311 * Allows sets of modifications to be cached and then applied.
1312 * Useful for processing generic attributes from LDAP.
1313 *
1314 * @ingroup xlat_functions
1315 */
1317 UNUSED xlat_ctx_t const *xctx,
1318 request_t *request, fr_value_box_list_t *args)
1319{
1320 map_t *map = NULL;
1321 int ret;
1322 fr_value_box_t *fmt_vb;
1323 fr_value_box_t *vb;
1324
1325 tmpl_rules_t attr_rules = {
1326 .attr = {
1327 .dict_def = request->local_dict,
1328 .list_def = request_attr_request,
1329 },
1330 .xlat = {
1331 .runtime_el = unlang_interpret_event_list(request)
1332 }
1333 };
1334
1335 XLAT_ARGS(args, &fmt_vb);
1336
1337 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
1338 vb->vb_bool = false; /* Default fail value - changed to true on success */
1340
1341 fr_value_box_list_foreach_safe(&fmt_vb->vb_group, fmt) {
1342 if (map_afrom_attr_str(request, &map, fmt->vb_strvalue, &attr_rules, &attr_rules) < 0) {
1343 RPEDEBUG("Failed parsing \"%s\" as map", fmt_vb->vb_strvalue);
1344 return XLAT_ACTION_FAIL;
1345 }
1346
1347 switch (map->lhs->type) {
1348 case TMPL_TYPE_ATTR:
1349 case TMPL_TYPE_XLAT:
1350 break;
1351
1352 default:
1353 REDEBUG("Unexpected type %s in left hand side of expression",
1354 tmpl_type_to_str(map->lhs->type));
1355 return XLAT_ACTION_FAIL;
1356 }
1357
1358 switch (map->rhs->type) {
1359 case TMPL_TYPE_ATTR:
1360 case TMPL_TYPE_EXEC:
1361 case TMPL_TYPE_DATA:
1364 case TMPL_TYPE_XLAT:
1365 break;
1366
1367 default:
1368 REDEBUG("Unexpected type %s in right hand side of expression",
1369 tmpl_type_to_str(map->rhs->type));
1370 return XLAT_ACTION_FAIL;
1371 }
1372
1373 RINDENT();
1374 ret = map_to_request(request, map, map_to_vp, NULL);
1375 REXDENT();
1376 talloc_free(map);
1377 if (ret < 0) return XLAT_ACTION_FAIL;
1378 }}
1379
1380 vb->vb_bool = true;
1381 return XLAT_ACTION_DONE;
1382}
1383
1384
1386 { .required = true, .concat = true, .type = FR_TYPE_STRING },
1388};
1389
1390/** Calculate number of seconds until the next n hour(s), day(s), week(s), year(s).
1391 *
1392 * For example, if it were 16:18 %time.next(1h) would expand to 2520.
1393 *
1394 * The envisaged usage for this function is to limit sessions so that they don't
1395 * cross billing periods. The output of the xlat should be combined with %rand() to create
1396 * some jitter, unless the desired effect is every subscriber on the network
1397 * re-authenticating at the same time.
1398 *
1399 * @ingroup xlat_functions
1400 */
1402 UNUSED xlat_ctx_t const *xctx,
1403 request_t *request, fr_value_box_list_t *args)
1404{
1405 long num;
1406
1407 char const *p;
1408 char *q;
1409 time_t now;
1410 struct tm *local, local_buff;
1411 fr_value_box_t *in_head;
1412 fr_value_box_t *vb;
1413
1414 XLAT_ARGS(args, &in_head);
1415
1416 /*
1417 * We want to limit based on _now_, not on when they logged in.
1418 */
1419 now = time(NULL);
1420 local = localtime_r(&now, &local_buff);
1421
1422 p = in_head->vb_strvalue;
1423
1424 num = strtoul(p, &q, 10);
1425 if (!q || *q == '\0') {
1426 REDEBUG("<int> must be followed by time period (h|d|w|m|y)");
1427 return XLAT_ACTION_FAIL;
1428 }
1429
1430 if (p == q) {
1431 num = 1;
1432 } else {
1433 p += q - p;
1434 }
1435
1436 local->tm_sec = 0;
1437 local->tm_min = 0;
1438
1439 switch (*p) {
1440 case 'h':
1441 local->tm_hour += num;
1442 break;
1443
1444 case 'd':
1445 local->tm_hour = 0;
1446 local->tm_mday += num;
1447 break;
1448
1449 case 'w':
1450 local->tm_hour = 0;
1451 local->tm_mday += (7 - local->tm_wday) + (7 * (num-1));
1452 break;
1453
1454 case 'm':
1455 local->tm_hour = 0;
1456 local->tm_mday = 1;
1457 local->tm_mon += num;
1458 break;
1459
1460 case 'y':
1461 local->tm_hour = 0;
1462 local->tm_mday = 1;
1463 local->tm_mon = 0;
1464 local->tm_year += num;
1465 break;
1466
1467 default:
1468 REDEBUG("Invalid time period '%c', must be h|d|w|m|y", *p);
1469 return XLAT_ACTION_FAIL;
1470 }
1471
1472 MEM(vb = fr_value_box_alloc_null(ctx));
1473 fr_value_box_uint64(vb, NULL, (uint64_t)(mktime(local) - now), false);
1475 return XLAT_ACTION_DONE;
1476}
1477
1482
1483/** Just serves to push the result up the stack
1484 *
1485 */
1487 xlat_ctx_t const *xctx,
1488 UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
1489{
1490 xlat_eval_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_eval_rctx_t);
1492
1493 talloc_free(rctx);
1494
1495 return xa;
1496}
1497
1499 { .required = true, .concat = true, .type = FR_TYPE_STRING },
1501};
1502
1503/** Dynamically evaluate an expansion string
1504 *
1505 * @ingroup xlat_functions
1506 */
1508 UNUSED xlat_ctx_t const *xctx,
1509 request_t *request, fr_value_box_list_t *args)
1510{
1511 /*
1512 * These are escaping rules applied to the
1513 * input string. They're mostly here to
1514 * allow \% and \\ to work.
1515 *
1516 * Everything else should be passed in as
1517 * unescaped data.
1518 */
1519 static fr_sbuff_unescape_rules_t const escape_rules = {
1520 .name = "xlat",
1521 .chr = '\\',
1522 .subs = {
1523 ['%'] = '%',
1524 ['\\'] = '\\',
1525 },
1526 .do_hex = false,
1527 .do_oct = false
1528 };
1529
1530 xlat_eval_rctx_t *rctx;
1531 fr_value_box_t *arg = fr_value_box_list_head(args);
1532
1533 XLAT_ARGS(args, &arg);
1534
1535 MEM(rctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), xlat_eval_rctx_t));
1536
1537 /*
1538 * Parse the input as a literal expansion
1539 */
1540 if (xlat_tokenize_expression(rctx,
1541 &rctx->ex,
1542 &FR_SBUFF_IN(arg->vb_strvalue, arg->vb_length),
1543 &(fr_sbuff_parse_rules_t){
1544 .escapes = &escape_rules
1545 },
1546 &(tmpl_rules_t){
1547 .attr = {
1548 .dict_def = request->local_dict,
1549 .list_def = request_attr_request,
1550 .allow_unknown = false,
1551 .allow_unresolved = false,
1552 .allow_foreign = false,
1553 },
1554 .xlat = {
1555 .runtime_el = unlang_interpret_event_list(request),
1556 },
1557 .at_runtime = true
1558 }) < 0) {
1559 RPEDEBUG("Failed parsing expansion");
1560 error:
1561 talloc_free(rctx);
1562 return XLAT_ACTION_FAIL;
1563 }
1564
1565 /*
1566 * Call the resolution function so we produce
1567 * good errors about what function was
1568 * unresolved.
1569 */
1570 if (rctx->ex->flags.needs_resolving &&
1571 (xlat_resolve(rctx->ex, &(xlat_res_rules_t){ .allow_unresolved = false }) < 0)) {
1572 RPEDEBUG("Unresolved expansion functions in expansion");
1573 goto error;
1574
1575 }
1576
1577 if (unlang_xlat_yield(request, xlat_eval_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
1578
1579 if (unlang_xlat_push(ctx, &rctx->last_result, (fr_value_box_list_t *)out->dlist,
1580 request, rctx->ex, UNLANG_SUB_FRAME) < 0) goto error;
1581
1583}
1584
1586 { .required = true, .type = FR_TYPE_STRING },
1587 { .required = true, .single = true, .type = FR_TYPE_UINT64 },
1588 { .concat = true, .type = FR_TYPE_STRING },
1590};
1591
1592/** lpad a string
1593 *
1594@verbatim
1595%lpad(%{Attribute-Name}, <length> [, <fill>])
1596@endverbatim
1597 *
1598 * Example: (User-Name = "foo")
1599@verbatim
1600%lpad(%{User-Name}, 5 'x') == "xxfoo"
1601@endverbatim
1602 *
1603 * @ingroup xlat_functions
1604 */
1606 UNUSED xlat_ctx_t const *xctx,
1607 request_t *request, fr_value_box_list_t *args)
1608{
1609 fr_value_box_t *values;
1610 fr_value_box_t *pad;
1612
1613 fr_value_box_list_t *list;
1614
1615 size_t pad_len;
1616
1617 char const *fill_str = NULL;
1618 size_t fill_len = 0;
1619
1620 fr_value_box_t *in = NULL;
1621
1622 XLAT_ARGS(args, &values, &pad, &fill);
1623
1624 /* coverity[dereference] */
1625 list = &values->vb_group;
1626 /* coverity[dereference] */
1627 pad_len = (size_t)pad->vb_uint64;
1628
1629 /*
1630 * Fill is optional
1631 */
1632 if (fill) {
1633 fill_str = fill->vb_strvalue;
1634 fill_len = talloc_array_length(fill_str) - 1;
1635 }
1636
1637 if (fill_len == 0) {
1638 fill_str = " ";
1639 fill_len = 1;
1640 }
1641
1642 while ((in = fr_value_box_list_pop_head(list))) {
1643 size_t len = talloc_array_length(in->vb_strvalue) - 1;
1644 size_t remaining;
1645 char *buff;
1646 fr_sbuff_t sbuff;
1647 fr_sbuff_marker_t m_data;
1648
1650
1651 if (len >= pad_len) continue;
1652
1653 if (fr_value_box_bstr_realloc(in, &buff, in, pad_len) < 0) {
1654 RPEDEBUG("Failed reallocing input data");
1655 return XLAT_ACTION_FAIL;
1656 }
1657
1658 fr_sbuff_init_in(&sbuff, buff, pad_len);
1659 fr_sbuff_marker(&m_data, &sbuff);
1660
1661 /*
1662 * ...nothing to move if the input
1663 * string is empty.
1664 */
1665 if (len > 0) {
1666 fr_sbuff_advance(&m_data, pad_len - len); /* Mark where we want the data to go */
1667 fr_sbuff_move(&FR_SBUFF(&m_data), &FR_SBUFF(&sbuff), len); /* Shift the data */
1668 }
1669
1670 if (fill_len == 1) {
1671 memset(fr_sbuff_current(&sbuff), *fill_str, fr_sbuff_ahead(&m_data));
1672 continue;
1673 }
1674
1675 /*
1676 * Copy fill as a repeating pattern
1677 */
1678 while ((remaining = fr_sbuff_ahead(&m_data))) {
1679 size_t to_copy = remaining >= fill_len ? fill_len : remaining;
1680 memcpy(fr_sbuff_current(&sbuff), fill_str, to_copy); /* avoid \0 termination */
1681 fr_sbuff_advance(&sbuff, to_copy);
1682 }
1683 fr_sbuff_set_to_end(&sbuff);
1684 fr_sbuff_terminate(&sbuff); /* Move doesn't re-terminate */
1685 }
1686
1687 return XLAT_ACTION_DONE;
1688}
1689
1690/** Right pad a string
1691 *
1692@verbatim
1693%rpad(%{Attribute-Name}, <length> [, <fill>])
1694@endverbatim
1695 *
1696 * Example: (User-Name = "foo")
1697@verbatim
1698%rpad(%{User-Name}, 5 'x') == "fooxx"
1699@endverbatim
1700 *
1701 * @ingroup xlat_functions
1702 */
1704 UNUSED xlat_ctx_t const *xctx,
1705 request_t *request, fr_value_box_list_t *args)
1706{
1707 fr_value_box_t *values;
1708 fr_value_box_list_t *list;
1709 fr_value_box_t *pad;
1710 /* coverity[dereference] */
1711 size_t pad_len;
1713 char const *fill_str = NULL;
1714 size_t fill_len = 0;
1715
1716 fr_value_box_t *in = NULL;
1717
1718 XLAT_ARGS(args, &values, &pad, &fill);
1719
1720 list = &values->vb_group;
1721 pad_len = (size_t)pad->vb_uint64;
1722
1723 /*
1724 * Fill is optional
1725 */
1726 if (fill) {
1727 fill_str = fill->vb_strvalue;
1728 fill_len = talloc_array_length(fill_str) - 1;
1729 }
1730
1731 if (fill_len == 0) {
1732 fill_str = " ";
1733 fill_len = 1;
1734 }
1735
1736 while ((in = fr_value_box_list_pop_head(list))) {
1737 size_t len = talloc_array_length(in->vb_strvalue) - 1;
1738 size_t remaining;
1739 char *buff;
1740 fr_sbuff_t sbuff;
1741
1743
1744 if (len >= pad_len) continue;
1745
1746 if (fr_value_box_bstr_realloc(in, &buff, in, pad_len) < 0) {
1747 fail:
1748 RPEDEBUG("Failed reallocing input data");
1749 return XLAT_ACTION_FAIL;
1750 }
1751
1752 fr_sbuff_init_in(&sbuff, buff, pad_len);
1753 fr_sbuff_advance(&sbuff, len);
1754
1755 if (fill_len == 1) {
1756 memset(fr_sbuff_current(&sbuff), *fill_str, fr_sbuff_remaining(&sbuff));
1757 continue;
1758 }
1759
1760 /*
1761 * Copy fill as a repeating pattern
1762 */
1763 while ((remaining = fr_sbuff_remaining(&sbuff))) {
1764 if (fr_sbuff_in_bstrncpy(&sbuff, fill_str, remaining >= fill_len ? fill_len : remaining) < 0) {
1765 goto fail;
1766 }
1767 }
1768 }
1769
1770 return XLAT_ACTION_DONE;
1771}
1772
1774 { .required = true, .concat = true, .type = FR_TYPE_OCTETS },
1776};
1777
1778/** Encode string or attribute as base64
1779 *
1780 * Example:
1781@verbatim
1782%base64.encode("foo") == "Zm9v"
1783@endverbatim
1784 *
1785 * @ingroup xlat_functions
1786 */
1788 UNUSED xlat_ctx_t const *xctx,
1789 request_t *request, fr_value_box_list_t *args)
1790{
1791 size_t alen;
1792 ssize_t elen;
1793 char *buff;
1794 fr_value_box_t *vb;
1796
1797 XLAT_ARGS(args, &in);
1798
1799 alen = FR_BASE64_ENC_LENGTH(in->vb_length);
1800
1801 MEM(vb = fr_value_box_alloc_null(ctx));
1802 if (fr_value_box_bstr_alloc(vb, &buff, vb, NULL, alen, false) < 0) {
1803 talloc_free(vb);
1804 return XLAT_ACTION_FAIL;
1805 }
1806
1807 elen = fr_base64_encode(&FR_SBUFF_OUT(buff, talloc_array_length(buff)),
1808 &FR_DBUFF_TMP(in->vb_octets, in->vb_length), true);
1809 if (elen < 0) {
1810 RPEDEBUG("Base64 encoding failed");
1811 talloc_free(vb);
1812 return XLAT_ACTION_FAIL;
1813 }
1814 fr_assert((size_t)elen <= alen);
1817
1818 return XLAT_ACTION_DONE;
1819}
1820
1822 { .required = true, .concat = true, .type = FR_TYPE_OCTETS },
1824};
1825
1826/** Decode base64 string
1827 *
1828 * Example:
1829@verbatim
1830%base64.decode("Zm9v") == "foo"
1831@endverbatim
1832 *
1833 * @ingroup xlat_functions
1834 */
1836 UNUSED xlat_ctx_t const *xctx,
1837 request_t *request, fr_value_box_list_t *args)
1838{
1839 size_t alen;
1840 ssize_t declen = 0;
1841 uint8_t *decbuf;
1842 fr_value_box_t *vb;
1844
1845 XLAT_ARGS(args, &in);
1846
1847 /*
1848 * Pass empty arguments through
1849 *
1850 * FR_BASE64_DEC_LENGTH produces 2 for empty strings...
1851 */
1852 if (in->vb_length == 0) {
1853 fr_value_box_list_remove(args, in);
1855 return XLAT_ACTION_DONE;
1856 }
1857
1858 alen = FR_BASE64_DEC_LENGTH(in->vb_length);
1859 MEM(vb = fr_value_box_alloc_null(ctx));
1860 if (alen > 0) {
1861 MEM(fr_value_box_mem_alloc(vb, &decbuf, vb, NULL, alen, false) == 0);
1862 declen = fr_base64_decode(&FR_DBUFF_TMP(decbuf, alen),
1863 &FR_SBUFF_IN(in->vb_strvalue, in->vb_length), true, true);
1864 if (declen < 0) {
1865 RPEDEBUG("Base64 string invalid");
1866 talloc_free(vb);
1867 return XLAT_ACTION_FAIL;
1868 }
1869
1870 MEM(fr_value_box_mem_realloc(vb, NULL, vb, declen) == 0);
1871 }
1872
1875
1876 return XLAT_ACTION_DONE;
1877}
1878
1880 { .required = true, .type = FR_TYPE_STRING },
1882};
1883
1884/** Convert hex string to binary
1885 *
1886 * Example:
1887@verbatim
1888%bin("666f6f626172") == "foobar"
1889@endverbatim
1890 *
1891 * @see #xlat_func_hex
1892 *
1893 * @ingroup xlat_functions
1894 */
1896 UNUSED xlat_ctx_t const *xctx,
1897 request_t *request, fr_value_box_list_t *args)
1898{
1899 fr_value_box_t *result;
1900 char const *p, *end;
1901 uint8_t *bin;
1902 size_t len, outlen;
1904 fr_value_box_t *list, *hex;
1905
1906 XLAT_ARGS(args, &list);
1907
1908 while ((hex = fr_value_box_list_pop_head(&list->vb_group))) {
1909 len = hex->vb_length;
1910 if ((len > 1) && (len & 0x01)) {
1911 REDEBUG("Input data length must be >1 and even, got %zu", len);
1912 return XLAT_ACTION_FAIL;
1913 }
1914
1915 p = hex->vb_strvalue;
1916 end = p + len;
1917
1918 /*
1919 * Look for 0x at the start of the string, and ignore if we see it.
1920 */
1921 if ((p[0] == '0') && (p[1] == 'x')) {
1922 p += 2;
1923 len -=2;
1924 }
1925
1926 /*
1927 * Zero length octets string
1928 */
1929 if (p == end) continue;
1930
1931 outlen = len / 2;
1932
1933 MEM(result = fr_value_box_alloc_null(ctx));
1934 MEM(fr_value_box_mem_alloc(result, &bin, result, NULL, outlen, false) == 0);
1935 fr_base16_decode(&err, &FR_DBUFF_TMP(bin, outlen), &FR_SBUFF_IN(p, end - p), true);
1936 if (err) {
1937 REDEBUG2("Invalid hex string");
1938 talloc_free(result);
1939 return XLAT_ACTION_FAIL;
1940 }
1941
1943 fr_dcursor_append(out, result);
1944 }
1945
1946 return XLAT_ACTION_DONE;
1947}
1948
1950 { .required = true, .single = true, .type = FR_TYPE_VOID },
1951 { .type = FR_TYPE_VOID },
1952 { .variadic = XLAT_ARG_VARIADIC_EMPTY_KEEP, .type = FR_TYPE_VOID },
1954};
1955
1956/** Cast one or more output value-boxes to the given type
1957 *
1958 * First argument of is type to cast to.
1959 *
1960 * Example:
1961@verbatim
1962%cast('string', %{request[*]}) results in all of the input boxes being cast to string/
1963@endverbatim
1964 *
1965 * @ingroup xlat_functions
1966 */
1968 UNUSED xlat_ctx_t const *xctx,
1969 request_t *request, fr_value_box_list_t *args)
1970{
1972 fr_value_box_t *arg;
1974 fr_dict_attr_t const *time_res = NULL;
1975
1976 XLAT_ARGS(args, &name);
1977
1978 /*
1979 * Get the type, which can be in one of a few formats.
1980 */
1981 if (fr_type_is_numeric(name->type)) {
1983 RPEDEBUG("Failed parsing '%pV' as a numerical data type", name);
1984 return XLAT_ACTION_FAIL;
1985 }
1986 type = name->vb_uint8;
1987
1988 } else {
1989 if (name->type != FR_TYPE_STRING) {
1991 RPEDEBUG("Failed parsing '%pV' as a string data type", name);
1992 return XLAT_ACTION_FAIL;
1993 }
1994 }
1995
1997 if (type == FR_TYPE_NULL) {
1998 if ((time_res = xlat_time_res_attr(name->vb_strvalue)) == NULL) {
1999 RDEBUG("Unknown data type '%s'", name->vb_strvalue);
2000 return XLAT_ACTION_FAIL;
2001 }
2002
2004 }
2005 }
2006
2007 (void) fr_value_box_list_pop_head(args);
2008
2009 /*
2010 * When we cast nothing to a string / octets, the result is an empty string/octets.
2011 */
2012 if (unlikely(!fr_value_box_list_head(args))) {
2013 if ((type == FR_TYPE_STRING) || (type == FR_TYPE_OCTETS)) {
2014 fr_value_box_t *dst;
2015
2016 MEM(dst = fr_value_box_alloc(ctx, type, NULL));
2017 fr_dcursor_append(out, dst);
2018 VALUE_BOX_LIST_VERIFY((fr_value_box_list_t *)out->dlist);
2019
2020 return XLAT_ACTION_DONE;
2021 }
2022
2023 RDEBUG("No data for cast to '%s'", fr_type_to_str(type));
2024 return XLAT_ACTION_FAIL;
2025 }
2026
2027 /*
2028 * Cast to string means *print* to string.
2029 */
2030 if (type == FR_TYPE_STRING) {
2031 fr_sbuff_t *agg;
2032 fr_value_box_t *dst;
2033
2035
2036 FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 256, SIZE_MAX);
2037
2038 MEM(dst = fr_value_box_alloc_null(ctx));
2040
2041 if (fr_value_box_list_concat_as_string(dst, agg, args, NULL, 0, NULL,
2043 RPEDEBUG("Failed concatenating string");
2044 return XLAT_ACTION_FAIL;
2045 }
2046
2047 fr_value_box_bstrndup(dst, dst, NULL, fr_sbuff_start(agg), fr_sbuff_used(agg), false);
2048 fr_dcursor_append(out, dst);
2049 VALUE_BOX_LIST_VERIFY((fr_value_box_list_t *)out->dlist);
2050
2051 return XLAT_ACTION_DONE;
2052 }
2053
2054 /*
2055 * Copy inputs to outputs, casting them along the way.
2056 */
2057 arg = NULL;
2058 while ((arg = fr_value_box_list_next(args, arg)) != NULL) {
2059 fr_value_box_t *vb, *p;
2060
2061 fr_assert(arg->type == FR_TYPE_GROUP);
2062
2063 vb = fr_value_box_list_head(&arg->vb_group);
2064 while (vb) {
2065 p = fr_value_box_list_remove(&arg->vb_group, vb);
2066
2067 if (fr_value_box_cast_in_place(vb, vb, type, time_res) < 0) {
2068 RPEDEBUG("Failed casting %pV to data type '%s'", vb, fr_type_to_str(type));
2069 return XLAT_ACTION_FAIL;
2070 }
2072 vb = fr_value_box_list_next(&arg->vb_group, p);
2073 }
2074 }
2075 VALUE_BOX_LIST_VERIFY((fr_value_box_list_t *)out->dlist);
2076
2077 return XLAT_ACTION_DONE;
2078}
2079
2081 { .required = true, .type = FR_TYPE_VOID },
2082 { .concat = true, .type = FR_TYPE_STRING },
2084};
2085
2086/** Concatenate string representation of values of given attributes using separator
2087 *
2088 * First argument of is the list of attributes to concatenate, followed
2089 * by an optional separator
2090 *
2091 * Example:
2092@verbatim
2093%concat(%{request.[*]}, ',') == "<attr1value>,<attr2value>,<attr3value>,..."
2094%concat(%{Tmp-String-0[*]}, '. ') == "<str1value>. <str2value>. <str3value>. ..."
2095%concat(%join(%{User-Name}, %{Calling-Station-Id}), ', ') == "bob, aa:bb:cc:dd:ee:ff"
2096@endverbatim
2097 *
2098 * @ingroup xlat_functions
2099 */
2101 UNUSED xlat_ctx_t const *xctx,
2102 request_t *request, fr_value_box_list_t *args)
2103{
2104 fr_value_box_t *result;
2105 fr_value_box_t *list;
2106 fr_value_box_t *separator;
2107 fr_value_box_list_t *to_concat;
2108 char *buff;
2109 char const *sep;
2110
2111 XLAT_ARGS(args, &list, &separator);
2112
2113 sep = (separator) ? separator->vb_strvalue : "";
2114 to_concat = &list->vb_group;
2115
2116 result = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL);
2117 if (!result) {
2118 error:
2119 RPEDEBUG("Failed concatenating input");
2120 return XLAT_ACTION_FAIL;
2121 }
2122
2123 buff = fr_value_box_list_aprint(result, to_concat, sep, NULL);
2124 if (!buff) goto error;
2125
2127
2128 fr_dcursor_append(out, result);
2129
2130 return XLAT_ACTION_DONE;
2131}
2132
2134 { .required = true, .type = FR_TYPE_OCTETS },
2136};
2137
2138/** Print data as hex, not as VALUE.
2139 *
2140 * Example:
2141@verbatim
2142%hex("foobar") == "666f6f626172"
2143@endverbatim
2144 *
2145 * @see #xlat_func_bin
2146 *
2147 * @ingroup xlat_functions
2148 */
2150 UNUSED xlat_ctx_t const *xctx,
2151 UNUSED request_t *request, fr_value_box_list_t *args)
2152{
2153 char *new_buff;
2154 fr_value_box_t *list, *bin;
2155 fr_value_box_t safety;
2156
2157 XLAT_ARGS(args, &list);
2158
2159 while ((bin = fr_value_box_list_pop_head(&list->vb_group))) {
2160 fr_value_box_safety_copy(&safety, bin);
2161
2162 /*
2163 * Use existing box, but with new buffer
2164 */
2165 MEM(new_buff = talloc_zero_array(bin, char, (bin->vb_length * 2) + 1));
2166 if (bin->vb_length) {
2167 fr_base16_encode(&FR_SBUFF_OUT(new_buff, (bin->vb_length * 2) + 1),
2168 &FR_DBUFF_TMP(bin->vb_octets, bin->vb_length));
2170 fr_value_box_strdup_shallow(bin, NULL, new_buff, false);
2171 /*
2172 * Zero length binary > zero length hex string
2173 */
2174 } else {
2176 fr_value_box_strdup(bin, bin, NULL, "", false);
2177 }
2178
2179 fr_value_box_safety_copy(bin, &safety);
2180 fr_dcursor_append(out, bin);
2181 }
2182
2183 return XLAT_ACTION_DONE;
2184}
2185
2190
2191static xlat_action_t xlat_hmac(TALLOC_CTX *ctx, fr_dcursor_t *out,
2192 fr_value_box_list_t *args, uint8_t *digest, int digest_len, hmac_type type)
2193{
2194 fr_value_box_t *vb, *data, *key;
2195
2196 XLAT_ARGS(args, &data, &key);
2197
2198 if (type == HMAC_MD5) {
2199 /* coverity[dereference] */
2200 fr_hmac_md5(digest, data->vb_octets, data->vb_length, key->vb_octets, key->vb_length);
2201 } else if (type == HMAC_SHA1) {
2202 /* coverity[dereference] */
2203 fr_hmac_sha1(digest, data->vb_octets, data->vb_length, key->vb_octets, key->vb_length);
2204 }
2205
2206 MEM(vb = fr_value_box_alloc_null(ctx));
2207 fr_value_box_memdup(vb, vb, NULL, digest, digest_len, false);
2208
2210
2211 return XLAT_ACTION_DONE;
2212}
2213
2215 { .required = true, .concat = true, .type = FR_TYPE_STRING },
2216 { .required = true, .concat = true, .type = FR_TYPE_STRING },
2218};
2219
2220/** Generate the HMAC-MD5 of a string or attribute
2221 *
2222 * Example:
2223@verbatim
2224%hmacmd5('foo', 'bar') == "0x31b6db9e5eb4addb42f1a6ca07367adc"
2225@endverbatim
2226 *
2227 * @ingroup xlat_functions
2228 */
2230 UNUSED xlat_ctx_t const *xctx,
2231 UNUSED request_t *request, fr_value_box_list_t *in)
2232{
2233 uint8_t digest[MD5_DIGEST_LENGTH];
2234 return xlat_hmac(ctx, out, in, digest, MD5_DIGEST_LENGTH, HMAC_MD5);
2235}
2236
2237
2238/** Generate the HMAC-SHA1 of a string or attribute
2239 *
2240 * Example:
2241@verbatim
2242%hmacsha1('foo', 'bar') == "0x85d155c55ed286a300bd1cf124de08d87e914f3a"
2243@endverbatim
2244 *
2245 * @ingroup xlat_functions
2246 */
2248 UNUSED xlat_ctx_t const *xctx,
2249 UNUSED request_t *request, fr_value_box_list_t *in)
2250{
2252 return xlat_hmac(ctx, out, in, digest, SHA1_DIGEST_LENGTH, HMAC_SHA1);
2253}
2254
2256 { .required = true, .type = FR_TYPE_VOID },
2257 { .variadic = XLAT_ARG_VARIADIC_EMPTY_SQUASH, .type = FR_TYPE_VOID },
2259};
2260
2261/** Join a series of arguments to form a single list
2262 *
2263 * null boxes are not preserved.
2264 */
2266 UNUSED xlat_ctx_t const *xctx,
2267 UNUSED request_t *request, fr_value_box_list_t *in)
2268{
2270 fr_assert(arg->type == FR_TYPE_GROUP);
2271
2272 fr_value_box_list_foreach_safe(&arg->vb_group, vb) {
2273 fr_value_box_list_remove(&arg->vb_group, vb);
2275 }}
2276 }
2277 return XLAT_ACTION_DONE;
2278}
2279
2280static void ungroup(fr_dcursor_t *out, fr_value_box_list_t *in)
2281{
2282 fr_value_box_t *vb;
2283
2284 while ((vb = fr_value_box_list_pop_head(in)) != NULL) {
2285 if (vb->type != FR_TYPE_GROUP) {
2287 continue;
2288 }
2289 talloc_free(vb);
2290 }
2291}
2292
2293/** Ungroups all of its arguments into one flat list.
2294 *
2295 */
2297 UNUSED xlat_ctx_t const *xctx,
2298 UNUSED request_t *request, fr_value_box_list_t *in)
2299{
2300 fr_value_box_t *arg = NULL;
2301
2302 while ((arg = fr_value_box_list_next(in, arg)) != NULL) {
2303 fr_assert(arg->type == FR_TYPE_GROUP);
2304
2305 ungroup(out, &arg->vb_group);
2306 }
2307 return XLAT_ACTION_DONE;
2308}
2309
2311 { .single = true, .variadic = XLAT_ARG_VARIADIC_EMPTY_KEEP, .type = FR_TYPE_VOID },
2313};
2314
2315/** Return the on-the-wire size of the boxes in bytes
2316 *
2317 * skips null values
2318 *
2319 * Example:
2320@verbatim
2321%length(foobar) == 6
2322%length(%bin("0102030005060708")) == 8
2323@endverbatim
2324 *
2325 * @see #xlat_func_strlen
2326 *
2327 * @ingroup xlat_functions
2328 */
2330 UNUSED xlat_ctx_t const *xctx,
2331 UNUSED request_t *request, fr_value_box_list_t *in)
2332
2333{
2336
2337 MEM(my = fr_value_box_alloc(ctx, FR_TYPE_SIZE, NULL));
2338 if (!fr_type_is_null(vb->type)) my->vb_size = fr_value_box_network_length(vb);
2340 }
2341
2342 return XLAT_ACTION_DONE;
2343}
2344
2345
2347 { .concat = true, .type = FR_TYPE_OCTETS },
2349};
2350
2351/** Calculate the MD4 hash of a string or attribute.
2352 *
2353 * Example:
2354@verbatim
2355%md4("foo") == "0ac6700c491d70fb8650940b1ca1e4b2"
2356@endverbatim
2357 *
2358 * @ingroup xlat_functions
2359 */
2361 UNUSED xlat_ctx_t const *xctx,
2362 UNUSED request_t *request, fr_value_box_list_t *args)
2363{
2364 uint8_t digest[MD4_DIGEST_LENGTH];
2365 fr_value_box_t *vb;
2366 fr_value_box_t *in_head;
2367
2368 XLAT_ARGS(args, &in_head);
2369
2370 if (in_head) {
2371 fr_md4_calc(digest, in_head->vb_octets, in_head->vb_length);
2372 } else {
2373 /* Digest of empty string */
2374 fr_md4_calc(digest, NULL, 0);
2375 }
2376
2377 MEM(vb = fr_value_box_alloc_null(ctx));
2378 fr_value_box_memdup(vb, vb, NULL, digest, sizeof(digest), false);
2379
2381 VALUE_BOX_LIST_VERIFY((fr_value_box_list_t *)out->dlist);
2382
2383 return XLAT_ACTION_DONE;
2384}
2385
2387 { .concat = true, .type = FR_TYPE_OCTETS },
2389};
2390
2391/** Calculate the MD5 hash of a string or attribute.
2392 *
2393 * Example:
2394@verbatim
2395%md5("foo") == "acbd18db4cc2f85cedef654fccc4a4d8"
2396@endverbatim
2397 *
2398 * @ingroup xlat_functions
2399 */
2401 UNUSED xlat_ctx_t const *xctx,
2402 UNUSED request_t *request, fr_value_box_list_t *args)
2403{
2404 uint8_t digest[MD5_DIGEST_LENGTH];
2405 fr_value_box_t *vb;
2406 fr_value_box_t *in_head;
2407
2408 XLAT_ARGS(args, &in_head);
2409
2410 if (in_head) {
2411 fr_md5_calc(digest, in_head->vb_octets, in_head->vb_length);
2412 } else {
2413 /* Digest of empty string */
2414 fr_md5_calc(digest, NULL, 0);
2415 }
2416
2417 MEM(vb = fr_value_box_alloc_null(ctx));
2418 fr_value_box_memdup(vb, vb, NULL, digest, sizeof(digest), false);
2419
2421
2422 return XLAT_ACTION_DONE;
2423}
2424
2425
2426/** Encode attributes as a series of string attribute/value pairs
2427 *
2428 * This is intended to serialize one or more attributes as a comma
2429 * delimited string.
2430 *
2431 * Example:
2432@verbatim
2433%pairs.print(request.[*]) == 'User-Name = "foo"User-Password = "bar"'
2434%concat(%pairs.print.print(request.[*]), ', ') == 'User-Name = "foo", User-Password = "bar"'
2435@endverbatim
2436 *
2437 * @see #xlat_func_concat
2438 *
2439 * @ingroup xlat_functions
2440 */
2442 UNUSED xlat_ctx_t const *xctx,
2443 request_t *request, fr_value_box_list_t *args)
2444{
2445 fr_pair_t *vp;
2446 fr_dcursor_t *cursor;
2447 fr_value_box_t *vb;
2448 fr_value_box_t *in_head;
2449
2450 XLAT_ARGS(args, &in_head);
2451
2452 cursor = fr_value_box_get_cursor(in_head);
2453
2454 for (vp = fr_dcursor_current(cursor);
2455 vp;
2456 vp = fr_dcursor_next(cursor)) {
2457 char *buff;
2458
2459 MEM(vb = fr_value_box_alloc_null(ctx));
2460 if (unlikely(fr_pair_aprint(vb, &buff, NULL, vp) < 0)) {
2461 RPEDEBUG("Failed printing pair");
2462 talloc_free(vb);
2463 return XLAT_ACTION_FAIL;
2464 }
2465
2466 fr_value_box_bstrdup_buffer_shallow(NULL, vb, NULL, buff, false);
2468
2469 VALUE_BOX_VERIFY(vb);
2470 }
2471
2472 return XLAT_ACTION_DONE;
2473}
2474
2476 { .required = true, .single = true, .type = FR_TYPE_UINT32 },
2478};
2479
2480/** Generate a random integer value
2481 *
2482 * For "N = %rand(MAX)", 0 <= N < MAX
2483 *
2484 * Example:
2485@verbatim
2486%rand(100) == 42
2487@endverbatim
2488 *
2489 * @ingroup xlat_functions
2490 */
2492 UNUSED xlat_ctx_t const *xctx,
2493 UNUSED request_t *request, fr_value_box_list_t *in)
2494{
2495 int64_t result;
2496 fr_value_box_t *vb;
2497 fr_value_box_t *in_head = fr_value_box_list_head(in);
2498
2499 result = in_head->vb_uint32;
2500
2501 /* Make sure it isn't too big */
2502 if (result > (1 << 30)) result = (1 << 30);
2503
2504 result *= fr_rand(); /* 0..2^32-1 */
2505 result >>= 32;
2506
2507 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_UINT64, NULL));
2508 vb->vb_uint64 = result;
2509
2511
2512 return XLAT_ACTION_DONE;
2513}
2514
2516 { .required = true, .concat = true, .type = FR_TYPE_STRING },
2518};
2519
2520/** Generate a string of random chars
2521 *
2522 * Build strings of random chars, useful for generating tokens and passcodes
2523 * Format similar to String::Random.
2524 *
2525 * Format characters may include the following, and may be
2526 * preceded by a repetition count:
2527 * - "c" lowercase letters
2528 * - "C" uppercase letters
2529 * - "n" numbers
2530 * - "a" alphanumeric
2531 * - "!" punctuation
2532 * - "." alphanumeric + punctuation
2533 * - "s" alphanumeric + "./"
2534 * - "o" characters suitable for OTP (easily confused removed)
2535 * - "b" binary data
2536 *
2537 * Example:
2538@verbatim
2539%randstr("CCCC!!cccnnn") == "IPFL>{saf874"
2540%randstr("42o") == "yHdupUwVbdHprKCJRYfGbaWzVwJwUXG9zPabdGAhM9"
2541%hex(%randstr("bbbb")) == "a9ce04f3"
2542%hex(%randstr("8b")) == "fe165529f9f66839"
2543@endverbatim
2544 * @ingroup xlat_functions
2545 */
2547 UNUSED xlat_ctx_t const *xctx,
2548 request_t *request, fr_value_box_list_t *args)
2549{
2550 /*
2551 * Lookup tables for randstr char classes
2552 */
2553 static char randstr_punc[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
2554 static char randstr_salt[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz/.";
2555
2556 /*
2557 * Characters humans rarely confuse. Reduces char set considerably
2558 * should only be used for things such as one time passwords.
2559 */
2560 static char randstr_otp[] = "469ACGHJKLMNPQRUVWXYabdfhijkprstuvwxyz";
2561
2562 char const *p, *start, *end;
2563 char *endptr;
2564 char *buff_p;
2565 unsigned int result;
2566 unsigned int reps;
2567 size_t outlen = 0;
2568 fr_value_box_t* vb;
2569 fr_value_box_t *in_head;
2570
2571 XLAT_ARGS(args, &in_head);
2572
2573 /** Max repetitions of a single character class
2574 *
2575 */
2576#define REPETITION_MAX 1024
2577
2578 start = p = in_head->vb_strvalue;
2579 end = p + in_head->vb_length;
2580
2581 /*
2582 * Calculate size of output
2583 */
2584 while (p < end) {
2585 /*
2586 * Repetition modifiers.
2587 *
2588 * We limit it to REPETITION_MAX, because we don't want
2589 * utter stupidity.
2590 */
2591 if (isdigit((uint8_t) *p)) {
2592 reps = strtol(p, &endptr, 10);
2593 if (reps > REPETITION_MAX) reps = REPETITION_MAX;
2594 outlen += reps;
2595 p = endptr;
2596 } else {
2597 outlen++;
2598 }
2599 p++;
2600 }
2601
2602 MEM(vb = fr_value_box_alloc_null(ctx));
2603 MEM(fr_value_box_bstr_alloc(vb, &buff_p, vb, NULL, outlen, false) == 0);
2604
2605 /* Reset p to start position */
2606 p = start;
2607
2608 while (p < end) {
2609 size_t i;
2610
2611 if (isdigit((uint8_t) *p)) {
2612 reps = strtol(p, &endptr, 10);
2613 if (reps > REPETITION_MAX) {
2614 reps = REPETITION_MAX;
2615 RMARKER(L_WARN, L_DBG_LVL_2, start, start - p,
2616 "Forcing repetition to %u", (unsigned int)REPETITION_MAX);
2617 }
2618 p = endptr;
2619 } else {
2620 reps = 1;
2621 }
2622
2623 for (i = 0; i < reps; i++) {
2624 result = fr_rand();
2625 switch (*p) {
2626 /*
2627 * Lowercase letters
2628 */
2629 case 'c':
2630 *buff_p++ = 'a' + (result % 26);
2631 break;
2632
2633 /*
2634 * Uppercase letters
2635 */
2636 case 'C':
2637 *buff_p++ = 'A' + (result % 26);
2638 break;
2639
2640 /*
2641 * Numbers
2642 */
2643 case 'n':
2644 *buff_p++ = '0' + (result % 10);
2645 break;
2646
2647 /*
2648 * Alpha numeric
2649 */
2650 case 'a':
2651 *buff_p++ = randstr_salt[result % (sizeof(randstr_salt) - 3)];
2652 break;
2653
2654 /*
2655 * Punctuation
2656 */
2657 case '!':
2658 *buff_p++ = randstr_punc[result % (sizeof(randstr_punc) - 1)];
2659 break;
2660
2661 /*
2662 * Alpha numeric + punctuation
2663 */
2664 case '.':
2665 *buff_p++ = '!' + (result % 95);
2666 break;
2667
2668 /*
2669 * Alpha numeric + salt chars './'
2670 */
2671 case 's':
2672 *buff_p++ = randstr_salt[result % (sizeof(randstr_salt) - 1)];
2673 break;
2674
2675 /*
2676 * Chars suitable for One Time Password tokens.
2677 * Alpha numeric with easily confused char pairs removed.
2678 */
2679 case 'o':
2680 *buff_p++ = randstr_otp[result % (sizeof(randstr_otp) - 1)];
2681 break;
2682
2683 /*
2684 * Binary data - Copy between 1-4 bytes at a time
2685 */
2686 case 'b':
2687 {
2688 size_t copy = (reps - i) > sizeof(result) ? sizeof(result) : reps - i;
2689
2690 memcpy(buff_p, (uint8_t *)&result, copy);
2691 buff_p += copy;
2692 i += (copy - 1); /* Loop +1 */
2693 }
2694 break;
2695
2696 default:
2697 REDEBUG("Invalid character class '%c'", *p);
2698 talloc_free(vb);
2699
2700 return XLAT_ACTION_FAIL;
2701 }
2702 }
2703
2704 p++;
2705 }
2706
2707 *buff_p++ = '\0';
2708
2710
2711 return XLAT_ACTION_DONE;
2712}
2713
2714/** Convert a UUID in an array of uint32_t to the conventional string representation.
2715 */
2716static int uuid_print_vb(fr_value_box_t *vb, uint32_t vals[4])
2717{
2718 char buffer[36];
2719 int i, j = 0;
2720
2721#define UUID_CHARS(_v, _num) for (i = 0; i < _num; i++) { \
2722 buffer[j++] = fr_base16_alphabet_encode_lc[(uint8_t)((vals[_v] & 0xf0000000) >> 28)]; \
2723 vals[_v] = vals[_v] << 4; \
2724 }
2725
2726 UUID_CHARS(0, 8)
2727 buffer[j++] = '-';
2728 UUID_CHARS(1, 4)
2729 buffer[j++] = '-';
2730 UUID_CHARS(1, 4);
2731 buffer[j++] = '-';
2732 UUID_CHARS(2, 4);
2733 buffer[j++] = '-';
2734 UUID_CHARS(2, 4);
2735 UUID_CHARS(3, 8);
2736
2737 return fr_value_box_bstrndup(vb, vb, NULL, buffer, sizeof(buffer), false);
2738}
2739
2740static inline void uuid_set_version(uint32_t vals[4], uint8_t version)
2741{
2742 /*
2743 * The version is indicated by the upper 4 bits of byte 7 - the 3rd byte of vals[1]
2744 */
2745 vals[1] = (vals[1] & 0xffff0fff) | (((uint32_t)version & 0x0f) << 12);
2746}
2747
2748static inline void uuid_set_variant(uint32_t vals[4], uint8_t variant)
2749{
2750 /*
2751 * The variant is indicated by the first 1, 2 or 3 bits of byte 9
2752 * The number of bits is determined by the variant.
2753 */
2754 switch (variant) {
2755 case 0:
2756 vals[2] = vals[2] & 0x7fffffff;
2757 break;
2758
2759 case 1:
2760 vals[2] = (vals[2] & 0x3fffffff) | 0x80000000;
2761 break;
2762
2763 case 2:
2764 vals[2] = (vals[2] & 0x3fffffff) | 0xc0000000;
2765 break;
2766
2767 case 3:
2768 vals[2] = vals[2] | 0xe0000000;
2769 break;
2770 }
2771}
2772
2773/** Generate a version 4 UUID
2774 *
2775 * Version 4 UUIDs are all random except the version and variant fields
2776 *
2777 * Example:
2778@verbatim
2779%uuid.v4 == "cba48bda-641c-42ae-8173-d97aa04f888a"
2780@endverbatim
2781 * @ingroup xlat_functions
2782 */
2783static xlat_action_t xlat_func_uuid_v4(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx,
2784 UNUSED request_t *request, UNUSED fr_value_box_list_t *args)
2785{
2786 fr_value_box_t *vb;
2787 uint32_t vals[4];
2788 int i;
2789
2790 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL));
2791
2792 /*
2793 * A type 4 UUID is all random except a few bits.
2794 * Start with 128 bits of random.
2795 */
2796 for (i = 0; i < 4; i++) vals[i] = fr_rand();
2797
2798 /*
2799 * Set the version and variant fields
2800 */
2801 uuid_set_version(vals, 4);
2802 uuid_set_variant(vals, 1);
2803
2804 if (uuid_print_vb(vb, vals) < 0) return XLAT_ACTION_FAIL;
2805
2807 return XLAT_ACTION_DONE;
2808}
2809
2810/** Generate a version 7 UUID
2811 *
2812 * Version 7 UUIDs use 48 bits of unix millisecond epoch and 74 bits of random
2813 *
2814 * Example:
2815@verbatim
2816%uuid.v7 == "019a58d8-8524-7342-aa07-c0fa2bba6a4e"
2817@endverbatim
2818 * @ingroup xlat_functions
2819 */
2820static xlat_action_t xlat_func_uuid_v7(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx,
2821 UNUSED request_t *request, UNUSED fr_value_box_list_t *args)
2822{
2823 fr_value_box_t *vb;
2824 uint32_t vals[4];
2825 int i;
2826 uint64_t now;
2827
2828 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL));
2829
2830 /*
2831 * A type 7 UUID has random data from bit 48
2832 * Start with random from bit 32 - since fr_rand is uint32
2833 */
2834 for (i = 1; i < 4; i++) vals[i] = fr_rand();
2835
2836 /*
2837 * The millisecond epoch fills the first 48 bits
2838 */
2839 now = fr_time_to_msec(fr_time());
2840 now = now << 16;
2841 vals[0] = now >> 32;
2842 vals[1] = (vals[1] & 0x0000ffff) | (now & 0xffff0000);
2843
2844 /*
2845 * Set the version and variant fields
2846 */
2847 uuid_set_version(vals, 7);
2848 uuid_set_variant(vals, 1);
2849
2850 if (uuid_print_vb(vb, vals) < 0) return XLAT_ACTION_FAIL;
2851
2853 return XLAT_ACTION_DONE;
2854}
2855
2857 { .required = true, .type = FR_TYPE_UINT64 },
2858 { .required = false, .type = FR_TYPE_UINT64 },
2859 { .required = false, .type = FR_TYPE_UINT64 },
2861};
2862
2863/** Generate a range of uint64 numbers
2864 *
2865 * Example:
2866@verbatim
2867%range(end) - 0..end
2868%rang(start, end)
2869%range(start,end, step)
2870@endverbatim
2871 * @ingroup xlat_functions
2872 */
2874 UNUSED xlat_ctx_t const *xctx,
2875 request_t *request, fr_value_box_list_t *args)
2876{
2877 fr_value_box_t *start_vb, *end_vb, *step_vb;
2878 fr_value_box_t *dst;
2879 uint64_t i, start, end, step;
2880
2881 XLAT_ARGS(args, &start_vb, &end_vb, &step_vb);
2882
2883 if (step_vb) {
2884 start = fr_value_box_list_head(&start_vb->vb_group)->vb_uint64;
2885 end = fr_value_box_list_head(&end_vb->vb_group)->vb_uint64;
2886 step = fr_value_box_list_head(&step_vb->vb_group)->vb_uint64;
2887
2888 } else if (end_vb) {
2889 start = fr_value_box_list_head(&start_vb->vb_group)->vb_uint64;
2890 end = fr_value_box_list_head(&end_vb->vb_group)->vb_uint64;
2891 step = 1;
2892
2893 } else {
2894 start = 0;
2895 end = fr_value_box_list_head(&start_vb->vb_group)->vb_uint64;
2896 step = 1;
2897 }
2898
2899 if (end <= start) {
2900 REDEBUG("Invalid range - 'start' must be less than 'end'");
2901 return XLAT_ACTION_FAIL;
2902 }
2903
2904 if (!step) {
2905 REDEBUG("Invalid range - 'step' must be greater than zero");
2906 return XLAT_ACTION_FAIL;
2907 }
2908
2909 if (step > (end - start)) {
2910 REDEBUG("Invalid range - 'step' must allow for at least one result");
2911 return XLAT_ACTION_FAIL;
2912 }
2913
2914 if (((end - start) / step) > 1000) {
2915 REDEBUG("Invalid range - Too many results");
2916 return XLAT_ACTION_FAIL;
2917 }
2918
2919 for (i = start; i < end; i += step) {
2920 MEM(dst = fr_value_box_alloc(ctx, FR_TYPE_UINT64, NULL));
2921 dst->vb_uint64 = i;
2922 fr_dcursor_append(out, dst);
2923 }
2924
2925 return XLAT_ACTION_DONE;
2926}
2927
2928static int CC_HINT(nonnull(2,3)) regex_xlat_escape(UNUSED request_t *request, fr_value_box_t *vb, UNUSED void *uctx)
2929{
2930 ssize_t slen;
2931 fr_sbuff_t *out = NULL;
2932 fr_value_box_entry_t entry;
2933
2934 FR_SBUFF_TALLOC_THREAD_LOCAL(&out, 256, 4096);
2935
2936 slen = fr_value_box_print(out, vb, &regex_escape_rules);
2937 if (slen < 0) return -1;
2938
2939 entry = vb->entry;
2941 (void) fr_value_box_bstrndup(vb, vb, NULL, fr_sbuff_start(out), fr_sbuff_used(out), false);
2942 vb->entry = entry;
2943
2944 return 0;
2945}
2946
2951
2952
2953/** Get named subcapture value from previous regex
2954 *
2955 * Example:
2956@verbatim
2957if ("foo" =~ /^(?<name>.*)/) {
2958 noop
2959}
2960%regex.match(name) == "foo"
2961@endverbatim
2962 *
2963 * @ingroup xlat_functions
2964 */
2966 UNUSED xlat_ctx_t const *xctx,
2967 request_t *request, fr_value_box_list_t *in)
2968{
2969 fr_value_box_t *in_head = fr_value_box_list_head(in);
2970
2971 /*
2972 * Find the first child of the first argument group
2973 */
2974 fr_value_box_t *arg = fr_value_box_list_head(&in_head->vb_group);
2975
2976 /*
2977 * Return the complete capture if no other capture is specified
2978 */
2979 if (!arg) {
2980 fr_value_box_t *vb;
2981
2982 MEM(vb = fr_value_box_alloc_null(ctx));
2983 if (regex_request_to_sub(vb, vb, request, 0) < 0) {
2984 REDEBUG2("No previous regex capture");
2985 talloc_free(vb);
2986 return XLAT_ACTION_FAIL;
2987 }
2988
2990
2991 return XLAT_ACTION_DONE;
2992 }
2993
2994 switch (arg->type) {
2995 /*
2996 * If the input is an integer value then get an
2997 * arbitrary subcapture index.
2998 */
2999 case FR_TYPE_NUMERIC:
3000 {
3001 fr_value_box_t idx;
3002 fr_value_box_t *vb;
3003
3004 if (fr_value_box_list_next(in, in_head)) {
3005 REDEBUG("Only one subcapture argument allowed");
3006 return XLAT_ACTION_FAIL;
3007 }
3008
3009 if (fr_value_box_cast(NULL, &idx, FR_TYPE_UINT32, NULL, arg) < 0) {
3010 RPEDEBUG("Bad subcapture index");
3011 return XLAT_ACTION_FAIL;
3012 }
3013
3014 MEM(vb = fr_value_box_alloc_null(ctx));
3015 if (regex_request_to_sub(vb, vb, request, idx.vb_uint32) < 0) {
3016 REDEBUG2("No previous numbered regex capture group '%u'", idx.vb_uint32);
3017 talloc_free(vb);
3018 return XLAT_ACTION_DONE;
3019 }
3021
3022 return XLAT_ACTION_DONE;
3023 }
3024
3025 default:
3026#if defined(HAVE_REGEX_PCRE) || defined(HAVE_REGEX_PCRE2)
3027 {
3028 fr_value_box_t *vb;
3029
3030 /*
3031 * Concatenate all input
3032 */
3034 arg, &in_head->vb_group, FR_TYPE_STRING,
3036 SIZE_MAX) < 0) {
3037 RPEDEBUG("Failed concatenating input");
3038 return XLAT_ACTION_FAIL;
3039 }
3040
3041 MEM(vb = fr_value_box_alloc_null(ctx));
3042 if (regex_request_to_sub_named(vb, vb, request, arg->vb_strvalue) < 0) {
3043 REDEBUG2("No previous named regex capture group '%s'", arg->vb_strvalue);
3044 talloc_free(vb);
3045 return XLAT_ACTION_DONE; /* NOT an error, just an empty result */
3046 }
3048
3049 return XLAT_ACTION_DONE;
3050 }
3051#else
3052 RDEBUG("Named regex captures are not supported (they require libpcre2)");
3053 return XLAT_ACTION_FAIL;
3054#endif
3055 }
3056}
3057
3059 { .concat = true, .type = FR_TYPE_OCTETS },
3061};
3062
3063/** Calculate the SHA1 hash of a string or attribute.
3064 *
3065 * Example:
3066@verbatim
3067%sha1(foo) == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
3068@endverbatim
3069 *
3070 * @ingroup xlat_functions
3071 */
3073 UNUSED xlat_ctx_t const *xctx,
3074 UNUSED request_t *request, fr_value_box_list_t *args)
3075{
3077 fr_sha1_ctx sha1_ctx;
3078 fr_value_box_t *vb;
3079 fr_value_box_t *in_head;
3080
3081 XLAT_ARGS(args, &in_head);
3082
3083 fr_sha1_init(&sha1_ctx);
3084 if (in_head) {
3085 fr_sha1_update(&sha1_ctx, in_head->vb_octets, in_head->vb_length);
3086 } else {
3087 /* sha1 of empty string */
3088 fr_sha1_update(&sha1_ctx, NULL, 0);
3089 }
3090 fr_sha1_final(digest, &sha1_ctx);
3091
3092 MEM(vb = fr_value_box_alloc_null(ctx));
3093 fr_value_box_memdup(vb, vb, NULL, digest, sizeof(digest), false);
3094
3096
3097 return XLAT_ACTION_DONE;
3098}
3099
3100/** Calculate any digest supported by OpenSSL EVP_MD
3101 *
3102 * Example:
3103@verbatim
3104%sha2_256(foo) == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
3105@endverbatim
3106 *
3107 * @ingroup xlat_functions
3108 */
3109#ifdef HAVE_OPENSSL_EVP_H
3110static xlat_action_t xlat_evp_md(TALLOC_CTX *ctx, fr_dcursor_t *out,
3111 UNUSED xlat_ctx_t const *xctx,
3112 UNUSED request_t *request, fr_value_box_list_t *args, EVP_MD const *md)
3113{
3114 uint8_t digest[EVP_MAX_MD_SIZE];
3115 unsigned int digestlen;
3116 EVP_MD_CTX *md_ctx;
3117 fr_value_box_t *vb;
3118 fr_value_box_t *in_head;
3119
3120 XLAT_ARGS(args, &in_head);
3121
3122 md_ctx = EVP_MD_CTX_create();
3123 EVP_DigestInit_ex(md_ctx, md, NULL);
3124 if (in_head) {
3125 EVP_DigestUpdate(md_ctx, in_head->vb_octets, in_head->vb_length);
3126 } else {
3127 EVP_DigestUpdate(md_ctx, NULL, 0);
3128 }
3129 EVP_DigestFinal_ex(md_ctx, digest, &digestlen);
3130 EVP_MD_CTX_destroy(md_ctx);
3131
3132 MEM(vb = fr_value_box_alloc_null(ctx));
3133 fr_value_box_memdup(vb, vb, NULL, digest, digestlen, false);
3134
3136
3137 return XLAT_ACTION_DONE;
3138}
3139
3140# define EVP_MD_XLAT(_md, _md_func) \
3141static xlat_action_t xlat_func_##_md(TALLOC_CTX *ctx, fr_dcursor_t *out,\
3142 xlat_ctx_t const *xctx, \
3143 request_t *request,\
3144 fr_value_box_list_t *in)\
3145{\
3146 return xlat_evp_md(ctx, out, xctx, request, in, EVP_##_md_func());\
3147}
3148
3149EVP_MD_XLAT(sha2_224, sha224)
3150EVP_MD_XLAT(sha2_256, sha256)
3151EVP_MD_XLAT(sha2_384, sha384)
3152EVP_MD_XLAT(sha2_512, sha512)
3153
3154/*
3155 * OpenWRT's OpenSSL library doesn't contain these by default
3156 */
3157#ifdef HAVE_EVP_BLAKE2S256
3158EVP_MD_XLAT(blake2s_256, blake2s256)
3159#endif
3160
3161#ifdef HAVE_EVP_BLAKE2B512
3162EVP_MD_XLAT(blake2b_512, blake2b512)
3163#endif
3164
3165EVP_MD_XLAT(sha3_224, sha3_224)
3166EVP_MD_XLAT(sha3_256, sha3_256)
3167EVP_MD_XLAT(sha3_384, sha3_384)
3168EVP_MD_XLAT(sha3_512, sha3_512)
3169#endif
3170
3171
3173 { .required = true, .concat = true, .type = FR_TYPE_STRING },
3175};
3176
3178 { .concat = true, .type = FR_TYPE_STRING },
3180};
3181
3182/** Print length of given string
3183 *
3184 * Example:
3185@verbatim
3186%strlen(foo) == 3
3187@endverbatim
3188 *
3189 * @see #xlat_func_length
3190 *
3191 * @ingroup xlat_functions
3192 */
3194 UNUSED xlat_ctx_t const *xctx,
3195 UNUSED request_t *request, fr_value_box_list_t *args)
3196{
3197 fr_value_box_t *vb;
3198 fr_value_box_t *in_head;
3199
3200 XLAT_ARGS(args, &in_head);
3201
3202 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_SIZE, NULL));
3203
3204 if (!in_head) {
3205 vb->vb_size = 0;
3206 } else {
3207 vb->vb_size = strlen(in_head->vb_strvalue);
3208 }
3209
3211
3212 return XLAT_ACTION_DONE;
3213}
3214
3216 { .concat = true, .type = FR_TYPE_STRING },
3217 { .single = true, .type = FR_TYPE_BOOL },
3219};
3220
3221/** Return whether a string has only printable chars
3222 *
3223 * This function returns true if the input string contains UTF8 sequences and printable chars.
3224 *
3225 * @note "\t" and " " are considered unprintable chars, unless the second argument(relaxed) is true.
3226 *
3227 * Example:
3228@verbatim
3229%str.printable("🍉abcdef🍓") == true
3230%str.printable("\000\n\r\t") == false
3231%str.printable("\t abcd", yes) == true
3232@endverbatim
3233 *
3234 * @ingroup xlat_functions
3235 */
3237 UNUSED xlat_ctx_t const *xctx,
3238 UNUSED request_t *request, fr_value_box_list_t *args)
3239{
3240 fr_value_box_t *vb;
3241 fr_value_box_t *str;
3242 fr_value_box_t *relaxed_vb;
3243 uint8_t const *p, *end;
3244 bool relaxed = false;
3245
3246 XLAT_ARGS(args, &str, &relaxed_vb);
3247
3248 if (relaxed_vb) relaxed = relaxed_vb->vb_bool;
3249
3250 p = (uint8_t const *)str->vb_strvalue;
3251 end = p + str->vb_length;
3252
3253 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
3255 vb->vb_bool = false;
3256
3257 do {
3258 size_t clen;
3259
3260 if ((*p < '!') &&
3261 (!relaxed || ((*p != '\t') && (*p != ' ')))) return XLAT_ACTION_DONE;
3262
3263 if (*p == 0x7f) return XLAT_ACTION_DONE;
3264
3265 clen = fr_utf8_char(p, end - p);
3266 if (clen == 0) return XLAT_ACTION_DONE;
3267 p += clen;
3268 } while (p < end);
3269
3270 vb->vb_bool = true;
3271
3272 return XLAT_ACTION_DONE;
3273}
3274
3276 { .concat = true, .type = FR_TYPE_STRING },
3278};
3279
3280/** Return whether a string is valid UTF-8
3281 *
3282 * This function returns true if the input string is valid UTF-8, false otherwise.
3283 *
3284 * Example:
3285@verbatim
3286%str.utf8(🍉🥝🍓) == true
3287%str.utf8(🍉\xff🍓) == false
3288@endverbatim
3289 *
3290 * @ingroup xlat_functions
3291 */
3293 UNUSED xlat_ctx_t const *xctx,
3294 UNUSED request_t *request, fr_value_box_list_t *args)
3295{
3296 fr_value_box_t *vb;
3297 fr_value_box_t *in_head;
3298
3299 XLAT_ARGS(args, &in_head);
3300
3301 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
3302 vb->vb_bool = (fr_utf8_str((uint8_t const *)in_head->vb_strvalue,
3303 in_head->vb_length) >= 0);
3304
3306
3307 return XLAT_ACTION_DONE;
3308}
3309
3311 { .single = true, .required = true, .type = FR_TYPE_VOID },
3312 { .single = true, .required = true, .type = FR_TYPE_INT32 },
3313 { .single = true, .type = FR_TYPE_INT32 },
3315};
3316
3317/** Extract a substring from string / octets data
3318 *
3319 * Non string / octets data is cast to a string.
3320 *
3321 * Second parameter is start position, optional third parameter is length
3322 * Negative start / length count from RHS of data.
3323 *
3324 * Example: (User-Name = "hello")
3325@verbatim
3326%substr(&User-Name, 1, 3) == 'ell'
3327@endverbatim
3328 *
3329 * @ingroup xlat_functions
3330 */
3331static xlat_action_t xlat_func_substr(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx,
3332 request_t *request, fr_value_box_list_t *args)
3333{
3334 fr_value_box_t *in = NULL, *start_vb, *len_vb, *vb;
3335 int32_t start, end, len;
3336
3337 XLAT_ARGS(args, &in, &start_vb, &len_vb);
3338
3339 switch (in->type) {
3340 case FR_TYPE_OCTETS:
3341 case FR_TYPE_STRING:
3342 break;
3343
3344 default:
3346 RPEDEBUG("Failed casting value to string");
3347 return XLAT_ACTION_FAIL;
3348 }
3349 break;
3350 }
3351
3352 if (start_vb->vb_int32 > (int32_t)in->vb_length) return XLAT_ACTION_DONE;
3353
3354 if (start_vb->vb_int32 < 0) {
3355 start = in->vb_length + start_vb->vb_int32;
3356 if (start < 0) start = 0;
3357 } else {
3358 start = start_vb->vb_int32;
3359 }
3360
3361 if (len_vb) {
3362 if (len_vb->vb_int32 < 0) {
3363 end = in->vb_length + len_vb->vb_int32;
3364 if (end < 0) return XLAT_ACTION_DONE;
3365 } else {
3366 end = start + len_vb->vb_int32;
3367 if (end > (int32_t)in->vb_length) end = in->vb_length;
3368 }
3369 } else {
3370 end = in->vb_length;
3371 }
3372
3373 if (start >= end) return XLAT_ACTION_DONE;
3374
3375 MEM(vb = fr_value_box_alloc(ctx, in->type, NULL));
3376
3377 len = end - start;
3378 switch (in->type) {
3379 case FR_TYPE_STRING:
3380 fr_value_box_bstrndup(vb, vb, NULL, &in->vb_strvalue[start], len, false);
3381 break;
3382 case FR_TYPE_OCTETS:
3383 {
3384 uint8_t *buf;
3385 fr_value_box_mem_alloc(vb, &buf, vb, NULL, len, false);
3386 memcpy(buf, &in->vb_octets[start], len);
3387 }
3388 break;
3389 default:
3390 fr_assert(0);
3391 }
3392
3395
3396 return XLAT_ACTION_DONE;
3397}
3398
3399#ifdef HAVE_REGEX_PCRE2
3400/** Cache statically compiled expressions
3401 */
3402typedef struct {
3403 regex_t *pattern;
3404 fr_regex_flags_t flags;
3405} xlat_subst_regex_inst_t;
3406
3407/** Pre-compile regexes where possible
3408 */
3409static int xlat_instantiate_subst_regex(xlat_inst_ctx_t const *xctx)
3410{
3411 xlat_subst_regex_inst_t *inst = talloc_get_type_abort(xctx->inst, xlat_subst_regex_inst_t);
3412 xlat_exp_t *patt_exp;
3413 fr_sbuff_t sbuff;
3414 fr_sbuff_marker_t start_m, end_m;
3415
3416 /* args #2 (pattern) */
3417 patt_exp = fr_dlist_next(&xctx->ex->call.args->dlist, fr_dlist_head(&xctx->ex->call.args->dlist));
3418 fr_assert(patt_exp && patt_exp->type == XLAT_GROUP); /* args must be groups */
3419
3420 /* If there are dynamic expansions, we can't pre-compile */
3421 if (!xlat_is_literal(patt_exp->group)) return 0;
3422 fr_assert(fr_dlist_num_elements(&patt_exp->group->dlist) == 1);
3423
3424 patt_exp = fr_dlist_head(&patt_exp->group->dlist);
3425
3426 /* We can only pre-compile strings */
3427 if (!fr_type_is_string(patt_exp->data.type)) return 0;
3428
3429 sbuff = FR_SBUFF_IN(patt_exp->data.vb_strvalue, patt_exp->data.vb_length);
3430
3431 /* skip any whitesapce */
3432 fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, 0);
3433
3434 /* Is the next char a forward slash? */
3435 if (fr_sbuff_next_if_char(&sbuff, '/')) {
3436 fr_slen_t slen;
3437
3438 fr_sbuff_marker(&start_m, &sbuff);
3439
3440 if (!fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '/')) return 0; /* Not a regex */
3441
3442 fr_sbuff_marker(&end_m, &sbuff);
3443 fr_sbuff_next(&sbuff); /* skip trailing slash */
3444
3445 if (fr_sbuff_remaining(&sbuff)) {
3446 slen = regex_flags_parse(NULL, &inst->flags,
3447 &sbuff,
3448 NULL, true);
3449 if (slen < 0) {
3450 PERROR("Failed parsing regex flags in \"%s\"", patt_exp->data.vb_strvalue);
3451 return -1;
3452 }
3453 }
3454
3455 if (regex_compile(inst, &inst->pattern,
3456 fr_sbuff_current(&start_m), fr_sbuff_current(&end_m) - fr_sbuff_current(&start_m),
3457 &inst->flags, true, false) <= 0) {
3458 PERROR("Failed compiling regex \"%s\"", patt_exp->data.vb_strvalue);
3459 return -1;
3460 }
3461 }
3462 /* No... then it's not a regex */
3463
3464 return 0;
3465}
3466
3467/** Perform regex substitution TODO CHECK
3468 *
3469 * Called when %subst() pattern begins with "/"
3470 *
3471@verbatim
3472%subst(<subject>, /<regex>/[flags], <replace>)
3473@endverbatim
3474 *
3475 * Example: (User-Name = "foo")
3476@verbatim
3477%subst(%{User-Name}, /oo.*$/, 'un') == "fun"
3478@endverbatim
3479 *
3480 * @note References can be specified in the replacement string with $<ref>
3481 *
3482 * @see #xlat_func_subst
3483 *
3484 * @ingroup xlat_functions
3485 */
3486static int xlat_func_subst_regex(TALLOC_CTX *ctx, fr_dcursor_t *out,
3487 xlat_ctx_t const *xctx, request_t *request,
3488 fr_value_box_list_t *args)
3489{
3490 xlat_subst_regex_inst_t const *inst = talloc_get_type_abort_const(xctx->inst, xlat_subst_regex_inst_t);
3491 fr_sbuff_t sbuff;
3492 fr_sbuff_marker_t start_m, end_m;
3493 char *buff;
3494 ssize_t slen;
3495 regex_t *pattern, *our_pattern = NULL;
3496 fr_regex_flags_t const *flags;
3497 fr_regex_flags_t our_flags = {};
3498 fr_value_box_t *vb;
3499 fr_value_box_t *subject_vb;
3500 fr_value_box_t *regex_vb;
3501 fr_value_box_t *rep_vb;
3502
3503 XLAT_ARGS(args, &subject_vb, &regex_vb, &rep_vb);
3504
3505 /*
3506 * Was not pre-compiled, so we need to compile it now
3507 */
3508 if (!inst->pattern) {
3509 sbuff = FR_SBUFF_IN(regex_vb->vb_strvalue, regex_vb->vb_length);
3510 if (fr_sbuff_len(&sbuff) == 0) {
3511 REDEBUG("Regex must not be empty");
3512 return XLAT_ACTION_FAIL;
3513 }
3514
3515 fr_sbuff_next(&sbuff); /* skip leading slash */
3516 fr_sbuff_marker(&start_m, &sbuff);
3517
3518 if (!fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '/')) return 1; /* Not a regex */
3519
3520 fr_sbuff_marker(&end_m, &sbuff);
3521 fr_sbuff_next(&sbuff); /* skip trailing slash */
3522
3523 slen = regex_flags_parse(NULL, &our_flags, &sbuff, NULL, true);
3524 if (slen < 0) {
3525 RPEDEBUG("Failed parsing regex flags");
3526 return -1;
3527 }
3528
3529 /*
3530 * Process the substitution
3531 */
3532 if (regex_compile(NULL, &our_pattern,
3533 fr_sbuff_current(&start_m), fr_sbuff_current(&end_m) - fr_sbuff_current(&start_m),
3534 &our_flags, true, true) <= 0) {
3535 RPEDEBUG("Failed compiling regex");
3536 return -1;
3537 }
3538 pattern = our_pattern;
3539 flags = &our_flags;
3540 } else {
3541 pattern = inst->pattern;
3542 flags = &inst->flags;
3543 }
3544
3545 MEM(vb = fr_value_box_alloc_null(ctx));
3546 if (regex_substitute(vb, &buff, 0, pattern, flags,
3547 subject_vb->vb_strvalue, subject_vb->vb_length,
3548 rep_vb->vb_strvalue, rep_vb->vb_length, NULL) < 0) {
3549 RPEDEBUG("Failed performing substitution");
3550 talloc_free(vb);
3551 talloc_free(pattern);
3552 return -1;
3553 }
3554 fr_value_box_bstrdup_buffer_shallow(NULL, vb, NULL, buff, false);
3555
3556 fr_value_box_safety_copy(vb, subject_vb);
3557 fr_value_box_safety_merge(vb, rep_vb);
3558
3560
3561 talloc_free(our_pattern);
3562
3563 return 0;
3564}
3565#endif
3566
3568 { .required = true, .concat = true, .type = FR_TYPE_STRING },
3569 { .required = true, .concat = true, .type = FR_TYPE_STRING },
3570 { .required = true, .concat = true, .type = FR_TYPE_STRING },
3572};
3573
3574/** Perform regex substitution
3575 *
3576@verbatim
3577%subst(<subject>, <pattern>, <replace>)
3578@endverbatim
3579 *
3580 * Example: (User-Name = "foobar")
3581@verbatim
3582%subst(%{User-Name}, 'oo', 'un') == "funbar"
3583@endverbatim
3584 *
3585 * @see xlat_func_subst_regex
3586 *
3587 * @ingroup xlat_functions
3588 */
3590#ifdef HAVE_REGEX_PCRE2
3591 xlat_ctx_t const *xctx,
3592#else
3593 UNUSED xlat_ctx_t const *xctx,
3594#endif
3595 request_t *request, fr_value_box_list_t *args)
3596{
3597 char const *p, *q, *end;
3598 char *vb_str;
3599
3600 char const *pattern, *rep;
3601 size_t pattern_len, rep_len;
3602
3603 fr_value_box_t *rep_vb, *vb;
3604 fr_value_box_t *subject_vb;
3605 fr_value_box_t *pattern_vb;
3606
3607 XLAT_ARGS(args, &subject_vb, &pattern_vb, &rep_vb);
3608
3609 /* coverity[dereference] */
3610 pattern = pattern_vb->vb_strvalue;
3611 if (*pattern == '/') {
3612#ifdef HAVE_REGEX_PCRE2
3613 switch (xlat_func_subst_regex(ctx, out, xctx, request, args)) {
3614 case 0:
3615 return XLAT_ACTION_DONE;
3616
3617 case 1:
3618 /* Not a regex, fall through */
3619 break;
3620
3621 case -1:
3622 return XLAT_ACTION_FAIL;
3623 }
3624#else
3625 if (memchr(pattern, '/', pattern_vb->vb_length - 1)) {
3626 REDEBUG("regex based substitutions require libpcre2. "
3627 "Check ${features.regex-pcre2} to determine support");
3628 }
3629 return XLAT_ACTION_FAIL;
3630#endif
3631 }
3632
3633 /*
3634 * Check for empty pattern
3635 */
3636 pattern_len = pattern_vb->vb_length;
3637 if (pattern_len == 0) {
3638 REDEBUG("Empty pattern");
3639 return XLAT_ACTION_FAIL;
3640 }
3641
3642 rep = rep_vb->vb_strvalue;
3643 rep_len = rep_vb->vb_length;
3644
3645 p = subject_vb->vb_strvalue;
3646 end = p + subject_vb->vb_length;
3647
3648 MEM(vb = fr_value_box_alloc_null(ctx));
3649 vb_str = talloc_bstrndup(vb, "", 0);
3650
3651 while (p < end) {
3652 q = memmem(p, end - p, pattern, pattern_len);
3653 if (!q) {
3654 MEM(vb_str = talloc_bstr_append(vb, vb_str, p, end - p));
3655 break;
3656 }
3657
3658 if (q > p) MEM(vb_str = talloc_bstr_append(vb, vb_str, p, q - p));
3659 if (rep_len) MEM(vb_str = talloc_bstr_append(vb, vb_str, rep, rep_len));
3660 p = q + pattern_len;
3661 }
3662
3663 if (fr_value_box_bstrdup_buffer_shallow(NULL, vb, NULL, vb_str, false) < 0) {
3664 RPEDEBUG("Failed creating output box");
3665 talloc_free(vb);
3666 return XLAT_ACTION_FAIL;
3667 }
3668
3669 fr_value_box_safety_copy(vb, subject_vb);
3670 fr_value_box_safety_merge(vb, rep_vb);
3671
3673
3674 return XLAT_ACTION_DONE;
3675}
3676
3677/*
3678 * Debug builds only, we don't want to allow unsanitised inputs to crash the server
3679 */
3680#ifndef NDEBUG
3682 { .single = true, .required = true, .type = FR_TYPE_STRING },
3684};
3685
3687 UNUSED xlat_ctx_t const *xctx, request_t *request,
3688 fr_value_box_list_t *args)
3689{
3690 static fr_table_num_sorted_t const signal_table[] = {
3691 { L("break"), SIGTRAP }, /* Save flailing at the keyboard */
3692 { L("BREAK"), SIGTRAP },
3693 { L("SIGABRT"), SIGABRT },
3694 { L("SIGALRM"), SIGALRM },
3695#ifdef SIGBUS
3696 { L("SIGBUS"), SIGBUS },
3697#endif
3698 { L("SIGCHLD"), SIGCHLD },
3699 { L("SIGCONT"), SIGCONT },
3700 { L("SIGFPE"), SIGFPE },
3701 { L("SIGHUP"), SIGHUP },
3702 { L("SIGILL"), SIGILL },
3703 { L("SIGINT"), SIGINT },
3704 { L("SIGKILL"), SIGKILL },
3705 { L("SIGPIPE"), SIGPIPE },
3706#ifdef SIGPOLL
3707 { L("SIGPOLL"), SIGPOLL },
3708#endif
3709 { L("SIGPROF"), SIGPROF },
3710 { L("SIGQUIT"), SIGQUIT },
3711 { L("SIGSEGV"), SIGSEGV },
3712 { L("SIGSTOP"), SIGSTOP },
3713#ifdef SIGSYS
3714 { L("SIGSYS"), SIGSYS },
3715#endif
3716 { L("SIGTERM"), SIGTERM },
3717#ifdef SIGTRAP
3718 { L("SIGTRAP"), SIGTRAP },
3719#endif
3720 { L("SIGTSTP"), SIGTSTP },
3721 { L("SIGTTIN"), SIGTTIN },
3722 { L("SIGTTOU"), SIGTTOU },
3723 { L("SIGURG"), SIGURG },
3724 { L("SIGUSR1"), SIGUSR1 },
3725 { L("SIGUSR2"), SIGUSR2 },
3726 { L("SIGVTALRM"), SIGVTALRM },
3727 { L("SIGXCPU"), SIGXCPU },
3728 { L("SIGXFSZ"), SIGXFSZ }
3729 };
3730 static size_t signal_table_len = NUM_ELEMENTS(signal_table);
3731
3732 fr_value_box_t *signal_vb;
3733 int signal;
3734
3735 XLAT_ARGS(args, &signal_vb);
3736
3737 signal = fr_table_value_by_substr(signal_table, signal_vb->vb_strvalue, signal_vb->vb_length, -1);
3738 if (signal < 0) {
3739 RERROR("Invalid signal \"%pV\"", signal_vb);
3740 return XLAT_ACTION_FAIL;
3741 }
3742 if (raise(signal) < 0) {
3743 RERROR("Failed raising signal %d: %s", signal, strerror(errno));
3744 return XLAT_ACTION_FAIL;
3745 }
3746 return XLAT_ACTION_DONE;
3747}
3748#endif
3749
3751 { .required = false, .single = true, .type = FR_TYPE_STRING },
3753};
3754
3755/** Return the time as a #FR_TYPE_DATE
3756 *
3757 * Note that all operations are UTC.
3758 *
3759@verbatim
3760%time()
3761@endverbatim
3762 *
3763 * Example:
3764@verbatim
3765update reply {
3766 &Reply-Message := "%{%time(now) - %time(request)}"
3767}
3768@endverbatim
3769 *
3770 * @ingroup xlat_functions
3771 */
3773 UNUSED xlat_ctx_t const *xctx,
3774 request_t *request, fr_value_box_list_t *args)
3775{
3776 fr_value_box_t *arg;
3777 fr_value_box_t *vb;
3779
3780 XLAT_ARGS(args, &arg);
3781
3782 if (!arg || (strcmp(arg->vb_strvalue, "now") == 0)) {
3784
3785 } else if (strcmp(arg->vb_strvalue, "request") == 0) {
3786 value = fr_time_to_unix_time(request->packet->timestamp);
3787
3788 } else if (strcmp(arg->vb_strvalue, "offset") == 0) {
3789 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
3790 vb->vb_time_delta = fr_time_gmtoff();
3791 goto append;
3792
3793 } else if (strcmp(arg->vb_strvalue, "dst") == 0) {
3794 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
3795 vb->vb_bool = fr_time_is_dst();
3796 goto append;
3797
3798 } else if (strcmp(arg->vb_strvalue, "mday_offset") == 0) {
3799 struct tm tm;
3800 fr_unix_time_t unix_time = fr_time_to_unix_time(request->packet->timestamp);
3801 time_t when = fr_unix_time_to_sec(unix_time);
3802 int64_t nsec;
3803
3804 gmtime_r(&when, &tm);
3805
3806 nsec = (int64_t) 86400 * (tm.tm_mday - 1);
3807 nsec += when % 86400;
3808 nsec *= NSEC;
3809 nsec += fr_unix_time_unwrap(unix_time) % NSEC;
3810
3811 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
3812 vb->vb_time_delta = fr_time_delta_wrap(nsec);
3813 goto append;
3814
3815 } else if (strcmp(arg->vb_strvalue, "wday_offset") == 0) {
3816 struct tm tm;
3817 fr_unix_time_t unix_time = fr_time_to_unix_time(request->packet->timestamp);
3818 time_t when = fr_unix_time_to_sec(unix_time);
3819 int64_t nsec;
3820
3821 gmtime_r(&when, &tm);
3822
3823 nsec = (int64_t) 86400 * tm.tm_wday;
3824 nsec += when % 86400;
3825 nsec *= NSEC;
3826 nsec += fr_unix_time_unwrap(unix_time) % NSEC;
3827
3828 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
3829 vb->vb_time_delta = fr_time_delta_wrap(nsec);
3830
3831 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
3832 vb->vb_time_delta = fr_time_delta_wrap(nsec);
3833 goto append;
3834
3835 } else if (fr_unix_time_from_str(&value, arg->vb_strvalue, FR_TIME_RES_SEC) < 0) {
3836 REDEBUG("Invalid time specification '%s'", arg->vb_strvalue);
3837 return XLAT_ACTION_FAIL;
3838 }
3839
3840 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_DATE, NULL));
3841 vb->vb_date = value;
3842
3843append:
3845
3846 return XLAT_ACTION_DONE;
3847}
3848
3849/** Return the current time as a #FR_TYPE_DATE
3850 *
3851 * Note that all operations are UTC.
3852 *
3853@verbatim
3854%time.now()
3855@endverbatim
3856 *
3857 * Example:
3858@verbatim
3859update reply {
3860 &Reply-Message := "%{%time.now() - %time.request()}"
3861}
3862@endverbatim
3863 *
3864 * @ingroup xlat_functions
3865 */
3867 UNUSED xlat_ctx_t const *xctx,
3868 UNUSED request_t *request, UNUSED fr_value_box_list_t *args)
3869{
3870 fr_value_box_t *vb;
3871
3872 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_DATE, NULL));
3873 vb->vb_date = fr_time_to_unix_time(fr_time());
3874
3876
3877 return XLAT_ACTION_DONE;
3878}
3879
3880/** Return the request receive time as a #FR_TYPE_DATE
3881 *
3882 * Note that all operations are UTC.
3883 *
3884@verbatim
3885%time.request()
3886@endverbatim
3887 *
3888 * Example:
3889@verbatim
3890update reply {
3891 &Reply-Message := "%{%time.now() - %time.request()}"
3892}
3893@endverbatim
3894 *
3895 * @ingroup xlat_functions
3896 */
3898 UNUSED xlat_ctx_t const *xctx,
3899 request_t *request, UNUSED fr_value_box_list_t *args)
3900{
3901 fr_value_box_t *vb;
3902
3903 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_DATE, NULL));
3904 vb->vb_date = fr_time_to_unix_time(request->packet->timestamp);
3905
3907
3908 return XLAT_ACTION_DONE;
3909}
3910
3911
3912/** Return the current time offset from gmt
3913 *
3914 * @ingroup xlat_functions
3915 */
3917 UNUSED xlat_ctx_t const *xctx,
3918 UNUSED request_t *request, UNUSED fr_value_box_list_t *args)
3919{
3920 fr_value_box_t *vb;
3921
3922 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
3923 vb->vb_time_delta = fr_time_gmtoff();
3924
3926
3927 return XLAT_ACTION_DONE;
3928}
3929
3930
3931/** Return whether we are in daylight savings or not
3932 *
3933 * @ingroup xlat_functions
3934 */
3936 UNUSED xlat_ctx_t const *xctx,
3937 UNUSED request_t *request, UNUSED fr_value_box_list_t *args)
3938{
3939 fr_value_box_t *vb;
3940
3941 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
3942 vb->vb_bool = fr_time_is_dst();
3943
3945
3946 return XLAT_ACTION_DONE;
3947}
3948
3949
3950/** Change case of a string
3951 *
3952 * If upper is true, change to uppercase, otherwise, change to lowercase
3953 */
3955 UNUSED request_t *request, fr_value_box_list_t *args, bool upper)
3956{
3957 char *p;
3958 char const *end;
3959 fr_value_box_t *vb;
3960
3961 XLAT_ARGS(args, &vb);
3962
3963 p = UNCONST(char *, vb->vb_strvalue);
3964 end = p + vb->vb_length;
3965
3966 while (p < end) {
3967 *(p) = upper ? toupper ((int) *(p)) : tolower((uint8_t) *(p));
3968 p++;
3969 }
3970
3971 fr_value_box_list_remove(args, vb); /* Can't leave it in both lists */
3973
3974 return XLAT_ACTION_DONE;
3975}
3976
3978 { .required = true, .concat = true, .type = FR_TYPE_STRING },
3980};
3981
3982
3983/** Convert a string to lowercase
3984 *
3985 * Example:
3986@verbatim
3987%tolower("Bar") == "bar"
3988@endverbatim
3989 *
3990 * Probably only works for ASCII
3991 *
3992 * @ingroup xlat_functions
3993 */
3995 UNUSED xlat_ctx_t const *xctx,
3996 request_t *request, fr_value_box_list_t *in)
3997{
3998 return xlat_change_case(ctx, out, request, in, false);
3999}
4000
4001
4002/** Convert a string to uppercase
4003 *
4004 * Example:
4005@verbatim
4006%toupper("Foo") == "FOO"
4007@endverbatim
4008 *
4009 * Probably only works for ASCII
4010 *
4011 * @ingroup xlat_functions
4012 */
4014 UNUSED xlat_ctx_t const *xctx,
4015 request_t *request, fr_value_box_list_t *in)
4016{
4017 return xlat_change_case(ctx, out, request, in, true);
4018}
4019
4020
4022 { .required = true, .concat = true, .type = FR_TYPE_STRING },
4024};
4025
4026/** URLencode special characters
4027 *
4028 * Example:
4029@verbatim
4030%urlquote("http://example.org/") == "http%3A%47%47example.org%47"
4031@endverbatim
4032 *
4033 * @ingroup xlat_functions
4034 */
4036 UNUSED xlat_ctx_t const *xctx,
4037 UNUSED request_t *request, fr_value_box_list_t *args)
4038{
4039 char const *p, *end;
4040 char *buff_p;
4041 size_t outlen = 0;
4042 fr_value_box_t *vb;
4043 fr_value_box_t *in_head;
4044
4045 XLAT_ARGS(args, &in_head);
4046
4047 p = in_head->vb_strvalue;
4048 end = p + in_head->vb_length;
4049
4050 /*
4051 * Calculate size of output
4052 */
4053 while (p < end) {
4054 if (isalnum(*p) ||
4055 *p == '-' ||
4056 *p == '_' ||
4057 *p == '.' ||
4058 *p == '~') {
4059 outlen++;
4060 } else {
4061 outlen += 3;
4062 }
4063 p++;
4064 }
4065
4066 MEM(vb = fr_value_box_alloc_null(ctx));
4067 MEM(fr_value_box_bstr_alloc(vb, &buff_p, vb, NULL, outlen, false) == 0);
4068 fr_value_box_safety_copy(vb, in_head);
4069
4070 /* Reset p to start position */
4071 p = in_head->vb_strvalue;
4072
4073 while (p < end) {
4074 if (isalnum(*p)) {
4075 *buff_p++ = *p++;
4076 continue;
4077 }
4078
4079 switch (*p) {
4080 case '-':
4081 case '_':
4082 case '.':
4083 case '~':
4084 *buff_p++ = *p++;
4085 break;
4086
4087 default:
4088 /* MUST be upper case hex to be compliant */
4089 snprintf(buff_p, 4, "%%%02X", (uint8_t) *p++); /* %XX */
4090
4091 buff_p += 3;
4092 }
4093 }
4094
4095 *buff_p = '\0';
4096
4097 // @todo - mark as safe for URL?
4099
4100 return XLAT_ACTION_DONE;
4101}
4102
4103
4105 { .required = true, .concat = true, .type = FR_TYPE_STRING },
4107};
4108
4109/** URLdecode special characters
4110 *
4111 * @note Remember to escape % with %% in strings, else xlat will try to parse it.
4112 *
4113 * Example:
4114@verbatim
4115%urlunquote("http%%3A%%47%%47example.org%%47") == "http://example.org/"
4116@endverbatim
4117 *
4118 * @ingroup xlat_functions
4119 */
4121 UNUSED xlat_ctx_t const *xctx,
4122 request_t *request, fr_value_box_list_t *args)
4123{
4124 char const *p, *end;
4125 char *buff_p;
4126 char *c1, *c2;
4127 size_t outlen = 0;
4128 fr_value_box_t *vb;
4129 fr_value_box_t *in_head;
4130
4131 XLAT_ARGS(args, &in_head);
4132
4133 p = in_head->vb_strvalue;
4134 end = p + in_head->vb_length;
4135
4136 /*
4137 * Calculate size of output
4138 */
4139 while (p < end) {
4140 if (*p == '%') {
4141 p += 3;
4142 } else {
4143 p++;
4144 }
4145 outlen++;
4146 }
4147
4148 MEM(vb = fr_value_box_alloc_null(ctx));
4149 MEM(fr_value_box_bstr_alloc(vb, &buff_p, vb, NULL, outlen, false) == 0);
4150 fr_value_box_safety_copy(vb, in_head);
4151
4152 /* Reset p to start position */
4153 p = in_head->vb_strvalue;
4154
4155 while (p < end) {
4156 if (*p != '%') {
4157 *buff_p++ = *p++;
4158 continue;
4159 }
4160 /* Is a % char */
4161
4162 /* Don't need \0 check, as it won't be in the hextab */
4163 if (!(c1 = memchr(hextab, tolower((uint8_t) *++p), 16)) ||
4164 !(c2 = memchr(hextab, tolower((uint8_t) *++p), 16))) {
4165 REMARKER(in_head->vb_strvalue, p - in_head->vb_strvalue, "Non-hex char in %% sequence");
4166 talloc_free(vb);
4167
4168 return XLAT_ACTION_FAIL;
4169 }
4170 p++;
4171 *buff_p++ = ((c1 - hextab) << 4) + (c2 - hextab);
4172 }
4173
4174 *buff_p = '\0';
4176
4177 return XLAT_ACTION_DONE;
4178}
4179
4181 { .required = true, .type = FR_TYPE_VOID },
4182 { .single = true, .type = FR_TYPE_ATTR },
4184};
4185
4186/** Decode any protocol attribute / options
4187 *
4188 * Creates protocol-specific attributes based on the given binary option data
4189 *
4190 * Example:
4191@verbatim
4192%dhcpv4.decode(%{Tmp-Octets-0})
4193@endverbatim
4194 *
4195 * @ingroup xlat_functions
4196 */
4198 xlat_ctx_t const *xctx,
4199 request_t *request, fr_value_box_list_t *in)
4200{
4201 int decoded;
4202 fr_value_box_t *vb, *in_head, *root_da;
4203 void *decode_ctx = NULL;
4204 xlat_pair_decode_uctx_t const *decode_uctx = talloc_get_type_abort(*(void * const *)xctx->inst, xlat_pair_decode_uctx_t);
4205 fr_test_point_pair_decode_t const *tp_decode = decode_uctx->tp_decode;
4206 fr_pair_t *vp = NULL;
4207 bool created = false;
4208
4209 XLAT_ARGS(in, &in_head, &root_da);
4210
4211 fr_assert(in_head->type == FR_TYPE_GROUP);
4212
4213 if (decode_uctx->dict && decode_uctx->dict != request->proto_dict) {
4214 REDEBUG2("Can't call %%%s() when in %s namespace", xctx->ex->call.func->name,
4215 fr_dict_root(request->proto_dict)->name);
4216 return XLAT_ACTION_FAIL;
4217 }
4218
4219 if (root_da) {
4220 int ret;
4221 if (!fr_type_is_structural(root_da->vb_attr->type)) {
4222 REDEBUG2("Decoding context must be a structural attribute reference");
4223 return XLAT_ACTION_FAIL;
4224 }
4225 ret = fr_pair_update_by_da_parent(fr_pair_list_parent(&request->request_pairs), &vp, root_da->vb_attr);
4226 if (ret < 0) {
4227 REDEBUG2("Failed creating decoding root pair");
4228 return XLAT_ACTION_FAIL;
4229 }
4230 if (ret == 0) created = true;
4231 }
4232
4233 if (tp_decode->test_ctx) {
4234 if (tp_decode->test_ctx(&decode_ctx, ctx, request->proto_dict, root_da ? root_da->vb_attr : NULL) < 0) {
4235 goto fail;
4236 }
4237 }
4238
4239 decoded = xlat_decode_value_box_list(root_da ? vp : request->request_ctx,
4240 root_da ? &vp->vp_group : &request->request_pairs,
4241 request, decode_ctx, tp_decode->func, &in_head->vb_group);
4242 if (decoded <= 0) {
4243 talloc_free(decode_ctx);
4244 RPERROR("Protocol decoding failed");
4245 fail:
4246 if (created) fr_pair_delete(&request->request_pairs, vp);
4247 return XLAT_ACTION_FAIL;
4248 }
4249
4250 /*
4251 * Create a value box to hold the decoded count, and add
4252 * it to the output list.
4253 */
4254 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_UINT32, NULL));
4255 vb->vb_uint32 = decoded;
4257
4258 talloc_free(decode_ctx);
4259 return XLAT_ACTION_DONE;
4260}
4261
4263 { .required = true, .single = true, .type = FR_TYPE_IPV4_PREFIX },
4265};
4266
4267/** Calculate the subnet mask from a IPv4 prefix
4268 *
4269 * Example:
4270@verbatim
4271%ip.v4.netmask(%{Network-Prefix})
4272@endverbatim
4273 *
4274 * @ingroup xlat_functions
4275 */
4277 UNUSED request_t *request, fr_value_box_list_t *args)
4278{
4279 fr_value_box_t *subnet, *vb;
4280 XLAT_ARGS(args, &subnet);
4281
4282 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_IPV4_ADDR, NULL));
4283 vb->vb_ip.addr.v4.s_addr = htonl((uint32_t)0xffffffff << (32 - subnet->vb_ip.prefix));
4285
4286 return XLAT_ACTION_DONE;
4287}
4288
4289/** Calculate the broadcast address from a IPv4 prefix
4290 *
4291 * Example:
4292@verbatim
4293%ip.v4.broadcast(%{Network-Prefix})
4294@endverbatim
4295 *
4296 * @ingroup xlat_functions
4297 */
4299 UNUSED request_t *request, fr_value_box_list_t *args)
4300{
4301 fr_value_box_t *subnet, *vb;
4302 XLAT_ARGS(args, &subnet);
4303
4304 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_IPV4_ADDR, NULL));
4305 vb->vb_ip.addr.v4.s_addr = htonl( ntohl(subnet->vb_ip.addr.v4.s_addr) | (uint32_t)0xffffffff >> subnet->vb_ip.prefix);
4307
4308 return XLAT_ACTION_DONE;
4309}
4310
4312{
4313 *(void **) mctx->inst = mctx->uctx;
4314 return 0;
4315}
4316
4322
4323/** Encode protocol attributes / options
4324 *
4325 * Returns octet string created from the provided pairs
4326 *
4327 * Example:
4328@verbatim
4329%dhcpv4.encode(&request[*])
4330@endverbatim
4331 *
4332 * @ingroup xlat_functions
4333 */
4335 xlat_ctx_t const *xctx,
4336 request_t *request, fr_value_box_list_t *args)
4337{
4338 fr_pair_t *vp;
4339 fr_dcursor_t *cursor;
4340 bool tainted = false, encode_children = false;
4341 fr_value_box_t *encoded;
4342
4343 fr_dbuff_t *dbuff;
4344 ssize_t len = 0;
4345 fr_value_box_t *in_head, *root_da;
4346 void *encode_ctx = NULL;
4347 fr_test_point_pair_encode_t const *tp_encode;
4348
4349 FR_DBUFF_TALLOC_THREAD_LOCAL(&dbuff, 2048, SIZE_MAX);
4350
4351 XLAT_ARGS(args, &in_head, &root_da);
4352
4353 memcpy(&tp_encode, xctx->inst, sizeof(tp_encode)); /* const issues */
4354
4355 cursor = fr_value_box_get_cursor(in_head);
4356
4357 /*
4358 * Create the encoding context.
4359 */
4360 if (tp_encode->test_ctx) {
4361 if (tp_encode->test_ctx(&encode_ctx, cursor, request->proto_dict, root_da ? root_da->vb_attr : NULL) < 0) {
4362 return XLAT_ACTION_FAIL;
4363 }
4364 }
4365
4366 if (root_da) {
4367 if (!fr_type_is_structural(root_da->vb_attr->type)) {
4368 REDEBUG2("Encoding context must be a structural attribute reference");
4369 return XLAT_ACTION_FAIL;
4370 }
4371 vp = fr_dcursor_current(cursor);
4372 if (!fr_dict_attr_common_parent(root_da->vb_attr, vp->da, true) && (root_da->vb_attr != vp->da)) {
4373 REDEBUG2("%s is not a child of %s", vp->da->name, root_da->vb_attr->name);
4374 return XLAT_ACTION_FAIL;
4375 }
4376 if (root_da->vb_attr == vp->da) encode_children = true;
4377 }
4378
4379 /*
4380 * Loop over the attributes, encoding them.
4381 */
4382 RDEBUG2("Encoding attributes");
4383
4384 if (RDEBUG_ENABLED2) {
4385 RINDENT();
4386 for (vp = fr_dcursor_current(cursor);
4387 vp != NULL;
4388 vp = fr_dcursor_next(cursor)) {
4389 RDEBUG2("%pP", vp);
4390 }
4391 REXDENT();
4392 }
4393
4394 /*
4395 * Encoders advance the cursor, so we just need to feed
4396 * in the next pair. This was originally so we could
4397 * extend the output buffer, but with dbuffs that's
4398 * no longer necessary... we might want to refactor this
4399 * in future.
4400 */
4401 for (vp = fr_dcursor_head(cursor);
4402 vp != NULL;
4403 vp = fr_dcursor_current(cursor)) {
4404 /*
4405 *
4406 * Don't check for internal attributes, the
4407 * encoders can skip them if they need to, and the
4408 * internal encoder can encode anything, as can
4409 * things like CBOR.
4410 *
4411 * Don't check the dictionaries. By definition,
4412 * vp->da->dict==request->proto_dict, OR else we're
4413 * using the internal encoder and encoding a real
4414 * protocol.
4415 *
4416 * However, we likely still want a
4417 * dictionary-specific "is encodable" function,
4418 * as AKA/SIM and DHCPv6 encode "bool"s only if
4419 * their value is true.
4420 */
4421 if (encode_children) {
4422 fr_dcursor_t child_cursor;
4423
4425
4426 /*
4427 * If we're given an encoding context which is the
4428 * same as the DA returned by the cursor, that means
4429 * encode the children.
4430 */
4431 fr_pair_dcursor_init(&child_cursor, &vp->vp_group);
4432 while (fr_dcursor_current(&child_cursor)) {
4433 len = tp_encode->func(dbuff, &child_cursor, encode_ctx);
4434 if (len < 0) break;
4435 }
4436 fr_dcursor_next(cursor);
4437 } else {
4438 len = tp_encode->func(dbuff, cursor, encode_ctx);
4439 }
4440 if (len < 0) {
4441 RPEDEBUG("Protocol encoding failed");
4442 return XLAT_ACTION_FAIL;
4443 }
4444
4445 tainted |= vp->vp_tainted;
4446 }
4447
4448 /*
4449 * Pass the options string back to the caller.
4450 */
4451 MEM(encoded = fr_value_box_alloc_null(ctx));
4452 fr_value_box_memdup(encoded, encoded, NULL, fr_dbuff_start(dbuff), fr_dbuff_used(dbuff), tainted);
4453 fr_dcursor_append(out, encoded);
4454
4455 return XLAT_ACTION_DONE;
4456}
4457
4458static int xlat_protocol_register_by_name(dl_t *dl, char const *name, fr_dict_t const *dict)
4459{
4460 fr_test_point_pair_decode_t *tp_decode;
4461 fr_test_point_pair_encode_t *tp_encode;
4462 xlat_pair_decode_uctx_t *decode_uctx;
4463 xlat_t *xlat;
4464 char buffer[256+32];
4465
4466 /*
4467 * See if there's a decode function for it.
4468 */
4469 snprintf(buffer, sizeof(buffer), "%s_tp_decode_pair", name);
4470 tp_decode = dlsym(dl->handle, buffer);
4471 if (tp_decode) {
4472 snprintf(buffer, sizeof(buffer), "%s.decode", name);
4473
4474 /* May be called multiple times, so just skip protocols we've already registered */
4475 if (xlat_func_find(buffer, -1)) return 1;
4476
4477 if (unlikely((xlat = xlat_func_register(NULL, buffer, xlat_pair_decode, FR_TYPE_UINT32)) == NULL)) return -1;
4479 decode_uctx = talloc(xlat, xlat_pair_decode_uctx_t);
4480 decode_uctx->tp_decode = tp_decode;
4481 decode_uctx->dict = dict;
4482 /* coverity[suspicious_sizeof] */
4485 }
4486
4487 /*
4488 * See if there's an encode function for it.
4489 */
4490 snprintf(buffer, sizeof(buffer), "%s_tp_encode_pair", name);
4491 tp_encode = dlsym(dl->handle, buffer);
4492 if (tp_encode) {
4493 snprintf(buffer, sizeof(buffer), "%s.encode", name);
4494
4495 if (xlat_func_find(buffer, -1)) return 1;
4496
4497 if (unlikely((xlat = xlat_func_register(NULL, buffer, xlat_pair_encode, FR_TYPE_OCTETS)) == NULL)) return -1;
4499 /* coverity[suspicious_sizeof] */
4502 }
4503
4504 return 0;
4505}
4506
4507static int xlat_protocol_register(fr_dict_t const *dict)
4508{
4509 dl_t *dl = fr_dict_dl(dict);
4510 char *p, name[256];
4511
4512 /*
4513 * No library for this protocol, skip it.
4514 *
4515 * Protocol TEST has no libfreeradius-test, so that's OK.
4516 */
4517 if (!dl) return 0;
4518
4519 strlcpy(name, fr_dict_root(dict)->name, sizeof(name));
4520 for (p = name; *p != '\0'; p++) {
4521 *p = tolower((uint8_t) *p);
4522 }
4523
4524 return xlat_protocol_register_by_name(dl, name, dict != fr_dict_internal() ? dict : NULL);
4525}
4526
4528
4530{
4531 dl_t *dl;
4532
4533 cbor_loader = dl_loader_init(NULL, NULL, false, false);
4534 if (!cbor_loader) return 0;
4535
4536 dl = dl_by_name(cbor_loader, "libfreeradius-cbor", NULL, false);
4537 if (!dl) return 0;
4538
4539 if (xlat_protocol_register_by_name(dl, "cbor", NULL) < 0) return -1;
4540
4541 return 0;
4542}
4543
4544
4545/** Register xlats for any loaded dictionaries
4546 */
4548{
4549 fr_dict_t *dict;
4551
4552 for (dict = fr_dict_global_ctx_iter_init(&iter);
4553 dict != NULL;
4554 dict = fr_dict_global_ctx_iter_next(&iter)) {
4555 if (xlat_protocol_register(dict) < 0) return -1;
4556 }
4557
4558 /*
4559 * And the internal protocol, too.
4560 */
4561 if (xlat_protocol_register(fr_dict_internal()) < 0) return -1;
4562
4563 /*
4564 * And cbor stuff
4565 */
4566 if (xlat_protocol_register_cbor() < 0) return -1;
4567
4568 return 0;
4569}
4570
4571/** De-register all xlat functions we created
4572 *
4573 */
4574static int _xlat_global_free(UNUSED void *uctx)
4575{
4576 TALLOC_FREE(xlat_ctx);
4580
4581 return 0;
4582}
4583
4584/** Global initialisation for xlat
4585 *
4586 * @note Free memory with #xlat_free
4587 *
4588 * @return
4589 * - 0 on success.
4590 * - -1 on failure.
4591 *
4592 * @hidecallgraph
4593 */
4594static int _xlat_global_init(UNUSED void *uctx)
4595{
4596 xlat_t *xlat;
4597
4598 xlat_ctx = talloc_init("xlat");
4599 if (!xlat_ctx) return -1;
4600
4601 if (xlat_func_init() < 0) return -1;
4602
4603 /*
4604 * Lookup attributes used by virtual xlat expansions.
4605 */
4606 if (xlat_eval_init() < 0) return -1;
4607
4608 /*
4609 * Registers async xlat operations in the `unlang` interpreter.
4610 */
4612
4613 /*
4614 * These are all "pure" functions.
4615 */
4616#define XLAT_REGISTER_ARGS(_xlat, _func, _return_type, _args) \
4617do { \
4618 if (unlikely((xlat = xlat_func_register(xlat_ctx, _xlat, _func, _return_type)) == NULL)) return -1; \
4619 xlat_func_args_set(xlat, _args); \
4620 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
4621} while (0)
4622
4623#define XLAT_NEW(_x) xlat->replaced_with = _x
4624
4626
4629 XLAT_NEW("str.concat");
4630
4633 XLAT_NEW("str.split");
4634
4636
4639 XLAT_NEW("hmac.md5");
4640
4643 XLAT_NEW("hmac.sha1");
4644
4646 xlat->deprecated = true;
4647
4650 xlat->deprecated = true;
4651
4653
4656 XLAT_NEW("str.lpad");
4657
4660 XLAT_NEW("str.rpad");
4661
4664 XLAT_NEW("str.substr");
4665
4668
4669 /*
4670 * The inputs to these functions are variable.
4671 */
4672#undef XLAT_REGISTER_ARGS
4673#define XLAT_REGISTER_ARGS(_xlat, _func, _return_type, _args) \
4674do { \
4675 if (unlikely((xlat = xlat_func_register(xlat_ctx, _xlat, _func, _return_type)) == NULL)) return -1; \
4676 xlat_func_args_set(xlat, _args); \
4677 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_INTERNAL); \
4678} while (0)
4679
4680#undef XLAT_REGISTER_VOID
4681#define XLAT_REGISTER_VOID(_xlat, _func, _return_type) \
4682do { \
4683 if (unlikely((xlat = xlat_func_register(xlat_ctx, _xlat, _func, _return_type)) == NULL)) return -1; \
4684 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_INTERNAL); \
4685} while (0)
4686
4689 XLAT_NEW("pairs.debug");
4690
4698
4700 XLAT_NEW("pairs.immutable");
4702
4708
4710 XLAT_NEW("time.next");
4712
4714 XLAT_NEW("pairs.print");
4716
4718
4720#ifdef HAVE_REGEX_PCRE2
4721 xlat_func_instantiate_set(xlat, xlat_instantiate_subst_regex, xlat_subst_regex_inst_t, NULL, NULL);
4722#endif
4724 XLAT_NEW("str.subst");
4725#ifdef HAVE_REGEX_PCRE2
4726 xlat_func_instantiate_set(xlat, xlat_instantiate_subst_regex, xlat_subst_regex_inst_t, NULL, NULL);
4727#endif
4728
4729#ifndef NDEBUG
4731#endif
4732
4738
4742
4745 XLAT_NEW("str.rand");
4746
4749
4751
4752 if (unlikely((xlat = xlat_func_register(xlat_ctx, "untaint", xlat_func_untaint, FR_TYPE_VOID)) == NULL)) return -1;
4755
4756 if (unlikely((xlat = xlat_func_register(xlat_ctx, "taint", xlat_func_taint, FR_TYPE_VOID)) == NULL)) return -1;
4759
4760 /*
4761 * All of these functions are pure.
4762 */
4763#define XLAT_REGISTER_PURE(_xlat, _func, _return_type, _arg) \
4764do { \
4765 if (unlikely((xlat = xlat_func_register(xlat_ctx, _xlat, _func, _return_type)) == NULL)) return -1; \
4766 xlat_func_args_set(xlat, _arg); \
4767 xlat_func_flags_set(xlat, XLAT_FUNC_FLAG_PURE | XLAT_FUNC_FLAG_INTERNAL); \
4768} while (0)
4769
4775 XLAT_NEW("hash.md4");
4776
4779 XLAT_NEW("hash.md4");
4780
4781 if (unlikely((xlat = xlat_func_register(xlat_ctx, "regex.match", xlat_func_regex, FR_TYPE_STRING)) == NULL)) return -1;
4784 if (unlikely((xlat = xlat_func_register(xlat_ctx, "regex", xlat_func_regex, FR_TYPE_STRING)) == NULL)) return -1;
4787 XLAT_NEW("regex.match");
4788
4789 {
4790 static xlat_arg_parser_t const xlat_regex_safe_args[] = {
4791 { .type = FR_TYPE_STRING, .variadic = true, .concat = true },
4793 };
4794
4795 static xlat_arg_parser_t const xlat_regex_escape_args[] = {
4796 { .type = FR_TYPE_STRING,
4797 .func = regex_xlat_escape, .safe_for = FR_REGEX_SAFE_FOR, .always_escape = true,
4798 .variadic = true, .concat = true },
4800 };
4801
4802 if (unlikely((xlat = xlat_func_register(xlat_ctx, "regex.safe",
4803 xlat_transparent, FR_TYPE_STRING)) == NULL)) return -1;
4805 xlat_func_args_set(xlat, xlat_regex_safe_args);
4806 xlat_func_safe_for_set(xlat, FR_REGEX_SAFE_FOR);
4807
4808 if (unlikely((xlat = xlat_func_register(xlat_ctx, "regex.escape",
4809 xlat_transparent, FR_TYPE_STRING)) == NULL)) return -1;
4811 xlat_func_args_set(xlat, xlat_regex_escape_args);
4812 xlat_func_safe_for_set(xlat, FR_REGEX_SAFE_FOR);
4813 }
4814
4815#define XLAT_REGISTER_HASH(_name, _func) do { \
4816 XLAT_REGISTER_PURE("hash." _name, _func, FR_TYPE_OCTETS, xlat_func_sha_arg); \
4817 XLAT_REGISTER_PURE(_name, _func, FR_TYPE_OCTETS, xlat_func_sha_arg); \
4818 XLAT_NEW("hash." _name); \
4819 } while (0)
4820
4822
4823#ifdef HAVE_OPENSSL_EVP_H
4824 XLAT_REGISTER_HASH("sha2_224", xlat_func_sha2_224);
4825 XLAT_REGISTER_HASH("sha2_256", xlat_func_sha2_256);
4826 XLAT_REGISTER_HASH("sha2_384", xlat_func_sha2_384);
4827 XLAT_REGISTER_HASH("sha2_512", xlat_func_sha2_512);
4828 XLAT_REGISTER_HASH("sha2", xlat_func_sha2_256);
4829
4830# ifdef HAVE_EVP_BLAKE2S256
4831 XLAT_REGISTER_HASH("blake2s_256", xlat_func_blake2s_256);
4832# endif
4833# ifdef HAVE_EVP_BLAKE2B512
4834 XLAT_REGISTER_HASH("blake2b_512", xlat_func_blake2b_512);
4835# endif
4836
4837 XLAT_REGISTER_HASH("sha3_224", xlat_func_sha3_224);
4838 XLAT_REGISTER_HASH("sha3_256", xlat_func_sha3_256);
4839 XLAT_REGISTER_HASH("sha3_384", xlat_func_sha3_384);
4840 XLAT_REGISTER_HASH("sha3_512", xlat_func_sha3_512);
4841 XLAT_REGISTER_HASH("sha3", xlat_func_sha3_256);
4842#endif
4843
4845 xlat->deprecated = true;
4847 XLAT_NEW("length");
4848
4851
4854 XLAT_NEW("str.lower");
4855
4858 XLAT_NEW("str.upper");
4859
4862 XLAT_NEW("url.quote");
4863
4866 XLAT_NEW("url.unquote");
4867
4869
4871}
4872
4874{
4875 int ret;
4876 fr_atexit_global_once_ret(&ret, _xlat_global_init, _xlat_global_free, NULL);
4877 return ret;
4878}
static int const char char buffer[256]
Definition acutest.h:578
int const char * file
Definition acutest.h:704
va_list args
Definition acutest.h:772
static int const char * fmt
Definition acutest.h:575
#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_encode(_out, _in, _add_padding)
Definition base64.h:74
#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
static dl_t * dl
Definition fuzzer.c:42
static bool stop
Definition radmin.c:70
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h:769
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:900
#define FR_DBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Create a function local and thread local extensible dbuff.
Definition dbuff.h:558
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:516
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:290
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:408
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:339
static void * fr_dcursor_head(fr_dcursor_t *cursor)
Rewind cursor to the start of the list.
Definition dcursor.h:234
#define MEM(x)
Definition debug.h:36
fr_dict_t * fr_dict_global_ctx_iter_next(fr_dict_global_ctx_iter_t *iter)
Definition dict_util.c:4879
char const * name
Vendor name.
Definition dict.h:275
fr_dict_attr_t const * fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
Find a common ancestor that two TLV type attributes share.
Definition dict_util.c:2306
static fr_slen_t err
Definition dict.h:870
fr_dict_t * fr_dict_global_ctx_iter_init(fr_dict_global_ctx_iter_t *iter)
Iterate protocols by name.
Definition dict_util.c:4872
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2662
dl_t * fr_dict_dl(fr_dict_t const *dict)
Definition dict_util.c:2672
uint32_t pen
Private enterprise number.
Definition dict.h:271
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4915
static fr_slen_t in
Definition dict.h:870
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:2897
Private enterprise.
Definition dict.h:270
Test enumeration values.
Definition dict_test.h:92
dl_loader_t * dl_loader_init(TALLOC_CTX *ctx, void *uctx, bool uctx_free, bool defer_symbol_init)
Initialise structures needed by the dynamic linker.
Definition dl.c:885
dl_t * dl_by_name(dl_loader_t *dl_loader, char const *name, void *uctx, bool uctx_free)
Search for a dl's shared object in various locations.
Definition dl.c:470
A dynamic loader.
Definition dl.c:81
void * handle
Handle returned by dlopen.
Definition dl.h:62
Module handle.
Definition dl.h:58
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 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_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition dlist.h:555
void fr_bio_shutdown & my
Definition fd_errno.h:70
static xlat_action_t xlat_func_time_now(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *args)
Return the current time as a FR_TYPE_DATE.
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_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_pairs_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)
Print out attribute info.
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_pair_decode(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_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 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.
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.
static xlat_action_t xlat_func_pairs_print(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_time_request(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *args)
Return the request receive time as a FR_TYPE_DATE.
static xlat_action_t xlat_func_regex(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Get named subcapture value from previous regex.
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.
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_pair_encode(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.
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_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED 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_time_is_dst(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *args)
Return whether we are in daylight savings or not.
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.
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_uuid_v7(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *args)
Generate a version 7 UUID.
static xlat_action_t xlat_func_uuid_v4(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *args)
Generate a version 4 UUID.
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_subnet_netmask(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 subnet mask from a IPv4 prefix.
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_str_printable(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *args)
Return whether a string has only printable chars.
static xlat_action_t xlat_func_range(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Generate a range of uint64 numbers.
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_subnet_broadcast(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 broadcast address from a IPv4 prefix.
static xlat_action_t xlat_func_str_utf8(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, fr_value_box_list_t *args)
Return whether a string is valid UTF-8.
static xlat_action_t xlat_func_time_offset(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *args)
Return the current time offset from gmt.
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.
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
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:1658
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:2010
#define UNLANG_SUB_FRAME
Definition interpret.h:37
fr_log_t * log_dst_by_name(char const *name)
Get a logging destination by name.
Definition log.c:1088
#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 RERROR(fmt,...)
Definition log.h:298
#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:1592
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:1872
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:1427
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:515
#define MD4_DIGEST_LENGTH
Definition md4.h:25
#define MD5_DIGEST_LENGTH
unsigned short uint16_t
fr_type_t
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_FLOAT32
Single precision floating point.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_VOID
User data.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_IFID
Interface ID.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
@ FR_TYPE_FLOAT64
Double precision floating point.
unsigned int uint32_t
long int ssize_t
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.
unsigned char uint8_t
ssize_t fr_slen_t
long long int off_t
unsigned long int size_t
fr_sbuff_parse_error_t
size_t fr_snprint_uint128(char *out, size_t outlen, uint128_t const num)
Write 128bit unsigned integer to buffer.
Definition misc.c:370
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
fr_pair_t * fr_pair_list_parent(fr_pair_list_t const *list)
Return a pointer to the parent pair which contains this list.
Definition pair.c:958
int fr_pair_update_by_da_parent(fr_pair_t *parent, fr_pair_t **out, fr_dict_attr_t const *da)
Return the first fr_pair_t matching the fr_dict_attr_t or alloc a new fr_pair_t and its subtree (and ...
Definition pair.c:1589
int fr_pair_delete(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list and free.
Definition pair.c:1819
fr_slen_t fr_utf8_str(uint8_t const *str, ssize_t inlen)
Validate a complete UTF8 string.
Definition print.c:153
size_t fr_utf8_char(uint8_t const *str, ssize_t inlen)
Checks for utf-8, taken from http://www.w3.org/International/questions/qa-forms-utf-8.
Definition print.c:39
static fr_internal_encode_ctx_t encode_ctx
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:81
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG_ENABLED2()
Definition radclient.h:50
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define RDEBUG(fmt,...)
Definition radclient.h:53
#define fill(_expr)
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:105
fr_dict_attr_t const * request_attr_request
Definition request.c:43
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:92
#define RAD_REQUEST_LVL_NONE
No debug messages should be printed.
Definition request.h:312
static char const * name
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:2020
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:1984
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:1483
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:2116
#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:203
#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_TALLOC_THREAD_LOCAL(_out, _init, _max)
Set of parsing rules for *unescape_until functions.
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
Definition tmpl.h:636
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
Definition tmpl.h:906
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
Definition tmpl.h:142
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
Definition tmpl.h:146
@ TMPL_TYPE_EXEC
Callout to an external script or program.
Definition tmpl.h:150
@ TMPL_TYPE_REGEX_XLAT_UNRESOLVED
A regular expression with unresolved xlat functions or attribute references.
Definition tmpl.h:197
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition tmpl.h:138
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
Definition tmpl.h:179
static fr_slen_t vpt
Definition tmpl.h:1271
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:337
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:917
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:334
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
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
PRIVATE void strings()
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:273
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:653
#define fr_table_value_by_substr(_table, _name, _name_len, _def)
Convert a partial string to a value using an ordered or sorted table.
Definition table.h:693
An element in an arbitrarily ordered array of name to num mappings.
Definition table.h:57
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:586
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:614
#define talloc_get_type_abort_const
Definition talloc.h:244
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition test_point.h:86
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition test_point.h:94
fr_pair_decode_t func
Decoder for pairs.
Definition test_point.h:87
fr_pair_encode_t func
Encoder for pairs.
Definition test_point.h:95
Entry point for pair decoders.
Definition test_point.h:85
Entry point for pair encoders.
Definition test_point.h:93
bool fr_time_is_dst(void)
Whether or not we're daylight savings.
Definition time.c:1207
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:794
fr_time_delta_t fr_time_gmtoff(void)
Get the offset to gmt.
Definition time.c:1199
static int64_t fr_time_to_msec(fr_time_t when)
Convert an fr_time_t (internal time) to number of msec since the unix epoch (wallclock time)
Definition time.h:711
static int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
Definition time.h:506
#define fr_time_delta_wrap(_time)
Definition time.h:152
@ FR_TIME_RES_SEC
Definition time.h:50
#define NSEC
Definition time.h:379
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:688
"Unix" time.
Definition time.h:95
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:544
int unlang_xlat_push(TALLOC_CTX *ctx, unlang_result_t *p_result, 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:270
void unlang_xlat_init(void)
Register xlat operation with the interpreter.
Definition xlat.c:806
fr_type_t type
Type to cast argument to.
Definition xlat.h:155
uint8_t single
Argument must only contain a single box.
Definition xlat.h:148
bool xlat_is_literal(xlat_exp_head_t const *head)
Check to see if the expansion consists entirely of value-box elements.
#define XLAT_ARG_PARSER_CURSOR
Definition xlat.h:162
@ XLAT_ARG_VARIADIC_EMPTY_KEEP
Empty argument groups are left alone, and either passed through as empty groups or null boxes.
Definition xlat.h:137
@ XLAT_ARG_VARIADIC_EMPTY_SQUASH
Empty argument groups are removed.
Definition xlat.h:136
xlat_arg_parser_variadic_t variadic
All additional boxes should be processed using this definition.
Definition xlat.h:153
#define XLAT_RESULT_SUCCESS(_p_result)
Definition xlat.h:503
uint8_t required
Argument must be present, and non-empty.
Definition xlat.h:146
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition xlat.h:383
uint8_t concat
Concat boxes together.
Definition xlat.h:147
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:170
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_YIELD
An xlat function pushed a resume frame onto the stack.
Definition xlat.h:42
@ XLAT_ACTION_PUSH_UNLANG
An xlat function pushed an unlang frame onto the unlang stack.
Definition xlat.h:39
fr_slen_t xlat_tokenize_expression(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))
Definition xlat_expr.c:3145
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:69
static void fr_pair_set_immutable(fr_pair_t *vp)
Definition pair.h:684
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition pair.h:589
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:576
#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:87
#define fr_type_is_structural(_x)
Definition types.h:393
@ FR_TYPE_ATTR
A contains an attribute reference.
Definition types.h:84
#define FR_TYPE_NON_LEAF
Definition types.h:319
#define fr_type_is_string(_x)
Definition types.h:349
#define fr_type_is_numeric(_x)
Definition types.h:383
#define FR_TYPE_STRUCTURAL
Definition types.h:317
#define fr_type_is_null(_x)
Definition types.h:348
#define fr_type_is_leaf(_x)
Definition types.h:394
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
#define FR_TYPE_LEAF
Definition types.h:318
#define FR_TYPE_NUMERIC
Definition types.h:307
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:1430
void fr_value_box_mark_unsafe(fr_value_box_t *vb)
Mark a value-box as "unsafe".
Definition value.c:6868
ssize_t fr_value_box_list_concat_as_string(fr_value_box_t *safety, 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, fr_value_box_safe_for_t safe_for, bool flatten)
Concatenate a list of value boxes together.
Definition value.c:6084
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:5817
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:4759
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:3730
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:6569
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:4792
void fr_value_box_list_untaint(fr_value_box_list_t *head)
Untaint every list member (and their children)
Definition value.c:6766
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:3976
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:4111
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:4394
void fr_value_box_safety_copy_changed(fr_value_box_t *out, fr_value_box_t const *in)
Copy the safety values from one box to another.
Definition value.c:6911
void fr_value_box_safety_merge(fr_value_box_t *out, fr_value_box_t const *in)
Merge safety results.
Definition value.c:6920
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:4503
void fr_value_box_safety_copy(fr_value_box_t *out, fr_value_box_t const *in)
Copy the safety values from one box to another.
Definition value.c:6898
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:4538
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:4157
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:6735
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:4571
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:4615
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:4720
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:4856
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:6300
@ FR_VALUE_BOX_LIST_FREE
Definition value.h:239
@ FR_VALUE_BOX_LIST_FREE_BOX
Free each processed box.
Definition value.h:236
#define fr_value_box_list_foreach_safe(_list_head, _iter)
Definition value.h:225
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:643
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition value.h:1077
static fr_slen_t data
Definition value.h:1322
#define fr_value_box_is_safe_for(_box, _safe_for)
Definition value.h:1084
#define fr_box_is_variable_size(_x)
Definition value.h:463
#define fr_value_box_get_cursor(_dst)
Definition value.h:1245
#define VALUE_BOX_VERIFY(_x)
Definition value.h:1352
#define VALUE_BOX_LIST_VERIFY(_x)
Definition value.h:1353
int nonnull(2, 5))
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:654
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:224
static size_t char ** out
Definition value.h:1023
#define fr_box_bool(_val)
Definition value.h:330
#define FR_VALUE_BOX_SAFE_FOR_ANY
Definition value.h:173
static xlat_arg_parser_t const xlat_func_bin_arg[]
static int xlat_protocol_register_cbor(void)
static xlat_arg_parser_t const xlat_func_map_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 *args)
#define XLAT_REGISTER_VOID(_xlat, _func, _return_type)
static xlat_arg_parser_t const xlat_func_log_dst_args[]
static xlat_arg_parser_t const xlat_func_taint_args[]
static xlat_arg_parser_t const xlat_func_time_args[]
static xlat_arg_parser_t const xlat_func_base64_encode_arg[]
unlang_result_t last_result
static int _log_dst_free(fr_log_t *log)
static xlat_arg_parser_t const xlat_pair_encode_args[]
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)
static xlat_arg_parser_t const xlat_func_signal_raise_args[]
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[]
static int xlat_pair_dencode_instantiate(xlat_inst_ctx_t const *mctx)
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 from input list to output list.
static xlat_arg_parser_t const xlat_func_hex_arg[]
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)
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 *args)
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_subnet_args[]
#define XLAT_REGISTER_PURE(_xlat, _func, _return_type, _arg)
static xlat_arg_parser_t const xlat_func_str_printable_arg[]
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[]
int xlat_protocols_register(void)
Register xlats for any loaded dictionaries.
static xlat_arg_parser_t const xlat_func_str_utf8_arg[]
#define REPETITION_MAX
void xlat_debug_attr_list(request_t *request, fr_pair_list_t const *list)
static const fr_sbuff_escape_rules_t xlat_filename_escape_dots
static dl_loader_t * cbor_loader
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[]
int xlat_global_init(void)
static xlat_arg_parser_t const xlat_func_urlquote_arg[]
static xlat_arg_parser_t const xlat_pair_cursor_args[]
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 *args)
static void ungroup(fr_dcursor_t *out, fr_value_box_list_t *in)
static xlat_arg_parser_t const xlat_func_md4_arg[]
static int regex_xlat_escape(UNUSED request_t *request, fr_value_box_t *vb, UNUSED void *uctx)
static xlat_arg_parser_t const xlat_func_join_args[]
#define XLAT_NEW(_x)
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)
#define XLAT_REGISTER_HASH(_name, _func)
static xlat_arg_parser_t const xlat_func_debug_args[]
static char const hextab[]
#define FR_FILENAME_SAFE_FOR
static xlat_action_t xlat_func_signal_raise(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
fr_test_point_pair_decode_t * tp_decode
static xlat_arg_parser_t const xlat_func_pad_args[]
static int uuid_print_vb(fr_value_box_t *vb, uint32_t vals[4])
Convert a UUID in an array of uint32_t to the conventional string representation.
static xlat_arg_parser_t const xlat_func_urlunquote_arg[]
static xlat_action_t xlat_func_file_touch(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
fr_dict_t const * dict
Restrict xlat to this namespace.
void xlat_debug_attr_vp(request_t *request, fr_pair_t *vp, tmpl_t const *vpt)
static xlat_arg_parser_t const xlat_pair_decode_args[]
static xlat_arg_parser_t const xlat_func_rand_arg[]
static void uuid_set_variant(uint32_t vals[4], uint8_t variant)
static int filename_xlat_escape(UNUSED request_t *request, fr_value_box_t *vb, UNUSED void *uctx)
static xlat_arg_parser_t const xlat_func_concat_args[]
static xlat_arg_parser_t const xlat_func_file_name_count_args[]
static xlat_arg_parser_t const xlat_func_range_arg[]
static xlat_arg_parser_t const xlat_func_integer_args[]
static int _xlat_global_init(UNUSED void *uctx)
Global initialisation for xlat.
#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)
static xlat_action_t xlat_func_file_cat(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
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 *args)
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 xlat_protocol_register_by_name(dl_t *dl, char const *name, fr_dict_t const *dict)
static xlat_arg_parser_t const xlat_func_file_cat_args[]
static void uuid_set_version(uint32_t vals[4], uint8_t version)
#define UUID_CHARS(_v, _num)
return XLAT_ACTION_DONE
static xlat_arg_parser_t const xlat_func_file_name_args[]
static TALLOC_CTX * xlat_ctx
static xlat_arg_parser_t const xlat_func_next_time_args[]
static int _xlat_global_free(UNUSED void *uctx)
De-register all xlat functions we created.
static const fr_sbuff_escape_rules_t xlat_filename_escape
static xlat_arg_parser_t const xlat_func_base64_decode_arg[]
static xlat_arg_parser_t const xlat_hmac_args[]
static xlat_arg_parser_t const xlat_func_regex_args[]
void * rctx
Resume context.
Definition xlat_ctx.h:54
xlat_exp_t const * ex
Tokenized expression.
Definition xlat_ctx.h:55
xlat_exp_t * ex
Tokenized expression to use in expansion.
Definition xlat_ctx.h:64
void const * inst
xlat instance data.
Definition xlat_ctx.h:50
void * uctx
Passed to the registration function.
Definition xlat_ctx.h:66
void * inst
xlat instance data to populate.
Definition xlat_ctx.h:63
An xlat calling ctx.
Definition xlat_ctx.h:49
An xlat instantiation ctx.
Definition xlat_ctx.h:62
fr_dict_attr_t const * xlat_time_res_attr(char const *res)
Definition xlat_eval.c:129
int xlat_eval_init(void)
Definition xlat_eval.c:1996
void xlat_eval_free(void)
Definition xlat_eval.c:2021
int xlat_register_expressions(void)
Definition xlat_expr.c:1858
void xlat_func_free(void)
Definition xlat_func.c:563
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:399
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:363
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:216
int xlat_func_init(void)
Definition xlat_func.c:547
xlat_t * xlat_func_find(char const *in, ssize_t inlen)
Definition xlat_func.c:77
#define xlat_func_instantiate_set(_xlat, _instantiate, _inst_struct, _detach, _uctx)
Set a callback for global instantiation of xlat functions.
Definition xlat_func.h:93
#define xlat_func_safe_for_set(_xlat, _escaped)
Set the escaped values for output boxes.
Definition xlat_func.h:82
@ 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:116
bool deprecated
this function was deprecated
Definition xlat_priv.h:68
xlat_type_t _CONST type
type of this expansion.
Definition xlat_priv.h:155
An xlat expansion node.
Definition xlat_priv.h:148