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