The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 0234f583648b9044aa8c75662b8cf77e91e7203b $
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: 0234f583648b9044aa8c75662b8cf77e91e7203b $")
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/dlist.h>
40#include <freeradius-devel/util/proto.h>
41#include <freeradius-devel/util/value.h>
42#include <freeradius-devel/util/edit.h>
43#include <freeradius-devel/util/token.h>
44#include <freeradius-devel/util/types.h>
45
46#include <talloc.h>
47
49static fr_dict_t const *dict_radius;
50
53 { .out = &dict_freeradius, .proto = "freeradius" },
54 { .out = &dict_radius, .proto = "radius" }, /* @todo - remove RADIUS from the server core... */
55 { NULL }
56};
57
58/** Placeholder attribute for uses of unspecified attribute references
59 */
62
63
64/** Resolve attribute #fr_pair_list_t value to an attribute list.
65 *
66 * The value returned is a pointer to the pointer of the HEAD of a #fr_pair_t list in the
67 * #request_t. If the head of the list changes, the pointer will still be valid.
68 *
69 * @param[in] request containing the target lists.
70 * @param[in] list #fr_pair_list_t value to resolve to #fr_pair_t list. Will be NULL if list
71 * name couldn't be resolved.
72 * @return a pointer to the HEAD of a list in the #request_t.
73 *
74 * @see tmpl_dcursor_init
75 */
77{
78 if (!request) return NULL;
79
80 if (list == request_attr_request) {
81 if (!request->packet) return NULL;
82 return &request->request_pairs;
83 }
84
85 if (list == request_attr_reply) {
86 if (!request->reply) return NULL;
87 return &request->reply_pairs;
88 }
89
90 if (list == request_attr_control) return &request->control_pairs;
91
92 if (list == request_attr_state) return &request->session_state_pairs;
93
94 if (list == request_attr_local) return &request->local_pairs;
95
96 RWDEBUG2("List \"%s\" is not available", tmpl_list_name(list, "<INVALID>"));
97
98 return NULL;
99}
100
101/** Return the correct TALLOC_CTX to alloc #fr_pair_t in, for a list
102 *
103 * Allocating new #fr_pair_t in the context of a #request_t is usually wrong.
104 * #fr_pair_t should be allocated in the context of a #fr_packet_t, so that if the
105 * #fr_packet_t is freed before the #request_t, the associated #fr_pair_t lists are
106 * freed too.
107 *
108 * @param[in] request containing the target lists.
109 * @param[in] list #fr_pair_list_t value to resolve to TALLOC_CTX.
110 * @return
111 * - TALLOC_CTX on success.
112 * - NULL on failure.
113 *
114 * @see tmpl_pair_list
115 */
116TALLOC_CTX *tmpl_list_ctx(request_t *request, fr_dict_attr_t const *list)
117{
118 if (!request) return NULL;
119
120 if (list == request_attr_request) return request->request_ctx;
121
122 if (list == request_attr_reply) return request->reply_ctx;
123
124 if (list == request_attr_control) return request->control_ctx;
125
126 if (list == request_attr_state) return request->session_state_ctx;
127
128 if (list == request_attr_local) return request->local_ctx;
129
130 return NULL;
131}
132
133/** Resolve a list to the #fr_packet_t holding the HEAD pointer for a #fr_pair_t list
134 *
135 * Returns a pointer to the #fr_packet_t that holds the HEAD pointer of a given list,
136 * for the current #request_t.
137 *
138 * @param[in] request To resolve list in.
139 * @param[in] list #fr_pair_list_t value to resolve to #fr_packet_t.
140 * @return
141 * - #fr_packet_t on success.
142 * - NULL on failure.
143 *
144 * @see tmpl_pair_list
145 */
147{
148 if (list == request_attr_request) return request->packet;
149
150 if (list == request_attr_reply) return request->reply;
151
152 return NULL;
153}
154
155/** Resolve a #tmpl_request_ref_t to a #request_t.
156 *
157 * Sometimes #request_t structs may be chained to each other, as is the case
158 * when internally proxying EAP. This function resolves a #tmpl_request_ref_t
159 * to a #request_t higher in the chain than the current #request_t.
160 *
161 * @see tmpl_pair_list
162 * @param[in,out] context #request_t to start resolving from, and where to write
163 * a pointer to the resolved #request_t back to.
164 * @param[in] rql list of request qualifiers to follow.
165 * @return
166 * - 0 if request is valid in this context.
167 * - -1 if request is not valid in this context.
168 */
169int tmpl_request_ptr(request_t **context, FR_DLIST_HEAD(tmpl_request_list) const *rql)
170{
171 tmpl_request_t *rr = NULL;
172 request_t *request = *context;
173
174 while ((rr = tmpl_request_list_next(rql, rr))) {
175 switch (rr->request) {
176 case REQUEST_CURRENT:
177 continue; /* noop */
178
179 case REQUEST_PARENT: /* Navigate up one level */
180 if (!request->parent) return -1;
181 request = request->parent;
182 break;
183
184 case REQUEST_OUTER: /* Navigate to the outermost request */
185 if (!request->parent) return -1;
186 while (request->parent) request = request->parent;
187 break;
188
189 case REQUEST_UNKNOWN:
190 default:
191 fr_assert(0);
192 return -1;
193 }
194 }
195
196 *context = request;
197
198 return 0;
199}
200
201/** Return the native data type of the expression
202 *
203 * @param[in] vpt to determine the type of.
204 * @return
205 * - FR_TYPE_NULL if the type of the #tmpl_t can't be determined.
206 * - The data type we'd expect the #tmpl_t to produce at runtime
207 * when expanded.
208 */
210{
211 /*
212 * Regexes can't be expanded
213 */
215
216 /*
217 * Casts take precedence over everything.
218 */
220
221 /*
222 * Anything that's not a bare word will
223 * be a string unless there's a casting
224 * operator.
225 */
226 if (vpt->quote != T_BARE_WORD) return FR_TYPE_STRING;
227
228 switch (vpt->type) {
229 case TMPL_TYPE_ATTR:
230 return tmpl_attr_tail_da(vpt)->type;
231
232 case TMPL_TYPE_DATA:
233 return tmpl_value_type(vpt);
234
235 case TMPL_TYPE_XLAT:
236 case TMPL_TYPE_EXEC:
237 return FR_TYPE_STRING;
238
239 default:
240 break;
241 }
242
243 return FR_TYPE_NULL;
244}
245
246/** Expand a #tmpl_t to a string writing the result to a buffer
247 *
248 * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #tmpl_t
249 * provided by the conf parser, into a usable value.
250 * The value returned should be raw and undoctored for #FR_TYPE_STRING and #FR_TYPE_OCTETS types,
251 * and the printable (string) version of the data for all others.
252 *
253 * Depending what arguments are passed, either copies the value to buff, or writes a pointer
254 * to a string buffer to out. This allows the most efficient access to the value resolved by
255 * the #tmpl_t, avoiding unnecessary string copies.
256 *
257 * @note This function is used where raw string values are needed, which may mean the string
258 * returned may be binary data or contain unprintable chars. #fr_snprint or #fr_asprint
259 * should be used before using these values in debug statements. #is_printable can be used to
260 * check if the string only contains printable chars.
261 *
262 * @param[out] out Where to write a pointer to the string buffer. On return may
263 * point to buff if buff was used to store the value. Otherwise will
264 * point to a #fr_value_box_t buffer, or the name of the template.
265 * Must not be NULL.
266 * @param[out] buff Expansion buffer, may be NULL except for the following types:
267 * - #TMPL_TYPE_EXEC
268 * - #TMPL_TYPE_XLAT
269 * @param[in] bufflen Length of expansion buffer. Must be >= 2.
270 * @param[in] request Current request.
271 * @param[in] vpt to expand. Must be one of the following types:
272 * - #TMPL_TYPE_DATA_UNRESOLVED
273 * - #TMPL_TYPE_EXEC
274 * - #TMPL_TYPE_XLAT
275 * - #TMPL_TYPE_ATTR
276 * - #TMPL_TYPE_DATA
277 * @param[in] escape xlat escape function (only used for xlat types).
278 * @param[in] escape_ctx xlat escape function data.
279 * @param dst_type FR_TYPE_* matching out pointer. @see tmpl_expand.
280 * @return
281 * - -1 on failure.
282 * - The length of data written out.
283 */
285 uint8_t *buff, size_t bufflen,
286 request_t *request,
287 tmpl_t const *vpt,
288 xlat_escape_legacy_t escape, void const *escape_ctx,
289 fr_type_t dst_type)
290{
291 fr_value_box_t value_to_cast = FR_VALUE_BOX_INITIALISER_NULL(value_to_cast);
292 fr_value_box_t value_from_cast = FR_VALUE_BOX_INITIALISER_NULL(value_from_cast);
293 fr_value_box_t const *to_cast = &value_to_cast;
294 fr_value_box_t const *from_cast = &value_from_cast;
295
296 fr_pair_t *vp = NULL;
297
298 fr_type_t src_type = FR_TYPE_NULL;
299
300 ssize_t slen = -1; /* quiet compiler */
301
303
304 fr_assert(!buff || (bufflen >= 2));
305
306 switch (vpt->type) {
308 RDEBUG4("EXPAND TMPL UNRESOLVED");
309 fr_value_box_bstrndup_shallow(&value_to_cast, NULL, vpt->name, vpt->len, false);
310 src_type = FR_TYPE_STRING;
311 break;
312
313 case TMPL_TYPE_EXEC:
314 {
315 RDEBUG4("EXPAND TMPL EXEC");
316 if (!buff) {
317 fr_strerror_const("Missing expansion buffer for EXEC");
318 return -1;
319 }
320
321 if (radius_exec_program_legacy((char *)buff, bufflen, request, vpt->name, NULL,
322 true, false, fr_time_delta_from_sec(EXEC_TIMEOUT)) != 0) return -1;
323 fr_value_box_strdup_shallow(&value_to_cast, NULL, (char *)buff, true);
324 src_type = FR_TYPE_STRING;
325 }
326 break;
327
328 case TMPL_TYPE_XLAT:
329 {
330 size_t len;
331
332 RDEBUG4("EXPAND TMPL XLAT PARSED");
333
334 /* No EXPAND <xlat> here as the xlat code does it */
335
336 if (!buff) {
337 fr_strerror_const("Missing expansion buffer for XLAT_STRUCT");
338 return -1;
339 }
340 /* Error in expansion, this is distinct from zero length expansion */
341 slen = xlat_eval_compiled((char *)buff, bufflen, request, tmpl_xlat(vpt), escape, escape_ctx);
342 if (slen < 0) return slen;
343
344 RDEBUG2(" --> %s", (char *)buff); /* Print pre-unescaping (so it's escaped) */
345
346 /*
347 * Undo any of the escaping that was done by the
348 * xlat expansion function.
349 *
350 * @fixme We need a way of signalling xlat not to escape things.
351 */
352 len = fr_value_str_unescape(&FR_SBUFF_IN((char *)buff, slen),
353 &FR_SBUFF_IN((char *)buff, slen), SIZE_MAX, '"');
355 fr_value_box_bstrndup_shallow(&value_to_cast, NULL, (char *)buff, len, true);
356 src_type = FR_TYPE_STRING;
357 }
358 break;
359
360 case TMPL_TYPE_ATTR:
361 {
362 int ret;
363
364 RDEBUG4("EXPAND TMPL ATTR");
365 ret = tmpl_find_vp(&vp, request, vpt);
366 if (ret < 0) return -2;
367
368 to_cast = &vp->data;
369 src_type = vp->vp_type;
370 }
371 break;
372
373 case TMPL_TYPE_DATA:
374 RDEBUG4("EXPAND TMPL DATA");
375 to_cast = tmpl_value(vpt);
376 src_type = tmpl_value_type(vpt);
377 break;
378
379 /*
380 * We should never be expanding these.
381 */
383 case TMPL_TYPE_NULL:
387 case TMPL_TYPE_REGEX:
391 case TMPL_TYPE_MAX:
392 fr_assert(0);
393 return -1;
394 }
395
396 /*
397 * Deal with casts.
398 */
399 switch (src_type) {
400 case FR_TYPE_STRING:
401 switch (dst_type) {
402 case FR_TYPE_STRING:
403 case FR_TYPE_OCTETS:
404 from_cast = to_cast;
405 break;
406
407 default:
408 break;
409 }
410 break;
411
412 case FR_TYPE_OCTETS:
413 switch (dst_type) {
414 /*
415 * Need to use the expansion buffer for this conversion as
416 * we need to add a \0 terminator.
417 */
418 case FR_TYPE_STRING:
419 if (!buff) {
420 fr_strerror_const("Missing expansion buffer for octet->string cast");
421 return -1;
422 }
423 if (bufflen <= to_cast->vb_length) {
424 fr_strerror_printf("Expansion buffer too small. "
425 "Have %zu bytes, need %zu bytes", bufflen,
426 to_cast->vb_length + 1);
427 return -1;
428 }
429 memcpy(buff, to_cast->vb_octets, to_cast->vb_length);
430 buff[to_cast->vb_length] = '\0';
431
432 fr_value_box_bstrndup_shallow(&value_from_cast, NULL,
433 (char *)buff, to_cast->vb_length, true);
434 break;
435
436 /*
437 * Just copy the pointer. Length does not include \0.
438 */
439 case FR_TYPE_OCTETS:
440 from_cast = to_cast;
441 break;
442
443 default:
444 break;
445 }
446 break;
447
448 default:
449 {
450 int ret;
451 TALLOC_CTX *ctx;
452
453 /*
454 * Same type, just set from_cast to to_cast and copy the value.
455 */
456 if (src_type == dst_type) {
457 from_cast = to_cast;
458 break;
459 }
460
461 MEM(ctx = talloc_new(request));
462
463 from_cast = &value_from_cast;
464
465 /*
466 * Data type conversion...
467 */
468 ret = fr_value_box_cast(ctx, &value_from_cast, dst_type, NULL, to_cast);
469 if (ret < 0) goto error;
470
471
472 /*
473 * For the dynamic types we need to copy the output
474 * to the buffer. Really we need a version of fr_value_box_cast
475 * that works with buffers, but it's not a high priority...
476 */
477 switch (dst_type) {
478 case FR_TYPE_STRING:
479 if (!buff) {
480 fr_strerror_const("Missing expansion buffer to store cast output");
481 error:
482 talloc_free(ctx);
483 return -1;
484 }
485 if (from_cast->vb_length >= bufflen) {
486 fr_strerror_printf("Expansion buffer too small. "
487 "Have %zu bytes, need %zu bytes", bufflen,
488 from_cast->vb_length + 1);
489 goto error;
490 }
491 memcpy(buff, from_cast->vb_strvalue, from_cast->vb_length);
492 buff[from_cast->vb_length] = '\0';
493
494 fr_value_box_bstrndup_shallow(&value_from_cast, NULL,
495 (char *)buff, from_cast->vb_length, from_cast->tainted);
496 break;
497
498 case FR_TYPE_OCTETS:
499 if (!buff) {
500 fr_strerror_const("Missing expansion buffer to store cast output");
501 goto error;
502 }
503 if (from_cast->vb_length > bufflen) {
504 fr_strerror_printf("Expansion buffer too small. "
505 "Have %zu bytes, need %zu bytes", bufflen, from_cast->vb_length);
506 goto error;
507 }
508 memcpy(buff, from_cast->vb_octets, from_cast->vb_length);
509 fr_value_box_memdup_shallow(&value_from_cast, NULL,
510 buff, from_cast->vb_length, from_cast->tainted);
511 break;
512
513 default:
514 break;
515 }
516
517 talloc_free(ctx); /* Free any dynamically allocated memory from the cast */
518 }
519 }
520
521 RDEBUG4("Copying %zu bytes to %p from offset %zu",
523
524 fr_value_box_memcpy_out(out, from_cast);
525
526 return from_cast->vb_length;
527}
528
529/** Expand a template to a string, allocing a new buffer to hold the string
530 *
531 * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #tmpl_t
532 * provided by the conf parser, into a usable value.
533 * The value returned should be raw and undoctored for #FR_TYPE_STRING and #FR_TYPE_OCTETS types,
534 * and the printable (string) version of the data for all others.
535 *
536 * This function will always duplicate values, whereas #tmpl_expand may return a pointer to an
537 * existing buffer.
538 *
539 * @note This function is used where raw string values are needed, which may mean the string
540 * returned may be binary data or contain unprintable chars. #fr_snprint or #fr_asprint should
541 * be used before using these values in debug statements. #is_printable can be used to check
542 * if the string only contains printable chars.
543 *
544 * @note The type (char or uint8_t) can be obtained with talloc_get_type, and may be used as a
545 * hint as to how to process or print the data.
546 *
547 * @param ctx to allocate new buffer in.
548 * @param out Where to write pointer to the new buffer.
549 * @param request Current request.
550 * @param vpt to expand. Must be one of the following types:
551 * - #TMPL_TYPE_DATA_UNRESOLVED
552 * - #TMPL_TYPE_EXEC
553 * - #TMPL_TYPE_XLAT
554 * - #TMPL_TYPE_ATTR
555 * - #TMPL_TYPE_DATA
556 * @param escape xlat escape function (only used for TMPL_TYPE_XLAT_UNRESOLVED_* types).
557 * @param escape_ctx xlat escape function data (only used for TMPL_TYPE_XLAT_UNRESOLVED_* types).
558 * @param dst_type FR_TYPE_* matching out pointer. @see tmpl_aexpand.
559 * @return
560 * - -1 on failure.
561 * - The length of data written to buff, or pointed to by out.
562 */
563ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out,
564 request_t *request,
565 tmpl_t const *vpt,
566 xlat_escape_legacy_t escape, void const *escape_ctx,
567 fr_type_t dst_type)
568{
569 fr_value_box_t *to_cast = NULL;
570 fr_value_box_t from_cast;
571
572 fr_pair_t *vp = NULL;
574 bool needs_dup = false;
575
576 ssize_t slen = -1;
577 int ret;
578
579 TALLOC_CTX *tmp_ctx = talloc_new(ctx);
580
582
583 switch (vpt->type) {
585 RDEBUG4("EXPAND TMPL DATA UNRESOLVED");
586
587 fr_value_box_bstrndup_shallow(&value, NULL, vpt->name, vpt->len, false);
588 to_cast = &value;
589 needs_dup = true;
590 break;
591
592 case TMPL_TYPE_EXEC:
593 {
594 char *buff;
595
596 RDEBUG4("EXPAND TMPL EXEC");
597
598 MEM(fr_value_box_bstr_alloc(tmp_ctx, &buff, &value, NULL, 1024, true));
599 if (radius_exec_program_legacy(buff, 1024, request, vpt->name, NULL,
600 true, false, fr_time_delta_from_sec(EXEC_TIMEOUT)) != 0) {
601 error:
602 talloc_free(tmp_ctx);
603 return slen;
604 }
605 fr_value_box_strtrim(tmp_ctx, &value);
606 to_cast = &value;
607 }
608 break;
609
611 {
612 fr_value_box_t tmp;
613 fr_type_t src_type = FR_TYPE_STRING;
614 char *result;
615
616 RDEBUG4("EXPAND TMPL XLAT");
617
618 /* Error in expansion, this is distinct from zero length expansion */
619 slen = xlat_aeval(tmp_ctx, &result, request, vpt->name, escape, escape_ctx);
620 if (slen < 0) goto error;
621
622 /*
623 * Undo any of the escaping that was done by the
624 * xlat expansion function.
625 *
626 * @fixme We need a way of signalling xlat not to escape things.
627 */
628 ret = fr_value_box_from_str(tmp_ctx, &tmp, src_type, NULL,
629 result, (size_t)slen,
630 NULL, false);
631 if (ret < 0) goto error;
632
633 fr_value_box_bstrndup_shallow(&value, NULL, tmp.vb_strvalue, tmp.vb_length, tmp.tainted);
634 to_cast = &value;
635 }
636 break;
637
638 case TMPL_TYPE_XLAT:
640 {
641 fr_value_box_t tmp;
642 fr_type_t src_type = FR_TYPE_STRING;
643 char *result;
644
645 RDEBUG4("EXPAND TMPL XLAT STRUCT");
646 /* No EXPAND xlat here as the xlat code does it */
647
648 /* Error in expansion, this is distinct from zero length expansion */
649 slen = xlat_aeval_compiled(tmp_ctx, &result, request, tmpl_xlat(vpt), escape, escape_ctx);
650 if (slen < 0) goto error;
651
652 /*
653 * Undo any of the escaping that was done by the
654 * xlat expansion function.
655 *
656 * @fixme We need a way of signalling xlat not to escape things.
657 */
658 ret = fr_value_box_from_str(tmp_ctx, &tmp, src_type, NULL,
659 result, (size_t)slen,
660 NULL, false);
661 if (ret < 0) goto error;
662
663 fr_value_box_bstrndup_shallow(&value, NULL, tmp.vb_strvalue, tmp.vb_length, tmp.tainted);
664 to_cast = &value;
665 }
666 break;
667
668 case TMPL_TYPE_ATTR:
669 RDEBUG4("EXPAND TMPL ATTR");
670
671 ret = tmpl_find_vp(&vp, request, vpt);
672 if (ret < 0) {
673 talloc_free(tmp_ctx);
674 return -2;
675 }
676
677 fr_assert(vp);
678
679 to_cast = &vp->data;
680 switch (to_cast->type) {
681 case FR_TYPE_STRING:
682 case FR_TYPE_OCTETS:
683 fr_assert(to_cast->datum.ptr);
684 needs_dup = true;
685 break;
686
687 default:
688 break;
689 }
690 break;
691
692 case TMPL_TYPE_DATA:
693 {
694 RDEBUG4("EXPAND TMPL DATA");
695
696 to_cast = UNCONST(fr_value_box_t *, tmpl_value(vpt));
697 switch (to_cast->type) {
698 case FR_TYPE_STRING:
699 case FR_TYPE_OCTETS:
700 fr_assert(to_cast->datum.ptr);
701 needs_dup = true;
702 break;
703
704 default:
705 break;
706 }
707 }
708 break;
709
710 /*
711 * We should never be expanding these.
712 */
714 case TMPL_TYPE_NULL:
716 case TMPL_TYPE_REGEX:
720 case TMPL_TYPE_MAX:
721 fr_assert(0);
722 goto error;
723 }
724
725 /*
726 * Special case where we just copy the boxed value
727 * directly instead of casting it.
728 */
729 if (dst_type == FR_TYPE_VALUE_BOX) {
730 fr_value_box_t **vb_out = (fr_value_box_t **)out;
731
732 MEM(*vb_out = fr_value_box_alloc_null(ctx));
733
734 ret = needs_dup ? fr_value_box_copy(*vb_out, *vb_out, to_cast) : fr_value_box_steal(*vb_out, *vb_out, to_cast);
735 talloc_free(tmp_ctx);
736 if (ret < 0) {
737 RPEDEBUG("Failed copying data to output box");
738 TALLOC_FREE(*vb_out);
739 return -1;
740 }
741 VALUE_BOX_VERIFY(*vb_out);
742 return 0;
743 }
744
745 /*
746 * Don't dup the buffers unless we need to.
747 */
748 if ((to_cast->type != dst_type) || needs_dup) {
749 ret = fr_value_box_cast(ctx, &from_cast, dst_type, NULL, to_cast);
750 if (ret < 0) goto error;
751 } else {
752 switch (to_cast->type) {
753 case FR_TYPE_OCTETS:
754 case FR_TYPE_STRING:
755 /*
756 * Ensure we don't free the output buffer when the
757 * tmp_ctx is freed.
758 */
759 if (value.datum.ptr && (talloc_parent(value.datum.ptr) == tmp_ctx)) {
760 (void)talloc_reparent(tmp_ctx, ctx, value.datum.ptr);
761 }
762 break;
763
764 default:
765 break;
766 }
767 fr_value_box_copy_shallow(NULL, &from_cast, to_cast);
768 }
769
770 RDEBUG4("Copying %zu bytes to %p from offset %zu",
771 fr_value_box_field_sizes[dst_type], *((void **)out), fr_value_box_offsets[dst_type]);
772
773 fr_value_box_memcpy_out(out, &from_cast);
774
775 /*
776 * Frees any memory allocated for temporary buffers
777 * in this function.
778 */
779 talloc_free(tmp_ctx);
780
781 return from_cast.vb_length;
782}
783
784/** Copy pairs matching a #tmpl_t in the current #request_t
785 *
786 * @param ctx to allocate new #fr_pair_t in.
787 * @param out Where to write the copied #fr_pair_t (s).
788 * @param request The current #request_t.
789 * @param vpt specifying the #fr_pair_t type or list to copy.
790 * Must be one of the following types:
791 * - #TMPL_TYPE_ATTR
792 * @return
793 * - -1 if no matching #fr_pair_t could be found.
794 * - -2 if list could not be found (doesn't exist in current #request_t).
795 * - -3 if context could not be found (no parent #request_t available).
796 * - -4 on memory allocation error.
797 */
798int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
799{
800 fr_pair_t *vp;
801 fr_dcursor_t from;
803 int err;
804
806
808
809 for (vp = tmpl_dcursor_init(&err, NULL, &cc, &from, request, vpt);
810 vp;
811 vp = fr_dcursor_next(&from)) {
812 vp = fr_pair_copy(ctx, vp);
813 if (!vp) {
815 fr_strerror_const("Out of memory");
816 err = -4;
817 break;
818 }
820 }
822
823 return err;
824}
825
826
827/** Copy children of pairs matching a #tmpl_t in the current #request_t
828 *
829 * @param ctx to allocate new #fr_pair_t in.
830 * @param out Where to write the copied #fr_pair_t (s).
831 * @param request The current #request_t.
832 * @param vpt specifying the #fr_pair_t type or list to copy.
833 * Must be one of the following types:
834 * - #TMPL_TYPE_ATTR
835 * @return
836 * - -1 if no matching #fr_pair_t could be found.
837 * - -2 if list could not be found (doesn't exist in current #request_t).
838 * - -3 if context could not be found (no parent #request_t available).
839 * - -4 on memory allocation error.
840 */
841int tmpl_copy_pair_children(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
842{
843 fr_pair_t *vp;
844 fr_dcursor_t from;
846 int err;
847
849
851
853
854 for (vp = tmpl_dcursor_init(&err, NULL, &cc, &from, request, vpt);
855 vp;
856 vp = fr_dcursor_next(&from)) {
857 switch (vp->vp_type) {
859 if (fr_pair_list_copy(ctx, out, &vp->vp_group) < 0) {
860 err = -4;
861 goto done;
862 }
863 break;
864
865 default:
866 continue;
867 }
868 }
869done:
871
872 return err;
873}
874
875
876/** Returns the first VP matching a #tmpl_t
877 *
878 * @param[out] out where to write the retrieved vp.
879 * @param[in] request The current #request_t.
880 * @param[in] vpt specifying the #fr_pair_t type to find.
881 * Must be one of the following types:
882 * - #TMPL_TYPE_ATTR
883 * @return
884 * - 0 on success (found matching #fr_pair_t).
885 * - -1 if no matching #fr_pair_t could be found.
886 * - -2 if list could not be found (doesn't exist in current #request_t).
887 * - -3 if context could not be found (no parent #request_t available).
888 */
890{
891 fr_dcursor_t cursor;
893 fr_pair_t *vp;
894 int err;
895
897
898 vp = tmpl_dcursor_init(&err, request, &cc, &cursor, request, vpt);
900
901 if (out) *out = vp;
902
903 return err;
904}
905
906/** Returns the first VP matching a #tmpl_t, or if no VPs match, creates a new one.
907 *
908 * @param[out] out where to write the retrieved or created vp.
909 * @param[in] request The current #request_t.
910 * @param[in] vpt specifying the #fr_pair_t type to retrieve or create. Must be #TMPL_TYPE_ATTR.
911 * @return
912 * - 1 on success a pair was created.
913 * - 0 on success a pair was found.
914 * - -1 if a new #fr_pair_t couldn't be found or created.
915 * - -2 if list could not be found (doesn't exist in current #request_t).
916 * - -3 if context could not be found (no parent #request_t available).
917 */
919{
920 fr_dcursor_t cursor;
922 fr_pair_t *vp;
923 int err;
924
927
928 *out = NULL;
929
930 vp = tmpl_dcursor_init(&err, NULL, &cc, &cursor, request, vpt);
932
933 switch (err) {
934 case 0:
935 *out = vp;
936 return 0;
937
938 case -1:
939 {
940 TALLOC_CTX *ctx;
942
943 tmpl_pair_list_and_ctx(ctx, head, request, tmpl_request(vpt), tmpl_list(vpt));
944 if (!head) return -1;
945
946 if (pair_append_by_tmpl_parent(ctx, &vp, head, vpt, true) < 0) return -1;
947
948 *out = vp;
949 }
950 return 1;
951
952 default:
953 return err;
954 }
955}
956
957/** Allocate and insert a leaf vp from a tmpl_t, building the parent vps if needed.
958 *
959 * This is the simple case - just add a vp at the first place where
960 * the parents exist, or create the parents, with no attempt to handle filters.
961 *
962 * It is functionally equivalent to fr_pair_append_by_da_parent() but
963 * uses a tmpl_t to build the nested structure rather than a fr_dict_attr_t.
964 *
965 * @param[in] ctx to allocate new pair(s) in
966 * @param[out] out Leaf pair we allocated.
967 * @param[in] list to insert into.
968 * @param[in] vpt tmpl representing the attribute to add.
969 * @param[in] skip_list skip list attr ref at the head of the tmpl.
970 * @return
971 * - 0 on success.
972 * - -1 on failure.
973 */
974int pair_append_by_tmpl_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, tmpl_t const *vpt, bool skip_list)
975{
976 fr_pair_t *vp = NULL;
977 TALLOC_CTX *pair_ctx = ctx;
978 tmpl_attr_t *ar, *leaf;
979 tmpl_attr_list_head_t const *ar_list = &vpt->data.attribute.ar;
980
981 if (!tmpl_is_attr(vpt)) {
982 error:
983 *out = NULL;
984 return -1;
985 }
986
987 leaf = tmpl_attr_list_tail(ar_list);
988 ar = tmpl_attr_list_head(ar_list);
989 if (!ar) goto error;
990 if (skip_list && tmpl_attr_is_list_attr(ar)) ar = tmpl_attr_list_next(ar_list, ar);
991
992 /*
993 * Walk down the tmpl ar stack looking for candidate parent
994 * attributes and then allocating the leaf.
995 */
996 while (true) {
997 if (unlikely(!ar)) goto error;
998 /*
999 * We're not at the leaf, look for a potential parent
1000 */
1001 if (ar != leaf) {
1002 vp = fr_pair_find_by_da(list, NULL, ar->da);
1003 /*
1004 * HACK - Pretend we didn't see this stupid key field
1005 *
1006 * If we don't have this, the code creates a key pair
1007 * and then horribly mangles its data by adding children
1008 * to it.
1009 *
1010 * We just skip one level down an don't create or update
1011 * the key pair.
1012 */
1013 if (vp && fr_dict_attr_is_key_field(ar->da) && fr_type_is_leaf(vp->data.type)) {
1014 ar = tmpl_attr_list_next(ar_list, ar);
1015 continue;
1016 }
1017 }
1018 /*
1019 * Nothing found, create the pair
1020 */
1021 if (!vp) {
1022 if (fr_pair_append_by_da(pair_ctx, &vp, list, ar->da) < 0) goto error;
1023 }
1024
1025 /*
1026 * We're at the leaf, return
1027 */
1028 if (ar == leaf) {
1029 *out = vp;
1030 return 0;
1031 }
1032
1033 /*
1034 * Prepare for next level
1035 */
1036 list = &vp->vp_group;
1037 pair_ctx = vp;
1038 vp = NULL;
1039 ar = tmpl_attr_list_next(ar_list, ar);
1040 }
1041}
1042
1043/** Insert a value-box to a list, with casting.
1044 *
1045 * @param list to append to
1046 * @param box box to cast / append
1047 * @param vpt tmpl with cast.
1048 * @return
1049 * - <0 for "cast failed"
1050 * - 0 for success
1051 */
1052int tmpl_value_list_insert_tail(fr_value_box_list_t *list, fr_value_box_t *box, tmpl_t const *vpt)
1053{
1055 (box->type == tmpl_rules_cast(vpt))) {
1056 fr_value_box_list_insert_tail(list, box);
1057 return 0;
1058 }
1059
1060 if (fr_value_box_cast_in_place(box, box, tmpl_rules_cast(vpt), tmpl_rules_enumv(vpt)) < 0) return -1;
1061
1062 fr_value_box_list_insert_tail(list, box);
1064 return 0;
1065}
1066
1067/** Gets the value of a real or virtual attribute
1068 *
1069 * @param[in] ctx to allocate boxed value, and buffers in.
1070 * @param[out] out Where to write the boxed value.
1071 * @param[in] request The current request.
1072 * @param[in] vpt Representing the attribute.
1073 * @return
1074 * - <0 we failed getting a value for the attribute.
1075 * - 0 we successfully evaluated the tmpl
1076 */
1077int tmpl_eval_pair(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
1078{
1079 fr_pair_t *vp = NULL;
1081
1082 fr_dcursor_t cursor;
1084
1085 int ret = 0;
1086 fr_value_box_list_t list;
1087
1089
1090 fr_value_box_list_init(&list);
1091
1092 /*
1093 * See if we're dealing with an attribute in the request
1094 *
1095 * This allows users to manipulate virtual attributes as if
1096 * they were real ones.
1097 */
1098 vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt);
1099
1100 /*
1101 * We didn't find the VP in a list, check to see if it's
1102 * virtual. This allows the caller to "realize" the
1103 * attribute, and we then prefer the realized version to
1104 * the virtual one.
1105 */
1106 if (!vp) {
1107 /*
1108 * Zero count.
1109 */
1112 if (!value) {
1113 oom:
1114 fr_strerror_const("Out of memory");
1115 ret = -1;
1116 goto fail;
1117 }
1118 value->datum.int32 = 0;
1119 fr_value_box_list_insert_tail(&list, value);
1120 } /* Fall through to being done */
1121
1122 goto done;
1123 }
1124
1125 switch (tmpl_attr_tail_num(vpt)) {
1126 /*
1127 * Return a count of the VPs.
1128 */
1129 case NUM_COUNT:
1130 {
1131 uint32_t count = 0;
1132
1133 while (vp != NULL) {
1134 count++;
1135 vp = fr_dcursor_next(&cursor);
1136 }
1137
1139 if (!value) goto oom;
1140 value->datum.uint32 = count;
1141 fr_value_box_list_insert_tail(&list, value);
1142 break;
1143 }
1144
1145 /*
1146 * Output multiple #value_box_t, one per attribute.
1147 */
1148 case NUM_ALL:
1149 /*
1150 * Loop over all matching #fr_value_pair
1151 * shallow copying buffers.
1152 */
1153 while (vp != NULL) {
1154 if (fr_type_is_structural(vp->vp_type)) {
1156 if (!value) goto oom;
1157
1158 if (fr_pair_list_copy_to_box(value, &vp->vp_group) < 0) {
1160 goto oom;
1161 }
1162
1163 } else {
1164 value = fr_value_box_alloc(ctx, vp->data.type, vp->da);
1165 if (!value) goto oom;
1166 fr_value_box_copy(value, value, &vp->data);
1167 }
1168
1169 fr_value_box_list_insert_tail(&list, value);
1170 vp = fr_dcursor_next(&cursor);
1171 }
1172 break;
1173
1174 default:
1175 if (!fr_type_is_leaf(vp->vp_type)) {
1176 fr_strerror_const("Invalid data type for evaluation");
1177 goto fail;
1178 }
1179
1180 value = fr_value_box_alloc(ctx, vp->data.type, vp->da);
1181 if (!value) goto oom;
1182
1183 fr_value_box_copy(value, value, &vp->data); /* Also dups taint */
1184 fr_value_box_list_insert_tail(&list, value);
1185 break;
1186 }
1187
1188done:
1189 /*
1190 * Evaluate casts if necessary.
1191 */
1192 if (ret == 0) {
1193 if (tmpl_eval_cast_in_place(&list, request, vpt) < 0) {
1194 fr_value_box_list_talloc_free(&list);
1195 ret = -1;
1196 goto fail;
1197 }
1198
1199 fr_value_box_list_move(out, &list);
1200 }
1201
1202fail:
1203 tmpl_dcursor_clear(&cc);
1205 return ret;
1206}
1207
1208
1209/** Gets the value of a tmpl
1210 *
1211 * The result is returned "raw". The caller must do any escaping it desires.
1212 *
1213 * @param[in] ctx to allocate boxed value, and buffers in.
1214 * @param[out] out Where to write the boxed value.
1215 * @param[in] request The current request.
1216 * @param[in] vpt Representing the tmpl
1217 * @return
1218 * - <0 we failed getting a value for the tmpl
1219 * - 0 we successfully evaluated the tmpl
1220 */
1221int tmpl_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
1222{
1223 char *p;
1225 fr_value_box_list_t list;
1226
1228 fr_strerror_const("Cannot evaluate unresolved tmpl");
1229 return -1;
1230 }
1231
1232 if (tmpl_async_required(vpt)) {
1233 fr_strerror_const("Cannot statically evaluate asynchronous expansions");
1234 return -1;
1235 }
1236
1237 if (tmpl_contains_regex(vpt)) {
1238 fr_strerror_const("Cannot statically evaluate regular expression");
1239 return -1;
1240 }
1241
1242 if (tmpl_is_attr(vpt)) {
1243 return tmpl_eval_pair(ctx, out, request, vpt);
1244 }
1245
1246 if (tmpl_is_data(vpt)) {
1248
1249 fr_value_box_copy(value, value, tmpl_value(vpt)); /* Also dups taint */
1250 goto done;
1251 }
1252
1254
1255 /*
1256 * @todo - respect escaping functions. But the sync
1257 * escaping uses a different method than the async ones.
1258 * And we then also need to escape the output of
1259 * tmpl_eval_pair(), too.
1260 */
1262 if (tmpl_aexpand(value, &p, request, vpt, NULL, NULL) < 0) {
1264 return -1;
1265 }
1266 fr_value_box_bstrndup_shallow(value, NULL, p, talloc_array_length(p) - 1, true);
1267
1268 /*
1269 * Cast the results if necessary.
1270 */
1271done:
1272 fr_value_box_list_init(&list);
1273 fr_value_box_list_insert_tail(&list, value);
1274
1275 if (tmpl_eval_cast_in_place(&list, request, vpt) < 0) {
1276 fr_value_box_list_talloc_free(&list);
1277 return -1;
1278 }
1279
1280 fr_value_box_list_move(out, &list);
1282
1283 return 0;
1284}
1285
1286/** Allocate a uctx for an escaping function
1287 *
1288 * @param[in] request The current request.
1289 * @param[in] escape Describing how to escape tmpl data.
1290 *
1291 * @return the uctx to pass to the escape function.
1292 */
1293static inline void *tmpl_eval_escape_uctx_alloc(request_t *request, tmpl_escape_t const *escape)
1294{
1295 switch (escape->uctx.type) {
1297 return UNCONST(void *, escape->uctx.ptr);
1298
1300 {
1301 void *uctx;
1302
1303 fr_assert_msg(escape->uctx.size > 0, "TMPL_ESCAPE_UCTX_ALLOC must specify uctx.size > 0");
1304 MEM(uctx = talloc_zero_array(NULL, uint8_t, escape->uctx.size));
1305 if (escape->uctx.talloc_type) talloc_set_type(uctx, escape->uctx.talloc_type);
1306 return uctx;
1307 }
1308
1310 fr_assert_msg(escape->uctx.func.alloc, "TMPL_ESCAPE_UCTX_ALLOC_FUNC must specify a non-null alloc.func");
1311 return escape->uctx.func.alloc(request, escape->uctx.func.uctx);
1312
1313 default:
1314 fr_assert_msg(0, "Unknown escape uctx type %u", escape->uctx.type);
1315 return NULL;
1316 }
1317}
1318
1319/** Free a uctx for an escaping function
1320 *
1321 * @param[in] escape Describing how to escape tmpl data.
1322 * @param[in] uctx The uctx to free.
1323 */
1324static inline void tmpl_eval_escape_uctx_free(tmpl_escape_t const *escape, void *uctx)
1325{
1326 switch (escape->uctx.type) {
1328 return;
1329
1331 talloc_free(uctx);
1332 return;
1333
1335 if (escape->uctx.func.free) escape->uctx.func.free(uctx);
1336 return;
1337 }
1338}
1339
1340/** Casts a value or list of values according to the tmpl
1341 *
1342 * @param[in,out] list Where to write the boxed value.
1343 * @param[in] request The current request.
1344 * @param[in] vpt Representing the attribute.
1345 * @return
1346 * - <0 the cast failed
1347 * - 0 we successfully evaluated the tmpl
1348 */
1349int tmpl_eval_cast_in_place(fr_value_box_list_t *list, request_t *request, tmpl_t const *vpt)
1350{
1352 bool did_concat = false;
1353 void *uctx = NULL;
1354
1355 if (fr_type_is_structural(cast)) {
1356 fr_strerror_printf("Cannot cast to structural type '%s'", fr_type_to_str(cast));
1357 return -1;
1358 }
1359
1360 /*
1361 * Quoting around the tmpl means everything
1362 * needs to be concatenated, either as a string
1363 * or octets string.
1364 */
1365 switch (vpt->quote) {
1370 {
1371 ssize_t slen;
1372 fr_value_box_t *vb;
1373
1374 vb = fr_value_box_list_head(list);
1375 if (!vb) return 0;
1376
1378 uctx = tmpl_eval_escape_uctx_alloc(request, &vpt->rules.escape);
1379 /*
1380 * Sets escaped values, so boxes don't get re-escaped
1381 */
1382 if (unlikely(fr_value_box_list_escape_in_place(list, vpt->rules.escape.func,
1383 vpt->rules.escape.safe_for, uctx) < 0)) {
1384 error:
1385 tmpl_eval_escape_uctx_free(&vpt->rules.escape, uctx);
1386 return -1;
1387 }
1388 }
1389
1391 FR_VALUE_BOX_LIST_FREE_BOX, true, SIZE_MAX);
1392 if (slen < 0) goto error;
1394
1395 /*
1396 * If there's no cast, or it's a cast to
1397 * a string, we're done!
1398 *
1399 * Otherwise we now need to re-cast the
1400 * result.
1401 */
1402 if (fr_type_is_null(cast) || fr_type_is_string(cast)) {
1403 success:
1404 tmpl_eval_escape_uctx_free(&vpt->rules.escape, uctx);
1405 return 0;
1406 }
1407
1408 did_concat = true;
1409 }
1410 break;
1411
1412 default:
1413 break;
1414 }
1415
1416 if (fr_type_is_null(cast)) goto success;
1417
1418 /*
1419 * Quoting above handled all concatenation,
1420 * we now need to handle potentially
1421 * multivalued lists.
1422 */
1424 if (fr_value_box_cast_in_place(vb, vb, cast, NULL) < 0) goto error;
1425 }}
1426
1427 /*
1428 * ...and finally, apply the escape function
1429 * if necessary. This is done last so that
1430 * the escape function gets boxes of the type
1431 * it expects.
1432 */
1434 uctx = tmpl_eval_escape_uctx_alloc(request, &vpt->rules.escape);
1435 if (unlikely(fr_value_box_list_escape_in_place(list, vpt->rules.escape.func,
1436 vpt->rules.escape.safe_for, uctx) < 0)) goto error;
1437 }
1438
1439 /*
1440 * If there's no escape function, but there is
1441 * an escaped value, mark all the boxes up with
1442 * this value.
1443 *
1444 * This is mostly useful for call_env usage in
1445 * modules where certain values are implicitly safe
1446 * for consumption, like SQL statements in the SQL
1447 * module.
1448 */
1449 if (!vpt->rules.escape.func && vpt->rules.escape.safe_for) {
1450 fr_value_box_list_mark_safe_for(list, vpt->rules.escape.safe_for);
1451 }
1452
1454
1456}
1457
1458static int _tmpl_global_free(UNUSED void *uctx)
1459{
1461
1463
1464 return 0;
1465}
1466
1467static int _tmpl_global_init(UNUSED void *uctx)
1468{
1469 fr_dict_attr_t *da;
1470
1471 if (fr_dict_autoload(tmpl_dict) < 0) {
1472 PERROR("%s", __FUNCTION__);
1473 return -1;
1474 }
1475
1477 fr_assert(da != NULL);
1478
1479 da->type = FR_TYPE_NULL;
1480 tmpl_attr_unspec = da;
1481
1482 return 0;
1483}
1484
1486{
1487 int ret;
1488
1489 fr_atexit_global_once_ret(&ret, _tmpl_global_init, _tmpl_global_free, NULL);
1490
1491 return 0;
1492}
static int context
Definition radmin.c:71
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:483
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
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:210
#define MEM(x)
Definition debug.h:36
#define fr_dict_autofree(_to_free)
Definition dict.h:853
static fr_slen_t err
Definition dict.h:824
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:580
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2400
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:281
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
#define fr_dict_autoload(_to_load)
Definition dict.h:850
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:153
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:280
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:1122
#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.
#define PERROR(_fmt,...)
Definition log.h:228
#define RWDEBUG2(fmt,...)
Definition log.h:362
#define RPEDEBUG(fmt,...)
Definition log.h:376
#define RDEBUG4(fmt,...)
Definition log.h:344
talloc_free(reap)
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_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_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:1466
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:2319
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:693
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:1345
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:489
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:2354
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:80
#define RDEBUG2(fmt,...)
Definition radclient.h:54
fr_dict_attr_t const * request_attr_request
Definition request.c:45
fr_dict_attr_t const * request_attr_control
Definition request.c:47
fr_dict_attr_t const * request_attr_local
Definition request.c:49
fr_dict_attr_t const * request_attr_state
Definition request.c:48
fr_dict_attr_t const * request_attr_reply
Definition request.c:46
#define FR_SBUFF_IN(_start, _len_or_end)
static int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
Return the last attribute reference's attribute number.
Definition tmpl.h:896
#define TMPL_VERIFY(_vpt)
Definition tmpl.h:969
#define tmpl_is_xlat(vpt)
Definition tmpl.h:215
#define tmpl_rules_enumv(_tmpl)
Definition tmpl.h:954
static fr_slen_t vpt
Definition tmpl.h:1272
#define tmpl_value(_tmpl)
Definition tmpl.h:948
#define tmpl_contains_regex(vpt)
Definition tmpl.h:230
#define tmpl_is_attr(vpt)
Definition tmpl.h:213
#define NUM_ALL
Definition tmpl.h:400
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:941
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
Definition tmpl.h:915
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:690
#define tmpl_rules_cast(_tmpl)
Definition tmpl.h:953
@ TMPL_TYPE_REGEX_UNCOMPILED
Regex where compilation is possible but hasn't been performed yet.
Definition tmpl.h:162
@ TMPL_TYPE_MAX
Marker for the last tmpl type.
Definition tmpl.h:203
@ TMPL_TYPE_ATTR_UNRESOLVED
An attribute reference that we couldn't resolve but looked valid.
Definition tmpl.h:189
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
Definition tmpl.h:146
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
Definition tmpl.h:150
@ TMPL_TYPE_NULL
Has no value.
Definition tmpl.h:138
@ TMPL_TYPE_EXEC
Callout to an external script or program.
Definition tmpl.h:154
@ TMPL_TYPE_REGEX_XLAT_UNRESOLVED
A regular expression with unresolved xlat functions or attribute references.
Definition tmpl.h:201
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition tmpl.h:142
@ TMPL_TYPE_REGEX
Compiled (and possibly JIT'd) regular expression.
Definition tmpl.h:158
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
Definition tmpl.h:183
@ TMPL_TYPE_XLAT_UNRESOLVED
A xlat expansion with unresolved xlat functions or attribute references.
Definition tmpl.h:197
@ TMPL_TYPE_REGEX_XLAT
A regex containing xlat expansions.
Definition tmpl.h:166
@ TMPL_TYPE_EXEC_UNRESOLVED
An exec with unresolved xlat function or attribute references.
Definition tmpl.h:193
@ TMPL_TYPE_UNINITIALISED
Uninitialised.
Definition tmpl.h:134
#define NUM_COUNT
Definition tmpl.h:401
#define tmpl_pair_list_and_ctx(_ctx, _head, _request, _ref, _list)
Determine the correct context and list head.
Definition tmpl.h:1001
#define tmpl_is_data(vpt)
Definition tmpl.h:211
#define tmpl_value_type(_tmpl)
Definition tmpl.h:950
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:812
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:926
@ REQUEST_OUTER
request_t containing the outer layer of the EAP conversation.
Definition tmpl.h:92
@ REQUEST_PARENT
Parent (whatever it is).
Definition tmpl.h:96
@ REQUEST_UNKNOWN
Unknown request.
Definition tmpl.h:97
@ REQUEST_CURRENT
The current request (default).
Definition tmpl.h:91
#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:1070
#define tmpl_needs_resolving(vpt)
Definition tmpl.h:228
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
return count
Definition module.c:163
fr_pair_t * vp
An element in a list of nested attribute references.
Definition tmpl.h:439
fr_dict_attr_t const *_CONST da
Resolved dictionary attribute.
Definition tmpl.h:443
Define manipulation functions for the attribute reference list.
Definition tmpl.h:480
tmpl_request_ref_t _CONST request
Definition tmpl.h:484
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
Functions which we wish were included in the standard talloc distribution.
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.
fr_value_box_escape_t func
How to escape when returned from evaluation.
Definition tmpl_escape.h:81
#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::@74 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:889
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:146
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:1052
fr_dict_attr_t const * tmpl_attr_unspec
Placeholder attribute for uses of unspecified attribute references.
Definition tmpl_eval.c:61
static int _tmpl_global_free(UNUSED void *uctx)
Definition tmpl_eval.c:1458
static fr_dict_t const * dict_freeradius
Definition tmpl_eval.c:48
static fr_dict_t const * dict_radius
Definition tmpl_eval.c:49
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:169
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:1221
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:1349
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:76
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:116
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:563
int tmpl_global_init(void)
Definition tmpl_eval.c:1485
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:1077
ssize_t _tmpl_to_type(void *out, uint8_t *buff, size_t bufflen, request_t *request, tmpl_t const *vpt, xlat_escape_legacy_t escape, void const *escape_ctx, fr_type_t dst_type)
Expand a tmpl_t to a string writing the result to a buffer.
Definition tmpl_eval.c:284
goto success
Definition tmpl_eval.c:1455
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:841
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:798
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:1324
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:918
static int _tmpl_global_init(UNUSED void *uctx)
Definition tmpl_eval.c:1467
fr_dict_autoload_t tmpl_dict[]
Definition tmpl_eval.c:52
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:1293
fr_type_t tmpl_expanded_type(tmpl_t const *vpt)
Return the native data type of the expression.
Definition tmpl_eval.c:209
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:974
@ T_SINGLE_QUOTED_STRING
Definition token.h:122
@ T_BARE_WORD
Definition token.h:120
@ T_BACK_QUOTED_STRING
Definition token.h:123
@ T_DOUBLE_QUOTED_STRING
Definition token.h:121
@ T_SOLIDUS_QUOTED_STRING
Definition token.h:124
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:1546
static fr_slen_t head
Definition xlat.h:422
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:1563
ssize_t xlat_aeval(TALLOC_CTX *ctx, char **out, request_t *request, char const *fmt, xlat_escape_legacy_t escape, void const *escape_ctx))
Definition xlat_eval.c:1554
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_structural(_x)
Definition types.h:371
#define fr_type_is_string(_x)
Definition types.h:327
#define FR_TYPE_STRUCTURAL
Definition types.h:296
#define fr_type_is_null(_x)
Definition types.h:326
#define fr_type_is_leaf(_x)
Definition types.h:372
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
size_t const fr_value_box_field_sizes[]
How many bytes wide each of the value data fields are.
Definition value.c:149
ssize_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, bool tainted)
Definition value.c:5315
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:3953
int fr_value_box_list_escape_in_place(fr_value_box_list_t *list, fr_value_box_escape_t escape, fr_value_box_safe_for_t safe_for, void *uctx)
Escape a list of value boxes in place.
Definition value.c:5982
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:3352
size_t const fr_value_box_offsets[]
Where the value starts in the fr_value_box_t.
Definition value.c:189
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:3740
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:3572
void fr_value_box_memdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Assign a buffer to a box, but don't copy it.
Definition value.c:4548
void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
Perform a shallow copy of a value_box.
Definition value.c:3834
size_t fr_value_str_unescape(fr_sbuff_t *out, fr_sbuff_t *in, size_t inlen, char quote)
Convert a string value with escape sequences into its binary form.
Definition value.c:1128
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:6313
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:4036
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:4071
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:3858
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:4232
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:5777
@ FR_VALUE_BOX_LIST_FREE_BOX
Free each processed box.
Definition value.h:218
#define fr_value_box_list_foreach_safe(_list_head, _iter)
Definition value.h:207
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:621
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:764
#define vb_length
Definition value.h:272
#define FR_VALUE_BOX_INITIALISER_NULL(_vb)
A static initialiser for stack/globally allocated boxes.
Definition value.h:488
#define VALUE_BOX_VERIFY(_x)
Definition value.h:1295
#define VALUE_BOX_LIST_VERIFY(_x)
Definition value.h:1296
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:632
static size_t char ** out
Definition value.h:997