The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
tmpl_eval.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: f22adf425b831f0eb785936f0eb882db34a8d127 $
19 *
20 * @brief #fr_pair_t template functions
21 * @file src/lib/server/tmpl_eval.c
22 *
23 * @ingroup AVP
24 *
25 * @copyright 2014-2020 The FreeRADIUS server project
26 */
27RCSID("$Id: f22adf425b831f0eb785936f0eb882db34a8d127 $")
28
29#define _TMPL_PRIVATE 1
30
31#include <freeradius-devel/server/exec.h>
32#include <freeradius-devel/server/exec_legacy.h>
33#include <freeradius-devel/server/tmpl.h>
34#include <freeradius-devel/server/tmpl_dcursor.h>
35#include <freeradius-devel/server/client.h>
36#include <freeradius-devel/unlang/call.h>
37
38#include <freeradius-devel/util/atexit.h>
39#include <freeradius-devel/util/edit.h>
40
41
43static fr_dict_t const *dict_radius;
44
47 { .out = &dict_freeradius, .proto = "freeradius" },
48 { .out = &dict_radius, .proto = "radius" }, /* @todo - remove RADIUS from the server core... */
50};
51
52/** Placeholder attribute for uses of unspecified attribute references
53 */
56
57
58/** Resolve attribute #fr_pair_list_t value to an attribute list.
59 *
60 * The value returned is a pointer to the pointer of the HEAD of a #fr_pair_t list in the
61 * #request_t. If the head of the list changes, the pointer will still be valid.
62 *
63 * @param[in] request containing the target lists.
64 * @param[in] list #fr_pair_list_t value to resolve to #fr_pair_t list. Will be NULL if list
65 * name couldn't be resolved.
66 * @return a pointer to the HEAD of a list in the #request_t.
67 *
68 * @see tmpl_dcursor_init
69 */
71{
72 if (!request) return NULL;
73
74 if (list == request_attr_request) {
75 if (!request->packet) return NULL;
76 return &request->request_pairs;
77 }
78
79 if (list == request_attr_reply) {
80 if (!request->reply) return NULL;
81 return &request->reply_pairs;
82 }
83
84 if (list == request_attr_control) return &request->control_pairs;
85
86 if (list == request_attr_state) return &request->session_state_pairs;
87
88 if (list == request_attr_local) return &request->local_pairs;
89
90 RWDEBUG2("List \"%s\" is not available", tmpl_list_name(list, "<INVALID>"));
91
92 return NULL;
93}
94
95/** Return the correct TALLOC_CTX to alloc #fr_pair_t in, for a list
96 *
97 * Allocating new #fr_pair_t in the context of a #request_t is usually wrong.
98 * #fr_pair_t should be allocated in the context of a #fr_packet_t, so that if the
99 * #fr_packet_t is freed before the #request_t, the associated #fr_pair_t lists are
100 * freed too.
101 *
102 * @param[in] request containing the target lists.
103 * @param[in] list #fr_pair_list_t value to resolve to TALLOC_CTX.
104 * @return
105 * - TALLOC_CTX on success.
106 * - NULL on failure.
107 *
108 * @see tmpl_pair_list
109 */
110TALLOC_CTX *tmpl_list_ctx(request_t *request, fr_dict_attr_t const *list)
111{
112 if (!request) return NULL;
113
114 if (list == request_attr_request) return request->request_ctx;
115
116 if (list == request_attr_reply) return request->reply_ctx;
117
118 if (list == request_attr_control) return request->control_ctx;
119
120 if (list == request_attr_state) return request->session_state_ctx;
121
122 if (list == request_attr_local) return request->local_ctx;
123
124 return NULL;
125}
126
127/** Resolve a list to the #fr_packet_t holding the HEAD pointer for a #fr_pair_t list
128 *
129 * Returns a pointer to the #fr_packet_t that holds the HEAD pointer of a given list,
130 * for the current #request_t.
131 *
132 * @param[in] request To resolve list in.
133 * @param[in] list #fr_pair_list_t value to resolve to #fr_packet_t.
134 * @return
135 * - #fr_packet_t on success.
136 * - NULL on failure.
137 *
138 * @see tmpl_pair_list
139 */
141{
142 if (list == request_attr_request) return request->packet;
143
144 if (list == request_attr_reply) return request->reply;
145
146 return NULL;
147}
148
149/** Resolve a #tmpl_request_ref_t to a #request_t.
150 *
151 * Sometimes #request_t structs may be chained to each other, as is the case
152 * when internally proxying EAP. This function resolves a #tmpl_request_ref_t
153 * to a #request_t higher in the chain than the current #request_t.
154 *
155 * @see tmpl_pair_list
156 * @param[in,out] context #request_t to start resolving from, and where to write
157 * a pointer to the resolved #request_t back to.
158 * @param[in] rql list of request qualifiers to follow.
159 * @return
160 * - 0 if request is valid in this context.
161 * - -1 if request is not valid in this context.
162 */
163int tmpl_request_ptr(request_t **context, FR_DLIST_HEAD(tmpl_request_list) const *rql)
164{
165 tmpl_request_t *rr = NULL;
166 request_t *request = *context;
167
168 while ((rr = tmpl_request_list_next(rql, rr))) {
169 switch (rr->request) {
170 case REQUEST_CURRENT:
171 continue; /* noop */
172
173 case REQUEST_PARENT: /* Navigate up one level */
174 if (!request->parent) return -1;
175 request = request->parent;
176 break;
177
178 case REQUEST_OUTER: /* Navigate to the outermost request */
179 if (!request->parent) return -1;
180 while (request->parent) request = request->parent;
181 break;
182
183 case REQUEST_UNKNOWN:
184 default:
185 fr_assert(0);
186 return -1;
187 }
188 }
189
190 *context = request;
191
192 return 0;
193}
194
195/** Return the native data type of the expression
196 *
197 * @param[in] vpt to determine the type of.
198 * @return
199 * - FR_TYPE_NULL if the type of the #tmpl_t can't be determined.
200 * - The data type we'd expect the #tmpl_t to produce at runtime
201 * when expanded.
202 */
204{
205 /*
206 * Regexes can't be expanded
207 */
209
210 /*
211 * Casts take precedence over everything.
212 */
214
215 /*
216 * Anything that's not a bare word will
217 * be a string unless there's a casting
218 * operator.
219 */
220 if (vpt->quote != T_BARE_WORD) return FR_TYPE_STRING;
221
222 switch (vpt->type) {
223 case TMPL_TYPE_ATTR:
224 return tmpl_attr_tail_da(vpt)->type;
225
226 case TMPL_TYPE_DATA:
227 return tmpl_value_type(vpt);
228
229 case TMPL_TYPE_XLAT:
230 case TMPL_TYPE_EXEC:
231 return FR_TYPE_STRING;
232
233 default:
234 break;
235 }
236
237 return FR_TYPE_NULL;
238}
239
240/** Expand a #tmpl_t to a string writing the result to a buffer
241 *
242 * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #tmpl_t
243 * provided by the conf parser, into a usable value.
244 * The value returned should be raw and undoctored for #FR_TYPE_STRING and #FR_TYPE_OCTETS types,
245 * and the printable (string) version of the data for all others.
246 *
247 * Depending what arguments are passed, either copies the value to buff, or writes a pointer
248 * to a string buffer to out. This allows the most efficient access to the value resolved by
249 * the #tmpl_t, avoiding unnecessary string copies.
250 *
251 * @note This function is used where raw string values are needed, which may mean the string
252 * returned may be binary data or contain unprintable chars. #fr_snprint or #fr_asprint
253 * should be used before using these values in debug statements. #is_printable can be used to
254 * check if the string only contains printable chars.
255 *
256 * @param[out] out Where to write a pointer to the string buffer. On return may
257 * point to buff if buff was used to store the value. Otherwise will
258 * point to a #fr_value_box_t buffer, or the name of the template.
259 * Must not be NULL.
260 * @param[out] buff Expansion buffer, may be NULL except for the following types:
261 * - #TMPL_TYPE_EXEC
262 * - #TMPL_TYPE_XLAT
263 * - input type non-string, output type string
264 * @param[in] bufflen Length of expansion buffer. Must be >= 2.
265 * @param[in] request Current request.
266 * @param[in] vpt to expand. Must be one of the following types:
267 * - #TMPL_TYPE_EXEC
268 * - #TMPL_TYPE_XLAT
269 * - #TMPL_TYPE_ATTR
270 * - #TMPL_TYPE_DATA
271 * @param dst_type FR_TYPE_* matching out pointer. @see tmpl_expand.
272 * @return
273 * - -1 on failure.
274 * - The length of data written out.
275 */
277 uint8_t *buff, size_t bufflen,
278 request_t *request,
279 tmpl_t const *vpt,
280 fr_type_t dst_type)
281{
282 fr_value_box_t value_to_cast = FR_VALUE_BOX_INITIALISER_NULL(value_to_cast);
283 fr_value_box_t value_from_cast = FR_VALUE_BOX_INITIALISER_NULL(value_from_cast);
284 fr_value_box_t const *to_cast = NULL;
285 fr_value_box_t const *from_cast = NULL;
286
287 fr_pair_t *vp = NULL;
288
289 ssize_t slen = -1; /* quiet compiler */
290
292
295
296 fr_assert(!buff || (bufflen >= 2));
297
298 switch (vpt->type) {
299 case TMPL_TYPE_EXEC:
300 RDEBUG4("EXPAND TMPL EXEC");
301 if (!buff) {
302 REDEBUG("Missing expansion buffer for exec");
303 return -1;
304 }
305
306 if (radius_exec_program_legacy((char *) buff, bufflen, request, vpt->name, NULL,
307 true, false, fr_time_delta_from_sec(EXEC_TIMEOUT)) != 0) return -1;
308
309 fr_value_box_strdup_shallow(&value_to_cast, NULL, (char *) buff, true);
310 to_cast = &value_to_cast;
311 break;
312
313 case TMPL_TYPE_XLAT:
314 RDEBUG4("EXPAND TMPL XLAT PARSED");
315
316 /* No EXPAND <xlat> here as the xlat code does it */
317
318 if (!buff) {
319 REDEBUG("Missing expansion buffer for dynamic expansion");
320 return -1;
321 }
322
323 /* Error in expansion, this is distinct from zero length expansion */
324 slen = xlat_eval_compiled((char *) buff, bufflen, request, tmpl_xlat(vpt), NULL, NULL);
325 if (slen < 0) return slen;
326
327 fr_value_box_bstrndup_shallow(&value_to_cast, NULL, (char *) buff, slen, true);
328 to_cast = &value_to_cast;
329 break;
330
331 case TMPL_TYPE_ATTR:
332 RDEBUG4("EXPAND TMPL ATTR");
333 if (tmpl_find_vp(&vp, request, vpt) < 0) {
334 REDEBUG("Failed to find attribute %s", vpt->name);
335 return -2;
336 }
337
338 to_cast = &vp->data;
339 break;
340
341 case TMPL_TYPE_DATA:
342 RDEBUG4("EXPAND TMPL DATA");
343 to_cast = tmpl_value(vpt);
344 break;
345
346 /*
347 * We should never be expanding these.
348 */
354 case TMPL_TYPE_REGEX:
358 case TMPL_TYPE_MAX:
359 fr_assert(0);
360 return -1;
361 }
362
363 /*
364 * Same type, just copy the value.
365 *
366 * If the input is exec/xlat, then we can just copy the output ptr to the caller, as it's already
367 * pointing to "buff".
368 */
369 if (to_cast->type == dst_type) {
370 from_cast = to_cast;
371 goto do_copy;
372 }
373
374 /*
375 * We need a buffer to hold ouput data which can be returned to the caller.
376 */
377 if (fr_type_is_variable_size(dst_type) && !buff) {
378 REDEBUG("Missing expansion buffer for %s -> %s cast", fr_type_to_str(to_cast->type), fr_type_to_str(dst_type));
379 return -1;
380 }
381
382 /*
383 * Convert to the correct data type.
384 */
385 if (fr_value_box_cast(request, &value_from_cast, dst_type, NULL, to_cast)) {
386 RPEDEBUG("Failed casting input %pV to data type %s", to_cast, fr_type_to_str(dst_type));
387 return -1;
388 }
389
390 from_cast = &value_from_cast;
391
392 /*
393 * If the output is a talloc'd buffer, then we have to copy it to "buff", so that we can return
394 * the pointer to the caller.
395 */
396 if (fr_type_is_variable_size(dst_type)) {
397 size_t len = from_cast->vb_length + (dst_type == FR_TYPE_STRING);
398
399 if (bufflen < len) {
400 REDEBUG("Expansion buffer is too small. Buffer is %zu bytes, and we need %zu bytes",
401 bufflen, len);
402 return -1;
403 }
404
405 /*
406 * Copy the data to the buffer, and clear the alloc'd pointer.
407 */
408 memcpy(buff, from_cast->vb_octets, len);
409 len = from_cast->vb_length;
410 fr_value_box_clear(&value_from_cast);
411
412 /*
413 * "out" is a pointer to a char* or uint8_t*
414 */
415 *(uint8_t **) out = buff;
416
417 return len; /* the amount of data we copied above */
418 }
419
420do_copy:
421 RDEBUG4("Copying %zu bytes to %p from offset %zu",
423
424 fr_value_box_memcpy_out(out, from_cast);
425
426 return from_cast->vb_length;
427}
428
429/** Expand a template to a string, allocing a new buffer to hold the string
430 *
431 * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #tmpl_t
432 * provided by the conf parser, into a usable value.
433 * The value returned should be raw and undoctored for #FR_TYPE_STRING and #FR_TYPE_OCTETS types,
434 * and the printable (string) version of the data for all others.
435 *
436 * This function will always duplicate values, whereas #tmpl_expand may return a pointer to an
437 * existing buffer.
438 *
439 * @note This function is used where raw string values are needed, which may mean the string
440 * returned may be binary data or contain unprintable chars. #fr_snprint or #fr_asprint should
441 * be used before using these values in debug statements. #is_printable can be used to check
442 * if the string only contains printable chars.
443 *
444 * @note The type (char or uint8_t) can be obtained with talloc_get_type, and may be used as a
445 * hint as to how to process or print the data.
446 *
447 * @param ctx to allocate new buffer in.
448 * @param out Where to write pointer to the new buffer.
449 * @param request Current request.
450 * @param vpt to expand. Must be one of the following types:
451 * - #TMPL_TYPE_DATA_UNRESOLVED
452 * - #TMPL_TYPE_EXEC
453 * - #TMPL_TYPE_XLAT
454 * - #TMPL_TYPE_ATTR
455 * - #TMPL_TYPE_DATA
456 * @param escape xlat escape function (only used for TMPL_TYPE_XLAT_UNRESOLVED_* types).
457 * @param escape_ctx xlat escape function data (only used for TMPL_TYPE_XLAT_UNRESOLVED_* types).
458 * @param dst_type FR_TYPE_* matching out pointer. @see tmpl_aexpand.
459 * @return
460 * - -1 on failure.
461 * - The length of data written to buff, or pointed to by out.
462 */
463ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out,
464 request_t *request,
465 tmpl_t const *vpt,
466 xlat_escape_legacy_t escape, void const *escape_ctx,
467 fr_type_t dst_type)
468{
469 fr_value_box_t *vb_out, *vb_in = NULL;
471
472 fr_pair_t *vp = NULL;
473 bool needs_dup = false;
474
475 ssize_t slen = -1;
476 int ret;
477
478 TALLOC_CTX *tmp_ctx = NULL;
479 char *str = NULL;
480
482
485
486 switch (vpt->type) {
487 case TMPL_TYPE_EXEC:
488 RDEBUG4("EXPAND TMPL EXEC");
489
490 MEM(tmp_ctx = talloc_new(ctx));
491
492 MEM(fr_value_box_bstr_alloc(tmp_ctx, &str, &value, NULL, 1024, true));
493 if (radius_exec_program_legacy(str, 1024, request, vpt->name, NULL,
494 true, false, fr_time_delta_from_sec(EXEC_TIMEOUT)) != 0) {
495 error:
496 talloc_free(tmp_ctx);
497 return -1;
498 }
499
500 fr_value_box_strtrim(tmp_ctx, &value);
501 vb_in = &value;
502 break;
503
504 case TMPL_TYPE_XLAT:
506 RDEBUG4("EXPAND TMPL XLAT STRUCT");
507
508 MEM(tmp_ctx = talloc_new(ctx));
509
510 /*
511 * An error in expansion is distinct from zero
512 * length expansion. Zero-length strings are
513 * permitted.
514 */
515 slen = xlat_aeval_compiled(tmp_ctx, &str, request, tmpl_xlat(vpt), escape, escape_ctx);
516 if (slen < 0) {
517 RPEDEBUG("Failed expanding %s", vpt->name);
518 goto error;
519 }
520
521 /*
522 * The output is a string which might get cast to something later.
523 */
524 fr_value_box_bstrndup_shallow(&value, NULL, str, (size_t) slen, false);
525 vb_in = &value;
526 break;
527
528 case TMPL_TYPE_ATTR:
529 RDEBUG4("EXPAND TMPL ATTR");
530
531 ret = tmpl_find_vp(&vp, request, vpt);
532 if (ret < 0) {
533 RDEBUG("Failed finding attribute %s", vpt->name);
534 talloc_free(tmp_ctx);
535 return -2;
536 }
537
538 fr_assert(vp);
539
540 needs_dup = true;
541 vb_in = &vp->data;
542 break;
543
544 case TMPL_TYPE_DATA:
545 RDEBUG4("EXPAND TMPL DATA");
546
547 needs_dup = true;
549 break;
550
551 /*
552 * We should never be expanding these.
553 */
556 case TMPL_TYPE_REGEX:
562 case TMPL_TYPE_MAX:
563 fr_assert(0);
564 goto error;
565 }
566
567 fr_assert(vb_in != NULL);
568 VALUE_BOX_VERIFY(vb_in);
569
570 /*
571 * If the output is a value-box, we might cast it using the tmpl cast. When done, we just copy
572 * the value-box.
573 */
574 if (dst_type == FR_TYPE_VALUE_BOX) {
575 fr_type_t cast_type;
576
577 MEM(vb_out = fr_value_box_alloc_null(ctx));
578 cast_type = tmpl_rules_cast(vpt);
579
580 if (cast_type == FR_TYPE_NULL) {
581 if (needs_dup) {
582 if (unlikely(fr_value_box_copy(vb_out, vb_out, vb_in) < 0)) {
583 talloc_free(vb_out);
584 goto failed_cast;
585 }
586 } else {
587 fr_value_box_steal(vb_out, vb_out, vb_in);
588 }
589
590 } else {
591 ret = fr_value_box_cast(vb_out, vb_out, cast_type, NULL, vb_in);
592
593 if (ret < 0) {
594 talloc_free(vb_out);
595 dst_type = cast_type;
596
597 failed_cast:
598 RPEDEBUG("Failed casting input %pV to data type %s", vb_in, fr_type_to_str(dst_type));
599 goto error;
600 }
601 }
602
603 talloc_free(tmp_ctx);
604 VALUE_BOX_VERIFY(vb_out);
605 *(fr_value_box_t **) out = vb_out;
606 return 0;
607 }
608
609 /*
610 * Cast the data to the correct type. Which also allocates any variable sized buffers from the
611 * output ctx.
612 */
613 if (dst_type != vb_in->type) {
614 if (vb_in == &value) {
615 size_t datalen;
616 fr_slen_t parse_len;
617
618 fr_assert(tmp_ctx != NULL);
619 fr_assert(str != NULL);
620 fr_assert(dst_type != FR_TYPE_STRING); /* exec / xlat returned string in 'str' */
621
622 datalen = talloc_strlen(str);
623 parse_len = fr_value_box_from_str(ctx, &value, dst_type, NULL, str, datalen, NULL);
624 if (parse_len < 0) {
625 fr_value_box_bstrndup_shallow(&value, NULL, str, datalen, false);
626 goto failed_cast;
627 }
628
629 } else {
630 ret = fr_value_box_cast(ctx, &value, dst_type, NULL, vb_in);
631 if (ret < 0) goto failed_cast;
632 }
633
634 /*
635 * The input data has been converted, and placed into value.
636 */
637 vb_in = &value;
638
639 } else if (fr_type_is_variable_size(dst_type)) {
640 /*
641 * The output type is the same, but variable sized types need to be either duplicated, or
642 * reparented.
643 */
644 if (needs_dup) {
645 fr_assert(vb_in != &value);
646
647 if (unlikely(fr_value_box_copy(ctx, &value, vb_in) < 0)) goto failed_cast;
648 vb_in = &value;
649 } else {
650 fr_assert(dst_type == FR_TYPE_STRING);
651 fr_assert(str != NULL);
652
653 (void) talloc_steal(ctx, str); /* ensure it's parented from the right context */
654 fr_assert(vb_in == &value);
655 }
656 } /* else the output type is a leaf, and is the same data type as the input */
657
658 RDEBUG4("Copying %zu bytes to %p from offset %zu",
660
662
663 /*
664 * Frees any memory allocated for temporary buffers
665 * in this function.
666 */
667 talloc_free(tmp_ctx);
668
669 return vb_in->vb_length;
670}
671
672/** Copy pairs matching a #tmpl_t in the current #request_t
673 *
674 * @param ctx to allocate new #fr_pair_t in.
675 * @param out Where to write the copied #fr_pair_t (s).
676 * @param request The current #request_t.
677 * @param vpt specifying the #fr_pair_t type or list to copy.
678 * Must be one of the following types:
679 * - #TMPL_TYPE_ATTR
680 * @return
681 * - -1 if no matching #fr_pair_t could be found.
682 * - -2 if list could not be found (doesn't exist in current #request_t).
683 * - -3 if context could not be found (no parent #request_t available).
684 * - -4 on memory allocation error.
685 */
686int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
687{
688 fr_pair_t *vp;
689 fr_dcursor_t from;
691 int err;
692
694
696
697 for (vp = tmpl_dcursor_init(&err, NULL, &cc, &from, request, vpt);
698 vp;
699 vp = fr_dcursor_next(&from)) {
700 vp = fr_pair_copy(ctx, vp);
701 if (!vp) {
703 fr_strerror_const("Out of memory");
704 err = -4;
705 break;
706 }
708 }
710
711 return err;
712}
713
714
715/** Copy children of pairs matching a #tmpl_t in the current #request_t
716 *
717 * @param ctx to allocate new #fr_pair_t in.
718 * @param out Where to write the copied #fr_pair_t (s).
719 * @param request The current #request_t.
720 * @param vpt specifying the #fr_pair_t type or list to copy.
721 * Must be one of the following types:
722 * - #TMPL_TYPE_ATTR
723 * @return
724 * - -1 if no matching #fr_pair_t could be found.
725 * - -2 if list could not be found (doesn't exist in current #request_t).
726 * - -3 if context could not be found (no parent #request_t available).
727 * - -4 on memory allocation error.
728 */
729int tmpl_copy_pair_children(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
730{
731 fr_pair_t *vp;
732 fr_dcursor_t from;
734 int err;
735
737
739
741
742 for (vp = tmpl_dcursor_init(&err, NULL, &cc, &from, request, vpt);
743 vp;
744 vp = fr_dcursor_next(&from)) {
745 switch (vp->vp_type) {
747 if (fr_pair_list_copy(ctx, out, &vp->vp_group) < 0) {
748 err = -4;
749 goto done;
750 }
751 break;
752
753 default:
754 continue;
755 }
756 }
757done:
759
760 return err;
761}
762
763
764/** Returns the first VP matching a #tmpl_t
765 *
766 * @param[out] out where to write the retrieved vp.
767 * @param[in] request The current #request_t.
768 * @param[in] vpt specifying the #fr_pair_t type to find.
769 * Must be one of the following types:
770 * - #TMPL_TYPE_ATTR
771 * @return
772 * - 0 on success (found matching #fr_pair_t).
773 * - -1 if no matching #fr_pair_t could be found.
774 * - -2 if list could not be found (doesn't exist in current #request_t).
775 * - -3 if context could not be found (no parent #request_t available).
776 */
778{
779 fr_dcursor_t cursor;
781 fr_pair_t *vp;
782 int err;
783
785
786 vp = tmpl_dcursor_init(&err, request, &cc, &cursor, request, vpt);
788
789 if (out) *out = vp;
790
791 return err;
792}
793
794/** Returns the first VP matching a #tmpl_t, or if no VPs match, creates a new one.
795 *
796 * @param[out] out where to write the retrieved or created vp.
797 * @param[in] request The current #request_t.
798 * @param[in] vpt specifying the #fr_pair_t type to retrieve or create. Must be #TMPL_TYPE_ATTR.
799 * @return
800 * - 1 on success a pair was created.
801 * - 0 on success a pair was found.
802 * - -1 if a new #fr_pair_t couldn't be found or created.
803 * - -2 if list could not be found (doesn't exist in current #request_t).
804 * - -3 if context could not be found (no parent #request_t available).
805 */
807{
808 fr_dcursor_t cursor;
810 fr_pair_t *vp;
811 int err;
812
815
816 *out = NULL;
817
818 vp = tmpl_dcursor_init(&err, NULL, &cc, &cursor, request, vpt);
820
821 switch (err) {
822 case 0:
823 *out = vp;
824 return 0;
825
826 case -1:
827 {
828 TALLOC_CTX *ctx;
830
831 tmpl_pair_list_and_ctx(ctx, head, request, tmpl_request(vpt), tmpl_list(vpt));
832 if (!head) return -1;
833
834 if (pair_append_by_tmpl_parent(ctx, &vp, head, vpt, true) < 0) return -1;
835
837 *out = vp;
838 }
839 return 1;
840
841 default:
842 return err;
843 }
844}
845
846/** Allocate and insert a leaf vp from a tmpl_t, building the parent vps if needed.
847 *
848 * This is the simple case - just add a vp at the first place where
849 * the parents exist, or create the parents, with no attempt to handle filters.
850 *
851 * It is functionally equivalent to fr_pair_append_by_da_parent() but
852 * uses a tmpl_t to build the nested structure rather than a fr_dict_attr_t.
853 *
854 * @param[in] ctx to allocate new pair(s) in
855 * @param[out] out Leaf pair we allocated.
856 * @param[in] list to insert into.
857 * @param[in] vpt tmpl representing the attribute to add.
858 * @param[in] skip_list skip list attr ref at the head of the tmpl.
859 * @return
860 * - 0 on success.
861 * - -1 on failure.
862 */
863int pair_append_by_tmpl_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, tmpl_t const *vpt, bool skip_list)
864{
865 fr_pair_t *vp = NULL;
866 TALLOC_CTX *pair_ctx = ctx;
867 tmpl_attr_t *ar, *leaf;
868 tmpl_attr_list_head_t const *ar_list = &vpt->data.attribute.ar;
869
870 if (!tmpl_is_attr(vpt)) {
871 error:
872 *out = NULL;
873 return -1;
874 }
875
876 leaf = tmpl_attr_list_tail(ar_list);
877 ar = tmpl_attr_list_head(ar_list);
878 if (!ar) goto error;
879 if (skip_list && tmpl_attr_is_list_attr(ar)) ar = tmpl_attr_list_next(ar_list, ar);
880
881 /*
882 * Walk down the tmpl ar stack looking for candidate parent
883 * attributes and then allocating the leaf.
884 */
885 while (true) {
886 if (unlikely(!ar)) goto error;
887 /*
888 * We're not at the leaf, look for a potential parent
889 */
890 if (ar != leaf) {
891 vp = fr_pair_find_by_da(list, NULL, ar->da);
892 }
893
894 /*
895 * Nothing found, create the pair
896 */
897 if (!vp) {
898 if (fr_pair_append_by_da(pair_ctx, &vp, list, ar->da) < 0) goto error;
900 }
901
902 /*
903 * We're at the leaf, return
904 */
905 if (ar == leaf) {
906 *out = vp;
907 return 0;
908 }
909
910 /*
911 * Prepare for next level
912 */
913 list = &vp->vp_group;
914 pair_ctx = vp;
915 vp = NULL;
916 ar = tmpl_attr_list_next(ar_list, ar);
917 }
918}
919
920/** Insert a value-box to a list, with casting.
921 *
922 * @param list to append to
923 * @param box box to cast / append
924 * @param vpt tmpl with cast.
925 * @return
926 * - <0 for "cast failed"
927 * - 0 for success
928 */
929int tmpl_value_list_insert_tail(fr_value_box_list_t *list, fr_value_box_t *box, tmpl_t const *vpt)
930{
932 (box->type == tmpl_rules_cast(vpt))) {
933 fr_value_box_list_insert_tail(list, box);
934 return 0;
935 }
936
937 if (fr_value_box_cast_in_place(box, box, tmpl_rules_cast(vpt), tmpl_rules_enumv(vpt)) < 0) return -1;
938
939 fr_value_box_list_insert_tail(list, box);
941 return 0;
942}
943
944/** Gets the value of a real or virtual attribute
945 *
946 * @param[in] ctx to allocate boxed value, and buffers in.
947 * @param[out] out Where to write the boxed value.
948 * @param[in] request The current request.
949 * @param[in] vpt Representing the attribute.
950 * @return
951 * - <0 we failed getting a value for the attribute.
952 * - 0 we successfully evaluated the tmpl
953 */
954int tmpl_eval_pair(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
955{
956 fr_pair_t *vp = NULL;
958
959 fr_dcursor_t cursor;
961
962 int ret = 0;
963 fr_value_box_list_t list;
964
966
967 fr_value_box_list_init(&list);
968
969 /*
970 * See if we're dealing with an attribute in the request
971 *
972 * This allows users to manipulate virtual attributes as if
973 * they were real ones.
974 */
975 vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt);
976
977 /*
978 * We didn't find the VP in a list, check to see if it's
979 * virtual. This allows the caller to "realize" the
980 * attribute, and we then prefer the realized version to
981 * the virtual one.
982 */
983 if (!vp) {
984 /*
985 * Zero count.
986 */
989 if (!value) {
990 oom:
991 fr_strerror_const("Out of memory");
992 ret = -1;
993 goto fail;
994 }
995 value->datum.uint32 = 0;
996 fr_value_box_list_insert_tail(&list, value);
997 } /* Fall through to being done */
998
999 goto done;
1000 }
1001
1002 switch (tmpl_attr_tail_num(vpt)) {
1003 /*
1004 * Return a count of the VPs.
1005 */
1006 case NUM_COUNT:
1007 {
1008 uint32_t count = 0;
1009
1010 while (vp != NULL) {
1011 count++;
1012 vp = fr_dcursor_next(&cursor);
1013 }
1014
1016 if (!value) goto oom;
1017 value->datum.uint32 = count;
1018 fr_value_box_list_insert_tail(&list, value);
1019 break;
1020 }
1021
1022 /*
1023 * Output multiple #value_box_t, one per attribute.
1024 */
1025 case NUM_ALL:
1026 /*
1027 * Loop over all matching #fr_value_pair
1028 * shallow copying buffers.
1029 */
1030 while (vp != NULL) {
1031 if (fr_type_is_structural(vp->vp_type)) {
1033 if (!value) goto oom;
1034
1035 if (fr_pair_list_copy_to_box(value, &vp->vp_group) < 0) {
1037 goto oom;
1038 }
1039
1040 } else {
1041 value = fr_value_box_alloc(ctx, vp->data.type, vp->da);
1042 if (!value) goto oom;
1043 if(unlikely(fr_value_box_copy(value, value, &vp->data) < 0)) {
1045 goto fail;
1046 }
1047 }
1048
1049 fr_value_box_list_insert_tail(&list, value);
1050 vp = fr_dcursor_next(&cursor);
1051 }
1052 break;
1053
1054 default:
1055 if (!fr_type_is_leaf(vp->vp_type)) {
1056 fr_strerror_const("Invalid data type for evaluation");
1057 goto fail;
1058 }
1059
1060 value = fr_value_box_alloc(ctx, vp->data.type, vp->da);
1061 if (!value) goto oom;
1062
1063 if (unlikely(fr_value_box_copy(value, value, &vp->data) < 0)) {
1065 goto fail;
1066 }
1067 fr_value_box_list_insert_tail(&list, value);
1068 break;
1069 }
1070
1071done:
1072 /*
1073 * Evaluate casts if necessary.
1074 */
1075 if (ret == 0) {
1076 if (tmpl_eval_cast_in_place(&list, request, vpt) < 0) {
1077 fr_value_box_list_talloc_free(&list);
1078 ret = -1;
1079 goto fail;
1080 }
1081
1082 fr_value_box_list_move(out, &list);
1083 }
1084
1085fail:
1086 tmpl_dcursor_clear(&cc);
1088 return ret;
1089}
1090
1091
1092/** Gets the value of a tmpl
1093 *
1094 * The result is returned "raw". The caller must do any escaping it desires.
1095 *
1096 * @param[in] ctx to allocate boxed value, and buffers in.
1097 * @param[out] out Where to write the boxed value.
1098 * @param[in] request The current request.
1099 * @param[in] vpt Representing the tmpl
1100 * @return
1101 * - <0 we failed getting a value for the tmpl
1102 * - 0 we successfully evaluated the tmpl
1103 */
1104int tmpl_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
1105{
1106 char *p;
1108 fr_value_box_list_t list;
1109
1111 fr_strerror_const("Cannot evaluate unresolved tmpl");
1112 return -1;
1113 }
1114
1115 if (tmpl_async_required(vpt)) {
1116 fr_strerror_const("Cannot statically evaluate asynchronous expansions");
1117 return -1;
1118 }
1119
1120 if (tmpl_contains_regex(vpt)) {
1121 fr_strerror_const("Cannot statically evaluate regular expression");
1122 return -1;
1123 }
1124
1125 if (tmpl_is_attr(vpt)) {
1126 return tmpl_eval_pair(ctx, out, request, vpt);
1127 }
1128
1129 if (tmpl_is_data(vpt)) {
1131
1134 return -1; /* Also dups taint */
1135 }
1136 goto done;
1137 }
1138
1140
1141 /*
1142 * @todo - respect escaping functions. But the sync
1143 * escaping uses a different method than the async ones.
1144 * And we then also need to escape the output of
1145 * tmpl_eval_pair(), too.
1146 */
1148 if (tmpl_aexpand(value, &p, request, vpt, NULL, NULL) < 0) {
1150 return -1;
1151 }
1153
1154 /*
1155 * Cast the results if necessary.
1156 */
1157done:
1158 fr_value_box_list_init(&list);
1159 fr_value_box_list_insert_tail(&list, value);
1160
1161 if (tmpl_eval_cast_in_place(&list, request, vpt) < 0) {
1162 fr_value_box_list_talloc_free(&list);
1163 return -1;
1164 }
1165
1166 fr_value_box_list_move(out, &list);
1168
1169 return 0;
1170}
1171
1172/** Allocate a uctx for an escaping function
1173 *
1174 * @param[in] request The current request.
1175 * @param[in] escape Describing how to escape tmpl data.
1176 *
1177 * @return the uctx to pass to the escape function.
1178 */
1179static inline void *tmpl_eval_escape_uctx_alloc(request_t *request, tmpl_escape_t const *escape)
1180{
1181 switch (escape->uctx.type) {
1183 return UNCONST(void *, escape->uctx.ptr);
1184
1186 {
1187 void *uctx;
1188
1189 fr_assert_msg(escape->uctx.size > 0, "TMPL_ESCAPE_UCTX_ALLOC must specify uctx.size > 0");
1190 MEM(uctx = talloc_zero_array(NULL, uint8_t, escape->uctx.size));
1191 if (escape->uctx.talloc_type) talloc_set_type(uctx, escape->uctx.talloc_type);
1192 return uctx;
1193 }
1194
1196 fr_assert_msg(escape->uctx.func.alloc, "TMPL_ESCAPE_UCTX_ALLOC_FUNC must specify a non-null alloc.func");
1197 return escape->uctx.func.alloc(request, escape->uctx.func.uctx);
1198
1199 default:
1200 fr_assert_msg(0, "Unknown escape uctx type %u", escape->uctx.type);
1201 return NULL;
1202 }
1203}
1204
1205/** Free a uctx for an escaping function
1206 *
1207 * @param[in] escape Describing how to escape tmpl data.
1208 * @param[in] uctx The uctx to free.
1209 */
1210static inline void tmpl_eval_escape_uctx_free(tmpl_escape_t const *escape, void *uctx)
1211{
1212 switch (escape->uctx.type) {
1214 return;
1215
1217 talloc_free(uctx);
1218 return;
1219
1221 if (escape->uctx.func.free) escape->uctx.func.free(uctx);
1222 return;
1223 }
1224}
1225
1226/** Casts a value or list of values according to the tmpl
1227 *
1228 * @param[in,out] list Where to write the boxed value.
1229 * @param[in] request The current request.
1230 * @param[in] vpt Representing the attribute.
1231 * @return
1232 * - <0 the cast failed
1233 * - 0 we successfully evaluated the tmpl
1234 */
1235int tmpl_eval_cast_in_place(fr_value_box_list_t *list, request_t *request, tmpl_t const *vpt)
1236{
1238 bool did_concat = false;
1239 void *uctx = NULL;
1240
1241 if (fr_type_is_structural(cast)) {
1242 fr_strerror_printf("Cannot cast to structural type '%s'", fr_type_to_str(cast));
1243 return -1;
1244 }
1245
1246 /*
1247 * Quoting around the tmpl means everything
1248 * needs to be concatenated, either as a string
1249 * or octets string.
1250 */
1251 switch (vpt->quote) {
1256 {
1257 ssize_t slen;
1258 fr_value_box_t *vb;
1259
1260 vb = fr_value_box_list_head(list);
1261 if (!vb) return 0;
1262
1264 uctx = tmpl_eval_escape_uctx_alloc(request, &vpt->rules.escape);
1265
1266 /*
1267 * Sets escaped values, so boxes don't get re-escaped
1268 */
1269 if (unlikely(fr_value_box_list_escape_in_place(list, &vpt->rules.escape.box_escape, uctx) < 0)) {
1270 error:
1271 tmpl_eval_escape_uctx_free(&vpt->rules.escape, uctx);
1272 return -1;
1273 }
1274 }
1275
1277 FR_VALUE_BOX_LIST_FREE_BOX, true, SIZE_MAX);
1278 if (slen < 0) goto error;
1280
1281 /*
1282 * If there's no cast, or it's a cast to
1283 * a string, we're done!
1284 *
1285 * Otherwise we now need to re-cast the
1286 * result.
1287 */
1288 if (fr_type_is_null(cast) || fr_type_is_string(cast)) {
1289 success:
1290 tmpl_eval_escape_uctx_free(&vpt->rules.escape, uctx);
1291 return 0;
1292 }
1293
1294 did_concat = true;
1295 }
1296 break;
1297
1298 default:
1299 break;
1300 }
1301
1302 if (fr_type_is_null(cast)) goto success;
1303
1304 /*
1305 * Quoting above handled all concatenation,
1306 * we now need to handle potentially
1307 * multivalued lists.
1308 */
1309 fr_value_box_list_foreach(list, vb) {
1310 if (fr_value_box_cast_in_place(vb, vb, cast, NULL) < 0) goto error;
1311 }
1312
1313 /*
1314 * ...and finally, apply the escape function
1315 * if necessary. This is done last so that
1316 * the escape function gets boxes of the type
1317 * it expects.
1318 */
1319 if ((!did_concat && tmpl_escape_pre_concat(vpt)) || tmpl_escape_post_concat(vpt)) {
1320 if (!uctx) uctx = tmpl_eval_escape_uctx_alloc(request, &vpt->rules.escape);
1321 if (unlikely(fr_value_box_list_escape_in_place(list, &vpt->rules.escape.box_escape, uctx) < 0)) goto error;
1322 }
1323
1324 /*
1325 * If there's no escape function, but there is
1326 * a safe_for value, mark all the boxes up with
1327 * this value.
1328 *
1329 * This is mostly useful for call_env usage in
1330 * modules where certain values are implicitly safe
1331 * for consumption, like SQL statements in the SQL
1332 * module.
1333 */
1334 if (!vpt->rules.escape.box_escape.func && vpt->rules.escape.box_escape.safe_for) {
1335 fr_value_box_list_mark_safe_for(list, vpt->rules.escape.box_escape.safe_for);
1336 }
1337
1339
1340 goto success;
1341}
1342
1344{
1346
1347 if (vpt->quote != T_BARE_WORD) return FR_TYPE_STRING;
1348
1349 if (tmpl_is_data(vpt)) return tmpl_value_type(vpt);
1350
1351 if (tmpl_is_attr(vpt)) return tmpl_attr_tail_da(vpt)->type;
1352
1354
1355 return FR_TYPE_NULL; /* can't determine it */
1356}
1357
1358
1359static int _tmpl_global_free(UNUSED void *uctx)
1360{
1362
1363 return 0;
1364}
1365
1366static int _tmpl_global_init(UNUSED void *uctx)
1367{
1368 fr_dict_attr_t *da;
1369
1370 if (fr_dict_autoload(tmpl_dict) < 0) {
1371 PERROR("%s", __FUNCTION__);
1372 return -1;
1373 }
1374
1376 fr_assert(da != NULL);
1377
1378 da->type = FR_TYPE_NULL;
1379 tmpl_attr_unspec = da;
1380
1381 return 0;
1382}
1383
1385{
1386 int ret;
1387
1388 fr_atexit_global_once_ret(&ret, _tmpl_global_init, _tmpl_global_free, NULL);
1389
1390 return ret;
1391}
static int context
Definition radmin.c:69
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:186
#define RCSID(id)
Definition build.h:560
#define unlikely(_x)
Definition build.h:455
#define UNUSED
Definition build.h:384
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:288
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:248
#define MEM(x)
Definition debug.h:38
#define fr_dict_autofree(_to_free)
Definition dict.h:937
static fr_slen_t err
Definition dict.h:904
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Definition dict.h:635
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
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:329
#define fr_dict_autoload(_to_load)
Definition dict.h:934
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:335
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:328
Test enumeration values.
Definition dict_test.h:92
#define FR_DLIST_HEAD(_name)
Expands to the type name used for the head wrapper structure.
Definition dlist.h:1139
#define EXEC_TIMEOUT
Default wait time for exec calls (in seconds).
Definition exec.h:32
int radius_exec_program_legacy(char *out, size_t outlen, request_t *request, char const *cmd, fr_pair_list_t *input_pairs, bool exec_wait, bool shell_escape, fr_time_delta_t timeout)
Execute a program.
talloc_free(hp)
#define PERROR(_fmt,...)
Definition log.h:233
#define RWDEBUG2(fmt,...)
Definition log.h:379
#define RPEDEBUG(fmt,...)
Definition log.h:393
#define RDEBUG4(fmt,...)
Definition log.h:361
size_t(* xlat_escape_legacy_t)(request_t *request, char *out, size_t outlen, char const *in, void *arg)
fr_type_t
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_VALUE_BOX
A boxed value.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_GROUP
A grouping of other attributes.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
ssize_t fr_slen_t
int fr_pair_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and append)
Definition pair.c:1417
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition pair.c:2300
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:708
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1298
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:504
int fr_pair_list_copy_to_box(fr_value_box_t *dst, fr_pair_list_t *from)
Copy the contents of a pair list to a set of value-boxes.
Definition pair.c:2335
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define RDEBUG(fmt,...)
static bool done
Definition radclient.c:80
fr_dict_attr_t const * request_attr_request
Definition request.c:43
fr_dict_attr_t const * request_attr_control
Definition request.c:45
fr_dict_attr_t const * request_attr_local
Definition request.c:47
fr_dict_attr_t const * request_attr_state
Definition request.c:46
fr_dict_attr_t const * request_attr_reply
Definition request.c:44
static int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
Return the last attribute reference's attribute number.
Definition tmpl.h:908
#define TMPL_VERIFY(_vpt)
Definition tmpl.h:984
#define tmpl_is_xlat(vpt)
Definition tmpl.h:217
#define tmpl_rules_enumv(_tmpl)
Definition tmpl.h:966
#define tmpl_value(_tmpl)
Definition tmpl.h:960
#define tmpl_contains_regex(vpt)
Definition tmpl.h:233
#define tmpl_is_attr(vpt)
Definition tmpl.h:215
#define NUM_ALL
Definition tmpl.h:418
bool tmpl_async_required(tmpl_t const *vpt)
Return whether or not async is required for this tmpl.
#define tmpl_xlat(_tmpl)
Definition tmpl.h:953
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
Definition tmpl.h:927
static bool tmpl_attr_is_list_attr(tmpl_attr_t const *ar)
Return true if the tmpl_attr is one of the list types.
Definition tmpl.h:706
#define tmpl_rules_cast(_tmpl)
Definition tmpl.h:965
@ TMPL_TYPE_REGEX_UNCOMPILED
Regex where compilation is possible but hasn't been performed yet.
Definition tmpl.h:165
@ TMPL_TYPE_MAX
Marker for the last tmpl type.
Definition tmpl.h:206
@ TMPL_TYPE_ATTR_UNRESOLVED
An attribute reference that we couldn't resolve but looked valid.
Definition tmpl.h:192
@ 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_REGEX
Compiled (and possibly JIT'd) regular expression.
Definition tmpl.h:161
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
Definition tmpl.h:186
@ TMPL_TYPE_XLAT_UNRESOLVED
A xlat expansion with unresolved xlat functions or attribute references.
Definition tmpl.h:200
@ TMPL_TYPE_REGEX_XLAT
A regex containing xlat expansions.
Definition tmpl.h:169
@ TMPL_TYPE_EXEC_UNRESOLVED
An exec with unresolved xlat function or attribute references.
Definition tmpl.h:196
@ TMPL_TYPE_UNINITIALISED
Uninitialised.
Definition tmpl.h:141
#define NUM_COUNT
Definition tmpl.h:419
#define tmpl_pair_list_and_ctx(_ctx, _head, _request, _ref, _list)
Determine the correct context and list head.
Definition tmpl.h:1016
#define tmpl_is_data(vpt)
Definition tmpl.h:213
static fr_slen_t vpt
Definition tmpl.h:1290
#define tmpl_value_type(_tmpl)
Definition tmpl.h:962
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:824
static char const * tmpl_list_name(fr_dict_attr_t const *list, char const *def)
Return the name of a tmpl list or def if list not provided.
Definition tmpl.h:938
@ REQUEST_OUTER
request_t containing the outer layer of the EAP conversation.
Definition tmpl.h:99
@ REQUEST_PARENT
Parent (whatever it is).
Definition tmpl.h:103
@ REQUEST_UNKNOWN
Unknown request.
Definition tmpl.h:104
@ REQUEST_CURRENT
The current request (default).
Definition tmpl.h:98
#define tmpl_aexpand(_ctx, _out, _request, _vpt, _escape, _escape_ctx)
Expand a tmpl to a C type, allocing a new buffer to hold the string.
Definition tmpl.h:1087
#define tmpl_needs_resolving(vpt)
Definition tmpl.h:230
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:37
return count
Definition module.c:155
fr_pair_t * vp
An element in a list of nested attribute references.
Definition tmpl.h:457
fr_dict_attr_t const *_CONST da
Resolved dictionary attribute.
Definition tmpl.h:461
Define manipulation functions for the attribute reference list.
Definition tmpl.h:498
tmpl_request_ref_t _CONST request
Definition tmpl.h:502
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
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
void tmpl_dcursor_clear(tmpl_dcursor_ctx_t *cc)
Clear any temporary state allocations.
#define tmpl_dcursor_init(_err, _ctx, _cc, _cursor, _request, _vpt)
Maintains state between cursor calls.
#define tmpl_escape_post_concat(_tmpl)
See if we should perform output escaping after concatenation.
#define tmpl_escape_pre_concat(_tmpl)
See if we should perform output escaping before concatenation.
@ TMPL_ESCAPE_UCTX_ALLOC
A new uctx of the specified size and type is allocated and freed when escaping is complete.
Definition tmpl_escape.h:33
@ TMPL_ESCAPE_UCTX_STATIC
A static (to us) is provided by whatever is initialising the tmpl_escape_t.
Definition tmpl_escape.h:31
@ TMPL_ESCAPE_UCTX_ALLOC_FUNC
A new uctx of the specified size and type is allocated and pre-populated by memcpying uctx....
Definition tmpl_escape.h:35
struct tmpl_escape_t::@80 uctx
Escaping rules for tmpls.
Definition tmpl_escape.h:80
int tmpl_find_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt)
Returns the first VP matching a tmpl_t.
Definition tmpl_eval.c:777
fr_packet_t * tmpl_packet_ptr(request_t *request, fr_dict_attr_t const *list)
Resolve a list to the fr_packet_t holding the HEAD pointer for a fr_pair_t list.
Definition tmpl_eval.c:140
int tmpl_value_list_insert_tail(fr_value_box_list_t *list, fr_value_box_t *box, tmpl_t const *vpt)
Insert a value-box to a list, with casting.
Definition tmpl_eval.c:929
fr_dict_attr_t const * tmpl_attr_unspec
Placeholder attribute for uses of unspecified attribute references.
Definition tmpl_eval.c:55
static int _tmpl_global_free(UNUSED void *uctx)
Definition tmpl_eval.c:1359
static fr_dict_t const * dict_freeradius
Definition tmpl_eval.c:42
static fr_dict_t const * dict_radius
Definition tmpl_eval.c:43
int tmpl_request_ptr(request_t **context, FR_DLIST_HEAD(tmpl_request_list) const *rql)
Resolve a tmpl_request_ref_t to a request_t.
Definition tmpl_eval.c:163
int tmpl_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
Gets the value of a tmpl.
Definition tmpl_eval.c:1104
int tmpl_eval_cast_in_place(fr_value_box_list_t *list, request_t *request, tmpl_t const *vpt)
Casts a value or list of values according to the tmpl.
Definition tmpl_eval.c:1235
fr_pair_list_t * tmpl_list_head(request_t *request, fr_dict_attr_t const *list)
Resolve attribute fr_pair_list_t value to an attribute list.
Definition tmpl_eval.c:70
TALLOC_CTX * tmpl_list_ctx(request_t *request, fr_dict_attr_t const *list)
Return the correct TALLOC_CTX to alloc fr_pair_t in, for a list.
Definition tmpl_eval.c:110
ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out, request_t *request, tmpl_t const *vpt, xlat_escape_legacy_t escape, void const *escape_ctx, fr_type_t dst_type)
Expand a template to a string, allocing a new buffer to hold the string.
Definition tmpl_eval.c:463
fr_type_t tmpl_data_type(tmpl_t const *vpt)
Definition tmpl_eval.c:1343
int tmpl_global_init(void)
Definition tmpl_eval.c:1384
int tmpl_eval_pair(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
Gets the value of a real or virtual attribute.
Definition tmpl_eval.c:954
int tmpl_copy_pair_children(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
Copy children of pairs matching a tmpl_t in the current request_t.
Definition tmpl_eval.c:729
ssize_t _tmpl_to_type(void *out, uint8_t *buff, size_t bufflen, request_t *request, tmpl_t const *vpt, fr_type_t dst_type)
Expand a tmpl_t to a string writing the result to a buffer.
Definition tmpl_eval.c:276
int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
Copy pairs matching a tmpl_t in the current request_t.
Definition tmpl_eval.c:686
static void tmpl_eval_escape_uctx_free(tmpl_escape_t const *escape, void *uctx)
Free a uctx for an escaping function.
Definition tmpl_eval.c:1210
int tmpl_find_or_add_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt)
Returns the first VP matching a tmpl_t, or if no VPs match, creates a new one.
Definition tmpl_eval.c:806
static int _tmpl_global_init(UNUSED void *uctx)
Definition tmpl_eval.c:1366
fr_dict_autoload_t tmpl_dict[]
Definition tmpl_eval.c:46
static void * tmpl_eval_escape_uctx_alloc(request_t *request, tmpl_escape_t const *escape)
Allocate a uctx for an escaping function.
Definition tmpl_eval.c:1179
fr_type_t tmpl_expanded_type(tmpl_t const *vpt)
Return the native data type of the expression.
Definition tmpl_eval.c:203
int pair_append_by_tmpl_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, tmpl_t const *vpt, bool skip_list)
Allocate and insert a leaf vp from a tmpl_t, building the parent vps if needed.
Definition tmpl_eval.c:863
@ T_SINGLE_QUOTED_STRING
Definition token.h:120
@ T_BARE_WORD
Definition token.h:118
@ T_BACK_QUOTED_STRING
Definition token.h:121
@ T_DOUBLE_QUOTED_STRING
Definition token.h:119
@ T_SOLIDUS_QUOTED_STRING
Definition token.h:122
ssize_t xlat_eval_compiled(char *out, size_t outlen, request_t *request, xlat_exp_head_t const *head, xlat_escape_legacy_t escape, void const *escape_ctx))
Definition xlat_eval.c:1908
static fr_slen_t head
Definition xlat.h:410
ssize_t xlat_aeval_compiled(TALLOC_CTX *ctx, char **out, request_t *request, xlat_exp_head_t const *head, xlat_escape_legacy_t escape, void const *escape_ctx))
Definition xlat_eval.c:1925
fr_type_t xlat_data_type(xlat_exp_head_t const *head)
#define PAIR_ALLOCED(_x)
Definition pair.h:213
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_type_is_variable_size(_x)
Definition types.h:388
#define fr_type_is_structural(_x)
Definition types.h:392
#define fr_type_is_string(_x)
Definition types.h:348
#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
size_t const fr_value_box_field_sizes[]
How many bytes wide each of the value data fields are.
Definition value.c:151
fr_slen_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules)
Definition value.c:6141
int fr_value_box_strtrim(TALLOC_CTX *ctx, fr_value_box_t *vb)
Trim the length of the string buffer to match the length of the C string.
Definition value.c:4674
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
size_t const fr_value_box_offsets[]
Where the value starts in the fr_value_box_t.
Definition value.c:193
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition value.c:4421
int fr_value_box_list_escape_in_place(fr_value_box_list_t *list, fr_value_box_escape_t const *escape, void *uctx)
Escape a list of value boxes in place.
Definition value.c:6913
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_list_mark_safe_for(fr_value_box_list_t *list, fr_value_box_safe_for_t safe_for)
Set the escaped flag for all value boxes in a list.
Definition value.c:7421
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
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
int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
Copy value data verbatim moving any buffers to the specified context.
Definition value.c:4579
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:4404
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
Definition value.c:4986
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_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
static int fr_value_box_memcpy_out(void *out, fr_value_box_t const *vb)
Copy the value of a value box to a field in a C struct.
Definition value.h:829
#define FR_VALUE_BOX_INITIALISER_NULL(_vb)
A static initialiser for stack/globally allocated boxes.
Definition value.h:536
static fr_sbuff_err_t char ** out
Definition value.h:1062
static fr_sbuff_err_t char size_t * len
Definition value.h:1062
#define VALUE_BOX_VERIFY(_x)
Definition value.h:1389
#define VALUE_BOX_LIST_VERIFY(_x)
Definition value.h:1390
#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