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