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: 48d680eec63a58da11c3aedef1b77c409fb562e6 $
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: 48d680eec63a58da11c3aedef1b77c409fb562e6 $")
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... */
49 { NULL }
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 * @param[in] bufflen Length of expansion buffer. Must be >= 2.
264 * @param[in] request Current request.
265 * @param[in] vpt to expand. Must be one of the following types:
266 * - #TMPL_TYPE_DATA_UNRESOLVED
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 = &value_to_cast;
285 fr_value_box_t const *from_cast = &value_from_cast;
286
287 fr_pair_t *vp = NULL;
288
289 fr_type_t src_type = FR_TYPE_NULL;
290
291 ssize_t slen = -1; /* quiet compiler */
292
294
295 fr_assert(!buff || (bufflen >= 2));
296
297 switch (vpt->type) {
299 RDEBUG4("EXPAND TMPL UNRESOLVED");
300 fr_value_box_bstrndup_shallow(&value_to_cast, NULL, vpt->name, vpt->len, false);
301 src_type = FR_TYPE_STRING;
302 break;
303
304 case TMPL_TYPE_EXEC:
305 {
306 RDEBUG4("EXPAND TMPL EXEC");
307 if (!buff) {
308 fr_strerror_const("Missing expansion buffer for EXEC");
309 return -1;
310 }
311
312 if (radius_exec_program_legacy((char *)buff, bufflen, request, vpt->name, NULL,
313 true, false, fr_time_delta_from_sec(EXEC_TIMEOUT)) != 0) return -1;
314 fr_value_box_strdup_shallow(&value_to_cast, NULL, (char *)buff, true);
315 src_type = FR_TYPE_STRING;
316 }
317 break;
318
319 case TMPL_TYPE_XLAT:
320 {
321 RDEBUG4("EXPAND TMPL XLAT PARSED");
322
323 /* No EXPAND <xlat> here as the xlat code does it */
324
325 if (!buff) {
326 fr_strerror_const("Missing expansion buffer for XLAT_STRUCT");
327 return -1;
328 }
329 /* Error in expansion, this is distinct from zero length expansion */
330 slen = xlat_eval_compiled((char *)buff, bufflen, request, tmpl_xlat(vpt), NULL, NULL);
331 if (slen < 0) return slen;
332
333 fr_value_box_bstrndup_shallow(&value_to_cast, NULL, (char *)buff, slen, true);
334 src_type = FR_TYPE_STRING;
335 }
336 break;
337
338 case TMPL_TYPE_ATTR:
339 {
340 int ret;
341
342 RDEBUG4("EXPAND TMPL ATTR");
343 ret = tmpl_find_vp(&vp, request, vpt);
344 if (ret < 0) return -2;
345
346 to_cast = &vp->data;
347 src_type = vp->vp_type;
348 }
349 break;
350
351 case TMPL_TYPE_DATA:
352 RDEBUG4("EXPAND TMPL DATA");
353 to_cast = tmpl_value(vpt);
354 src_type = tmpl_value_type(vpt);
355 break;
356
357 /*
358 * We should never be expanding these.
359 */
364 case TMPL_TYPE_REGEX:
368 case TMPL_TYPE_MAX:
369 fr_assert(0);
370 return -1;
371 }
372
373 /*
374 * Deal with casts.
375 */
376 switch (src_type) {
377 case FR_TYPE_STRING:
378 switch (dst_type) {
379 case FR_TYPE_STRING:
380 case FR_TYPE_OCTETS:
381 from_cast = to_cast;
382 break;
383
384 default:
385 break;
386 }
387 break;
388
389 case FR_TYPE_OCTETS:
390 switch (dst_type) {
391 /*
392 * Need to use the expansion buffer for this conversion as
393 * we need to add a \0 terminator.
394 */
395 case FR_TYPE_STRING:
396 if (!buff) {
397 fr_strerror_const("Missing expansion buffer for octet->string cast");
398 return -1;
399 }
400 if (bufflen <= to_cast->vb_length) {
401 fr_strerror_printf("Expansion buffer too small. "
402 "Have %zu bytes, need %zu bytes", bufflen,
403 to_cast->vb_length + 1);
404 return -1;
405 }
406 memcpy(buff, to_cast->vb_octets, to_cast->vb_length);
407 buff[to_cast->vb_length] = '\0';
408
409 fr_value_box_bstrndup_shallow(&value_from_cast, NULL,
410 (char *)buff, to_cast->vb_length, true);
411 break;
412
413 /*
414 * Just copy the pointer. Length does not include \0.
415 */
416 case FR_TYPE_OCTETS:
417 from_cast = to_cast;
418 break;
419
420 default:
421 break;
422 }
423 break;
424
425 default:
426 {
427 int ret;
428 TALLOC_CTX *ctx;
429
430 /*
431 * Same type, just set from_cast to to_cast and copy the value.
432 */
433 if (src_type == dst_type) {
434 from_cast = to_cast;
435 break;
436 }
437
438 MEM(ctx = talloc_new(request));
439
440 from_cast = &value_from_cast;
441
442 /*
443 * Data type conversion...
444 */
445 ret = fr_value_box_cast(ctx, &value_from_cast, dst_type, NULL, to_cast);
446 if (ret < 0) goto error;
447
448
449 /*
450 * For the dynamic types we need to copy the output
451 * to the buffer. Really we need a version of fr_value_box_cast
452 * that works with buffers, but it's not a high priority...
453 */
454 switch (dst_type) {
455 case FR_TYPE_STRING:
456 if (!buff) {
457 fr_strerror_const("Missing expansion buffer to store cast output");
458 error:
459 talloc_free(ctx);
460 return -1;
461 }
462 if (from_cast->vb_length >= bufflen) {
463 fr_strerror_printf("Expansion buffer too small. "
464 "Have %zu bytes, need %zu bytes", bufflen,
465 from_cast->vb_length + 1);
466 goto error;
467 }
468 memcpy(buff, from_cast->vb_strvalue, from_cast->vb_length);
469 buff[from_cast->vb_length] = '\0';
470
471 fr_value_box_bstrndup_shallow(&value_from_cast, NULL,
472 (char *)buff, from_cast->vb_length, from_cast->tainted);
473 break;
474
475 case FR_TYPE_OCTETS:
476 if (!buff) {
477 fr_strerror_const("Missing expansion buffer to store cast output");
478 goto error;
479 }
480 if (from_cast->vb_length > bufflen) {
481 fr_strerror_printf("Expansion buffer too small. "
482 "Have %zu bytes, need %zu bytes", bufflen, from_cast->vb_length);
483 goto error;
484 }
485 memcpy(buff, from_cast->vb_octets, from_cast->vb_length);
486 fr_value_box_memdup_shallow(&value_from_cast, NULL,
487 buff, from_cast->vb_length, from_cast->tainted);
488 break;
489
490 default:
491 break;
492 }
493
494 talloc_free(ctx); /* Free any dynamically allocated memory from the cast */
495 }
496 }
497
498 RDEBUG4("Copying %zu bytes to %p from offset %zu",
500
501 fr_value_box_memcpy_out(out, from_cast);
502
503 return from_cast->vb_length;
504}
505
506/** Expand a template to a string, allocing a new buffer to hold the string
507 *
508 * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #tmpl_t
509 * provided by the conf parser, into a usable value.
510 * The value returned should be raw and undoctored for #FR_TYPE_STRING and #FR_TYPE_OCTETS types,
511 * and the printable (string) version of the data for all others.
512 *
513 * This function will always duplicate values, whereas #tmpl_expand may return a pointer to an
514 * existing buffer.
515 *
516 * @note This function is used where raw string values are needed, which may mean the string
517 * returned may be binary data or contain unprintable chars. #fr_snprint or #fr_asprint should
518 * be used before using these values in debug statements. #is_printable can be used to check
519 * if the string only contains printable chars.
520 *
521 * @note The type (char or uint8_t) can be obtained with talloc_get_type, and may be used as a
522 * hint as to how to process or print the data.
523 *
524 * @param ctx to allocate new buffer in.
525 * @param out Where to write pointer to the new buffer.
526 * @param request Current request.
527 * @param vpt to expand. Must be one of the following types:
528 * - #TMPL_TYPE_DATA_UNRESOLVED
529 * - #TMPL_TYPE_EXEC
530 * - #TMPL_TYPE_XLAT
531 * - #TMPL_TYPE_ATTR
532 * - #TMPL_TYPE_DATA
533 * @param escape xlat escape function (only used for TMPL_TYPE_XLAT_UNRESOLVED_* types).
534 * @param escape_ctx xlat escape function data (only used for TMPL_TYPE_XLAT_UNRESOLVED_* types).
535 * @param dst_type FR_TYPE_* matching out pointer. @see tmpl_aexpand.
536 * @return
537 * - -1 on failure.
538 * - The length of data written to buff, or pointed to by out.
539 */
540ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out,
541 request_t *request,
542 tmpl_t const *vpt,
543 xlat_escape_legacy_t escape, void const *escape_ctx,
544 fr_type_t dst_type)
545{
546 fr_value_box_t *to_cast = NULL;
547 fr_value_box_t from_cast;
548
549 fr_pair_t *vp = NULL;
551 bool needs_dup = false;
552
553 ssize_t slen = -1;
554 int ret;
555
556 TALLOC_CTX *tmp_ctx = talloc_new(ctx);
557
559
560 switch (vpt->type) {
562 RDEBUG4("EXPAND TMPL DATA UNRESOLVED");
563
564 fr_value_box_bstrndup_shallow(&value, NULL, vpt->name, vpt->len, false);
565 to_cast = &value;
566 needs_dup = true;
567 break;
568
569 case TMPL_TYPE_EXEC:
570 {
571 char *buff;
572
573 RDEBUG4("EXPAND TMPL EXEC");
574
575 MEM(fr_value_box_bstr_alloc(tmp_ctx, &buff, &value, NULL, 1024, true));
576 if (radius_exec_program_legacy(buff, 1024, request, vpt->name, NULL,
577 true, false, fr_time_delta_from_sec(EXEC_TIMEOUT)) != 0) {
578 error:
579 talloc_free(tmp_ctx);
580 return slen;
581 }
582 fr_value_box_strtrim(tmp_ctx, &value);
583 to_cast = &value;
584 }
585 break;
586
588 {
589 fr_value_box_t tmp;
590 fr_type_t src_type = FR_TYPE_STRING;
591 char *result;
592
593 RDEBUG4("EXPAND TMPL XLAT");
594
595 /* Error in expansion, this is distinct from zero length expansion */
596 slen = xlat_aeval(tmp_ctx, &result, request, vpt->name, escape, escape_ctx);
597 if (slen < 0) goto error;
598
599 /*
600 * Undo any of the escaping that was done by the
601 * xlat expansion function.
602 *
603 * @fixme We need a way of signalling xlat not to escape things.
604 */
605 ret = fr_value_box_from_str(tmp_ctx, &tmp, src_type, NULL,
606 result, (size_t)slen,
607 NULL);
608 if (ret < 0) {
609 RPEDEBUG("Failed parsing %.*s", (int) slen, result);
610 goto error;
611 }
612
613 fr_value_box_bstrndup_shallow(&value, NULL, tmp.vb_strvalue, tmp.vb_length, tmp.tainted);
614 to_cast = &value;
615 }
616 break;
617
618 case TMPL_TYPE_XLAT:
620 {
621 fr_value_box_t tmp;
622 fr_type_t src_type = FR_TYPE_STRING;
623 char *result;
624
625 RDEBUG4("EXPAND TMPL XLAT STRUCT");
626 /* No EXPAND xlat here as the xlat code does it */
627
628 /* Error in expansion, this is distinct from zero length expansion */
629 slen = xlat_aeval_compiled(tmp_ctx, &result, request, tmpl_xlat(vpt), escape, escape_ctx);
630 if (slen < 0) goto error;
631
632 /*
633 * Undo any of the escaping that was done by the
634 * xlat expansion function.
635 *
636 * @fixme We need a way of signalling xlat not to escape things.
637 */
638 ret = fr_value_box_from_str(tmp_ctx, &tmp, src_type, NULL,
639 result, (size_t)slen,
640 NULL);
641 if (ret < 0) {
642 RPEDEBUG("Failed parsing %.*s", (int) slen, result);
643 goto error;
644 }
645
646 fr_value_box_bstrndup_shallow(&value, NULL, tmp.vb_strvalue, tmp.vb_length, tmp.tainted);
647 to_cast = &value;
648 }
649 break;
650
651 case TMPL_TYPE_ATTR:
652 RDEBUG4("EXPAND TMPL ATTR");
653
654 ret = tmpl_find_vp(&vp, request, vpt);
655 if (ret < 0) {
656 RDEBUG("Failed finding attribute %s", vpt->name);
657 talloc_free(tmp_ctx);
658 return -2;
659 }
660
661 fr_assert(vp);
662
663 to_cast = &vp->data;
664 switch (to_cast->type) {
665 case FR_TYPE_STRING:
666 case FR_TYPE_OCTETS:
667 fr_assert(to_cast->datum.ptr);
668 needs_dup = true;
669 break;
670
671 default:
672 break;
673 }
674 break;
675
676 case TMPL_TYPE_DATA:
677 {
678 RDEBUG4("EXPAND TMPL DATA");
679
680 to_cast = UNCONST(fr_value_box_t *, tmpl_value(vpt));
681 switch (to_cast->type) {
682 case FR_TYPE_STRING:
683 case FR_TYPE_OCTETS:
684 fr_assert(to_cast->datum.ptr);
685 needs_dup = true;
686 break;
687
688 default:
689 break;
690 }
691 }
692 break;
693
694 /*
695 * We should never be expanding these.
696 */
699 case TMPL_TYPE_REGEX:
703 case TMPL_TYPE_MAX:
704 fr_assert(0);
705 goto error;
706 }
707
708 /*
709 * Special case where we just copy the boxed value
710 * directly instead of casting it.
711 */
712 if (dst_type == FR_TYPE_VALUE_BOX) {
713 fr_value_box_t **vb_out = (fr_value_box_t **)out;
714 fr_type_t cast_type;
715
716 MEM(*vb_out = fr_value_box_alloc_null(ctx));
717
718 cast_type = tmpl_rules_cast(vpt);
719 if (cast_type == FR_TYPE_NULL) {
720 ret = needs_dup ? fr_value_box_copy(*vb_out, *vb_out, to_cast) : fr_value_box_steal(*vb_out, *vb_out, to_cast);
721 } else {
722 ret = fr_value_box_cast(ctx, *vb_out, cast_type, NULL, to_cast);
723 }
724
725 talloc_free(tmp_ctx);
726 if (ret < 0) {
727 RPEDEBUG("Failed copying data to output box");
728 TALLOC_FREE(*vb_out);
729 return -1;
730 }
731 VALUE_BOX_VERIFY(*vb_out);
732 return 0;
733 }
734
735 /*
736 * Don't dup the buffers unless we need to.
737 */
738 if ((to_cast->type != dst_type) || needs_dup) {
739 ret = fr_value_box_cast(ctx, &from_cast, dst_type, NULL, to_cast);
740 if (ret < 0) goto error;
741 } else {
742 switch (to_cast->type) {
743 case FR_TYPE_OCTETS:
744 case FR_TYPE_STRING:
745 /*
746 * Ensure we don't free the output buffer when the
747 * tmp_ctx is freed.
748 */
749 if (value.datum.ptr && (talloc_parent(value.datum.ptr) == tmp_ctx)) {
750 (void)talloc_reparent(tmp_ctx, ctx, value.datum.ptr);
751 }
752 break;
753
754 default:
755 break;
756 }
757 fr_value_box_copy_shallow(NULL, &from_cast, to_cast);
758 }
759
760 RDEBUG4("Copying %zu bytes to %p from offset %zu",
761 fr_value_box_field_sizes[dst_type], *((void **)out), fr_value_box_offsets[dst_type]);
762
763 fr_value_box_memcpy_out(out, &from_cast);
764
765 /*
766 * Frees any memory allocated for temporary buffers
767 * in this function.
768 */
769 talloc_free(tmp_ctx);
770
771 return from_cast.vb_length;
772}
773
774/** Copy pairs matching a #tmpl_t in the current #request_t
775 *
776 * @param ctx to allocate new #fr_pair_t in.
777 * @param out Where to write the copied #fr_pair_t (s).
778 * @param request The current #request_t.
779 * @param vpt specifying the #fr_pair_t type or list to copy.
780 * Must be one of the following types:
781 * - #TMPL_TYPE_ATTR
782 * @return
783 * - -1 if no matching #fr_pair_t could be found.
784 * - -2 if list could not be found (doesn't exist in current #request_t).
785 * - -3 if context could not be found (no parent #request_t available).
786 * - -4 on memory allocation error.
787 */
788int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
789{
790 fr_pair_t *vp;
791 fr_dcursor_t from;
793 int err;
794
796
798
799 for (vp = tmpl_dcursor_init(&err, NULL, &cc, &from, request, vpt);
800 vp;
801 vp = fr_dcursor_next(&from)) {
802 vp = fr_pair_copy(ctx, vp);
803 if (!vp) {
805 fr_strerror_const("Out of memory");
806 err = -4;
807 break;
808 }
810 }
812
813 return err;
814}
815
816
817/** Copy children of pairs matching a #tmpl_t in the current #request_t
818 *
819 * @param ctx to allocate new #fr_pair_t in.
820 * @param out Where to write the copied #fr_pair_t (s).
821 * @param request The current #request_t.
822 * @param vpt specifying the #fr_pair_t type or list to copy.
823 * Must be one of the following types:
824 * - #TMPL_TYPE_ATTR
825 * @return
826 * - -1 if no matching #fr_pair_t could be found.
827 * - -2 if list could not be found (doesn't exist in current #request_t).
828 * - -3 if context could not be found (no parent #request_t available).
829 * - -4 on memory allocation error.
830 */
831int tmpl_copy_pair_children(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
832{
833 fr_pair_t *vp;
834 fr_dcursor_t from;
836 int err;
837
839
841
843
844 for (vp = tmpl_dcursor_init(&err, NULL, &cc, &from, request, vpt);
845 vp;
846 vp = fr_dcursor_next(&from)) {
847 switch (vp->vp_type) {
849 if (fr_pair_list_copy(ctx, out, &vp->vp_group) < 0) {
850 err = -4;
851 goto done;
852 }
853 break;
854
855 default:
856 continue;
857 }
858 }
859done:
861
862 return err;
863}
864
865
866/** Returns the first VP matching a #tmpl_t
867 *
868 * @param[out] out where to write the retrieved vp.
869 * @param[in] request The current #request_t.
870 * @param[in] vpt specifying the #fr_pair_t type to find.
871 * Must be one of the following types:
872 * - #TMPL_TYPE_ATTR
873 * @return
874 * - 0 on success (found matching #fr_pair_t).
875 * - -1 if no matching #fr_pair_t could be found.
876 * - -2 if list could not be found (doesn't exist in current #request_t).
877 * - -3 if context could not be found (no parent #request_t available).
878 */
880{
881 fr_dcursor_t cursor;
883 fr_pair_t *vp;
884 int err;
885
887
888 vp = tmpl_dcursor_init(&err, request, &cc, &cursor, request, vpt);
890
891 if (out) *out = vp;
892
893 return err;
894}
895
896/** Returns the first VP matching a #tmpl_t, or if no VPs match, creates a new one.
897 *
898 * @param[out] out where to write the retrieved or created vp.
899 * @param[in] request The current #request_t.
900 * @param[in] vpt specifying the #fr_pair_t type to retrieve or create. Must be #TMPL_TYPE_ATTR.
901 * @return
902 * - 1 on success a pair was created.
903 * - 0 on success a pair was found.
904 * - -1 if a new #fr_pair_t couldn't be found or created.
905 * - -2 if list could not be found (doesn't exist in current #request_t).
906 * - -3 if context could not be found (no parent #request_t available).
907 */
909{
910 fr_dcursor_t cursor;
912 fr_pair_t *vp;
913 int err;
914
917
918 *out = NULL;
919
920 vp = tmpl_dcursor_init(&err, NULL, &cc, &cursor, request, vpt);
922
923 switch (err) {
924 case 0:
925 *out = vp;
926 return 0;
927
928 case -1:
929 {
930 TALLOC_CTX *ctx;
932
933 tmpl_pair_list_and_ctx(ctx, head, request, tmpl_request(vpt), tmpl_list(vpt));
934 if (!head) return -1;
935
936 if (pair_append_by_tmpl_parent(ctx, &vp, head, vpt, true) < 0) return -1;
937
938 *out = vp;
939 }
940 return 1;
941
942 default:
943 return err;
944 }
945}
946
947/** Allocate and insert a leaf vp from a tmpl_t, building the parent vps if needed.
948 *
949 * This is the simple case - just add a vp at the first place where
950 * the parents exist, or create the parents, with no attempt to handle filters.
951 *
952 * It is functionally equivalent to fr_pair_append_by_da_parent() but
953 * uses a tmpl_t to build the nested structure rather than a fr_dict_attr_t.
954 *
955 * @param[in] ctx to allocate new pair(s) in
956 * @param[out] out Leaf pair we allocated.
957 * @param[in] list to insert into.
958 * @param[in] vpt tmpl representing the attribute to add.
959 * @param[in] skip_list skip list attr ref at the head of the tmpl.
960 * @return
961 * - 0 on success.
962 * - -1 on failure.
963 */
964int pair_append_by_tmpl_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, tmpl_t const *vpt, bool skip_list)
965{
966 fr_pair_t *vp = NULL;
967 TALLOC_CTX *pair_ctx = ctx;
968 tmpl_attr_t *ar, *leaf;
969 tmpl_attr_list_head_t const *ar_list = &vpt->data.attribute.ar;
970
971 if (!tmpl_is_attr(vpt)) {
972 error:
973 *out = NULL;
974 return -1;
975 }
976
977 leaf = tmpl_attr_list_tail(ar_list);
978 ar = tmpl_attr_list_head(ar_list);
979 if (!ar) goto error;
980 if (skip_list && tmpl_attr_is_list_attr(ar)) ar = tmpl_attr_list_next(ar_list, ar);
981
982 /*
983 * Walk down the tmpl ar stack looking for candidate parent
984 * attributes and then allocating the leaf.
985 */
986 while (true) {
987 if (unlikely(!ar)) goto error;
988 /*
989 * We're not at the leaf, look for a potential parent
990 */
991 if (ar != leaf) {
992 vp = fr_pair_find_by_da(list, NULL, ar->da);
993 /*
994 * HACK - Pretend we didn't see this stupid key field
995 *
996 * If we don't have this, the code creates a key pair
997 * and then horribly mangles its data by adding children
998 * to it.
999 *
1000 * We just skip one level down an don't create or update
1001 * the key pair.
1002 */
1003 if (vp && fr_dict_attr_is_key_field(ar->da) && fr_type_is_leaf(vp->data.type)) {
1004 ar = tmpl_attr_list_next(ar_list, ar);
1005 continue;
1006 }
1007 }
1008 /*
1009 * Nothing found, create the pair
1010 */
1011 if (!vp) {
1012 if (fr_pair_append_by_da(pair_ctx, &vp, list, ar->da) < 0) goto error;
1013 }
1014
1015 /*
1016 * We're at the leaf, return
1017 */
1018 if (ar == leaf) {
1019 *out = vp;
1020 return 0;
1021 }
1022
1023 /*
1024 * Prepare for next level
1025 */
1026 list = &vp->vp_group;
1027 pair_ctx = vp;
1028 vp = NULL;
1029 ar = tmpl_attr_list_next(ar_list, ar);
1030 }
1031}
1032
1033/** Insert a value-box to a list, with casting.
1034 *
1035 * @param list to append to
1036 * @param box box to cast / append
1037 * @param vpt tmpl with cast.
1038 * @return
1039 * - <0 for "cast failed"
1040 * - 0 for success
1041 */
1042int tmpl_value_list_insert_tail(fr_value_box_list_t *list, fr_value_box_t *box, tmpl_t const *vpt)
1043{
1045 (box->type == tmpl_rules_cast(vpt))) {
1046 fr_value_box_list_insert_tail(list, box);
1047 return 0;
1048 }
1049
1050 if (fr_value_box_cast_in_place(box, box, tmpl_rules_cast(vpt), tmpl_rules_enumv(vpt)) < 0) return -1;
1051
1052 fr_value_box_list_insert_tail(list, box);
1054 return 0;
1055}
1056
1057/** Gets the value of a real or virtual attribute
1058 *
1059 * @param[in] ctx to allocate boxed value, and buffers in.
1060 * @param[out] out Where to write the boxed value.
1061 * @param[in] request The current request.
1062 * @param[in] vpt Representing the attribute.
1063 * @return
1064 * - <0 we failed getting a value for the attribute.
1065 * - 0 we successfully evaluated the tmpl
1066 */
1067int tmpl_eval_pair(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
1068{
1069 fr_pair_t *vp = NULL;
1071
1072 fr_dcursor_t cursor;
1074
1075 int ret = 0;
1076 fr_value_box_list_t list;
1077
1079
1080 fr_value_box_list_init(&list);
1081
1082 /*
1083 * See if we're dealing with an attribute in the request
1084 *
1085 * This allows users to manipulate virtual attributes as if
1086 * they were real ones.
1087 */
1088 vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt);
1089
1090 /*
1091 * We didn't find the VP in a list, check to see if it's
1092 * virtual. This allows the caller to "realize" the
1093 * attribute, and we then prefer the realized version to
1094 * the virtual one.
1095 */
1096 if (!vp) {
1097 /*
1098 * Zero count.
1099 */
1102 if (!value) {
1103 oom:
1104 fr_strerror_const("Out of memory");
1105 ret = -1;
1106 goto fail;
1107 }
1108 value->datum.int32 = 0;
1109 fr_value_box_list_insert_tail(&list, value);
1110 } /* Fall through to being done */
1111
1112 goto done;
1113 }
1114
1115 switch (tmpl_attr_tail_num(vpt)) {
1116 /*
1117 * Return a count of the VPs.
1118 */
1119 case NUM_COUNT:
1120 {
1121 uint32_t count = 0;
1122
1123 while (vp != NULL) {
1124 count++;
1125 vp = fr_dcursor_next(&cursor);
1126 }
1127
1129 if (!value) goto oom;
1130 value->datum.uint32 = count;
1131 fr_value_box_list_insert_tail(&list, value);
1132 break;
1133 }
1134
1135 /*
1136 * Output multiple #value_box_t, one per attribute.
1137 */
1138 case NUM_ALL:
1139 /*
1140 * Loop over all matching #fr_value_pair
1141 * shallow copying buffers.
1142 */
1143 while (vp != NULL) {
1144 if (fr_type_is_structural(vp->vp_type)) {
1146 if (!value) goto oom;
1147
1148 if (fr_pair_list_copy_to_box(value, &vp->vp_group) < 0) {
1150 goto oom;
1151 }
1152
1153 } else {
1154 value = fr_value_box_alloc(ctx, vp->data.type, vp->da);
1155 if (!value) goto oom;
1156 fr_value_box_copy(value, value, &vp->data);
1157 }
1158
1159 fr_value_box_list_insert_tail(&list, value);
1160 vp = fr_dcursor_next(&cursor);
1161 }
1162 break;
1163
1164 default:
1165 if (!fr_type_is_leaf(vp->vp_type)) {
1166 fr_strerror_const("Invalid data type for evaluation");
1167 goto fail;
1168 }
1169
1170 value = fr_value_box_alloc(ctx, vp->data.type, vp->da);
1171 if (!value) goto oom;
1172
1173 fr_value_box_copy(value, value, &vp->data); /* Also dups taint */
1174 fr_value_box_list_insert_tail(&list, value);
1175 break;
1176 }
1177
1178done:
1179 /*
1180 * Evaluate casts if necessary.
1181 */
1182 if (ret == 0) {
1183 if (tmpl_eval_cast_in_place(&list, request, vpt) < 0) {
1184 fr_value_box_list_talloc_free(&list);
1185 ret = -1;
1186 goto fail;
1187 }
1188
1189 fr_value_box_list_move(out, &list);
1190 }
1191
1192fail:
1193 tmpl_dcursor_clear(&cc);
1195 return ret;
1196}
1197
1198
1199/** Gets the value of a tmpl
1200 *
1201 * The result is returned "raw". The caller must do any escaping it desires.
1202 *
1203 * @param[in] ctx to allocate boxed value, and buffers in.
1204 * @param[out] out Where to write the boxed value.
1205 * @param[in] request The current request.
1206 * @param[in] vpt Representing the tmpl
1207 * @return
1208 * - <0 we failed getting a value for the tmpl
1209 * - 0 we successfully evaluated the tmpl
1210 */
1211int tmpl_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
1212{
1213 char *p;
1215 fr_value_box_list_t list;
1216
1218 fr_strerror_const("Cannot evaluate unresolved tmpl");
1219 return -1;
1220 }
1221
1222 if (tmpl_async_required(vpt)) {
1223 fr_strerror_const("Cannot statically evaluate asynchronous expansions");
1224 return -1;
1225 }
1226
1227 if (tmpl_contains_regex(vpt)) {
1228 fr_strerror_const("Cannot statically evaluate regular expression");
1229 return -1;
1230 }
1231
1232 if (tmpl_is_attr(vpt)) {
1233 return tmpl_eval_pair(ctx, out, request, vpt);
1234 }
1235
1236 if (tmpl_is_data(vpt)) {
1238
1239 fr_value_box_copy(value, value, tmpl_value(vpt)); /* Also dups taint */
1240 goto done;
1241 }
1242
1244
1245 /*
1246 * @todo - respect escaping functions. But the sync
1247 * escaping uses a different method than the async ones.
1248 * And we then also need to escape the output of
1249 * tmpl_eval_pair(), too.
1250 */
1252 if (tmpl_aexpand(value, &p, request, vpt, NULL, NULL) < 0) {
1254 return -1;
1255 }
1256 fr_value_box_bstrndup_shallow(value, NULL, p, talloc_array_length(p) - 1, true);
1257
1258 /*
1259 * Cast the results if necessary.
1260 */
1261done:
1262 fr_value_box_list_init(&list);
1263 fr_value_box_list_insert_tail(&list, value);
1264
1265 if (tmpl_eval_cast_in_place(&list, request, vpt) < 0) {
1266 fr_value_box_list_talloc_free(&list);
1267 return -1;
1268 }
1269
1270 fr_value_box_list_move(out, &list);
1272
1273 return 0;
1274}
1275
1276/** Allocate a uctx for an escaping function
1277 *
1278 * @param[in] request The current request.
1279 * @param[in] escape Describing how to escape tmpl data.
1280 *
1281 * @return the uctx to pass to the escape function.
1282 */
1283static inline void *tmpl_eval_escape_uctx_alloc(request_t *request, tmpl_escape_t const *escape)
1284{
1285 switch (escape->uctx.type) {
1287 return UNCONST(void *, escape->uctx.ptr);
1288
1290 {
1291 void *uctx;
1292
1293 fr_assert_msg(escape->uctx.size > 0, "TMPL_ESCAPE_UCTX_ALLOC must specify uctx.size > 0");
1294 MEM(uctx = talloc_zero_array(NULL, uint8_t, escape->uctx.size));
1295 if (escape->uctx.talloc_type) talloc_set_type(uctx, escape->uctx.talloc_type);
1296 return uctx;
1297 }
1298
1300 fr_assert_msg(escape->uctx.func.alloc, "TMPL_ESCAPE_UCTX_ALLOC_FUNC must specify a non-null alloc.func");
1301 return escape->uctx.func.alloc(request, escape->uctx.func.uctx);
1302
1303 default:
1304 fr_assert_msg(0, "Unknown escape uctx type %u", escape->uctx.type);
1305 return NULL;
1306 }
1307}
1308
1309/** Free a uctx for an escaping function
1310 *
1311 * @param[in] escape Describing how to escape tmpl data.
1312 * @param[in] uctx The uctx to free.
1313 */
1314static inline void tmpl_eval_escape_uctx_free(tmpl_escape_t const *escape, void *uctx)
1315{
1316 switch (escape->uctx.type) {
1318 return;
1319
1321 talloc_free(uctx);
1322 return;
1323
1325 if (escape->uctx.func.free) escape->uctx.func.free(uctx);
1326 return;
1327 }
1328}
1329
1330/** Casts a value or list of values according to the tmpl
1331 *
1332 * @param[in,out] list Where to write the boxed value.
1333 * @param[in] request The current request.
1334 * @param[in] vpt Representing the attribute.
1335 * @return
1336 * - <0 the cast failed
1337 * - 0 we successfully evaluated the tmpl
1338 */
1339int tmpl_eval_cast_in_place(fr_value_box_list_t *list, request_t *request, tmpl_t const *vpt)
1340{
1342 bool did_concat = false;
1343 void *uctx = NULL;
1344
1345 if (fr_type_is_structural(cast)) {
1346 fr_strerror_printf("Cannot cast to structural type '%s'", fr_type_to_str(cast));
1347 return -1;
1348 }
1349
1350 /*
1351 * Quoting around the tmpl means everything
1352 * needs to be concatenated, either as a string
1353 * or octets string.
1354 */
1355 switch (vpt->quote) {
1360 {
1361 ssize_t slen;
1362 fr_value_box_t *vb;
1363
1364 vb = fr_value_box_list_head(list);
1365 if (!vb) return 0;
1366
1368 uctx = tmpl_eval_escape_uctx_alloc(request, &vpt->rules.escape);
1369 /*
1370 * Sets escaped values, so boxes don't get re-escaped
1371 */
1372 if (unlikely(fr_value_box_list_escape_in_place(list, &vpt->rules.escape.box_escape, uctx) < 0)) {
1373 error:
1374 tmpl_eval_escape_uctx_free(&vpt->rules.escape, uctx);
1375 return -1;
1376 }
1377 }
1378
1380 FR_VALUE_BOX_LIST_FREE_BOX, true, SIZE_MAX);
1381 if (slen < 0) goto error;
1383
1384 /*
1385 * If there's no cast, or it's a cast to
1386 * a string, we're done!
1387 *
1388 * Otherwise we now need to re-cast the
1389 * result.
1390 */
1391 if (fr_type_is_null(cast) || fr_type_is_string(cast)) {
1392 success:
1393 tmpl_eval_escape_uctx_free(&vpt->rules.escape, uctx);
1394 return 0;
1395 }
1396
1397 did_concat = true;
1398 }
1399 break;
1400
1401 default:
1402 break;
1403 }
1404
1405 if (fr_type_is_null(cast)) goto success;
1406
1407 /*
1408 * Quoting above handled all concatenation,
1409 * we now need to handle potentially
1410 * multivalued lists.
1411 */
1413 if (fr_value_box_cast_in_place(vb, vb, cast, NULL) < 0) goto error;
1414 }}
1415
1416 /*
1417 * ...and finally, apply the escape function
1418 * if necessary. This is done last so that
1419 * the escape function gets boxes of the type
1420 * it expects.
1421 */
1423 uctx = tmpl_eval_escape_uctx_alloc(request, &vpt->rules.escape);
1424 if (unlikely(fr_value_box_list_escape_in_place(list, &vpt->rules.escape.box_escape, uctx) < 0)) goto error;
1425 }
1426
1427 /*
1428 * If there's no escape function, but there is
1429 * a safe_for value, mark all the boxes up with
1430 * this value.
1431 *
1432 * This is mostly useful for call_env usage in
1433 * modules where certain values are implicitly safe
1434 * for consumption, like SQL statements in the SQL
1435 * module.
1436 */
1437 if (!vpt->rules.escape.box_escape.func && vpt->rules.escape.box_escape.safe_for) {
1438 fr_value_box_list_mark_safe_for(list, vpt->rules.escape.box_escape.safe_for);
1439 }
1440
1442
1444}
1445
1447{
1449
1450 if (tmpl_is_data(vpt)) return tmpl_value_type(vpt);
1451
1452 if (tmpl_is_attr(vpt)) return tmpl_attr_tail_da(vpt)->type;
1453
1455
1456 return FR_TYPE_NULL; /* can't determine it */
1457}
1458
1459
1460static int _tmpl_global_free(UNUSED void *uctx)
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:485
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
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:862
static fr_slen_t err
Definition dict.h:833
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:585
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2402
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:285
#define fr_dict_autoload(_to_load)
Definition dict.h:859
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:157
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:284
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:1468
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:2321
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:695
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:1347
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:491
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:2356
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:81
#define RDEBUG(fmt,...)
Definition radclient.h:53
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:885
#define TMPL_VERIFY(_vpt)
Definition tmpl.h:961
#define tmpl_is_xlat(vpt)
Definition tmpl.h:210
#define tmpl_rules_enumv(_tmpl)
Definition tmpl.h:943
#define tmpl_value(_tmpl)
Definition tmpl.h:937
#define tmpl_contains_regex(vpt)
Definition tmpl.h:226
#define tmpl_is_attr(vpt)
Definition tmpl.h:208
#define NUM_ALL
Definition tmpl.h:391
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:930
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
Definition tmpl.h:904
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:679
#define tmpl_rules_cast(_tmpl)
Definition tmpl.h:942
@ TMPL_TYPE_REGEX_UNCOMPILED
Regex where compilation is possible but hasn't been performed yet.
Definition tmpl.h:158
@ TMPL_TYPE_MAX
Marker for the last tmpl type.
Definition tmpl.h:199
@ TMPL_TYPE_ATTR_UNRESOLVED
An attribute reference that we couldn't resolve but looked valid.
Definition tmpl.h:185
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
Definition tmpl.h:142
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
Definition tmpl.h:146
@ TMPL_TYPE_EXEC
Callout to an external script or program.
Definition tmpl.h:150
@ TMPL_TYPE_REGEX_XLAT_UNRESOLVED
A regular expression with unresolved xlat functions or attribute references.
Definition tmpl.h:197
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition tmpl.h:138
@ TMPL_TYPE_REGEX
Compiled (and possibly JIT'd) regular expression.
Definition tmpl.h:154
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
Definition tmpl.h:179
@ TMPL_TYPE_XLAT_UNRESOLVED
A xlat expansion with unresolved xlat functions or attribute references.
Definition tmpl.h:193
@ TMPL_TYPE_REGEX_XLAT
A regex containing xlat expansions.
Definition tmpl.h:162
@ TMPL_TYPE_EXEC_UNRESOLVED
An exec with unresolved xlat function or attribute references.
Definition tmpl.h:189
@ TMPL_TYPE_UNINITIALISED
Uninitialised.
Definition tmpl.h:134
#define NUM_COUNT
Definition tmpl.h:392
#define tmpl_pair_list_and_ctx(_ctx, _head, _request, _ref, _list)
Determine the correct context and list head.
Definition tmpl.h:993
#define tmpl_is_data(vpt)
Definition tmpl.h:206
static fr_slen_t vpt
Definition tmpl.h:1269
#define tmpl_value_type(_tmpl)
Definition tmpl.h:939
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:801
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:915
@ 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:1062
#define tmpl_needs_resolving(vpt)
Definition tmpl.h:223
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
return count
Definition module.c:155
fr_pair_t * vp
An element in a list of nested attribute references.
Definition tmpl.h:430
fr_dict_attr_t const *_CONST da
Resolved dictionary attribute.
Definition tmpl.h:434
Define manipulation functions for the attribute reference list.
Definition tmpl.h:471
tmpl_request_ref_t _CONST request
Definition tmpl.h:475
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 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::@75 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:879
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:1042
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:1460
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:1211
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:1339
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:540
fr_type_t tmpl_data_type(tmpl_t const *vpt)
Definition tmpl_eval.c:1446
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:1067
goto success
Definition tmpl_eval.c:1443
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:831
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:788
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:1314
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:908
static int _tmpl_global_init(UNUSED void *uctx)
Definition tmpl_eval.c:1467
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:1283
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:964
@ 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:1708
static fr_slen_t head
Definition xlat.h:416
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:1725
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:1716
fr_type_t xlat_data_type(xlat_exp_head_t const *head)
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:148
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:4187
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:3574
size_t const fr_value_box_offsets[]
Where the value starts in the fr_value_box_t.
Definition value.c:188
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:3963
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:6155
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:3795
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:4703
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:4068
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)
Definition value.c:5450
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:6496
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:4270
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:4305
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:4092
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:4466
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:5934
@ FR_VALUE_BOX_LIST_FREE_BOX
Free each processed box.
Definition value.h:229
#define fr_value_box_list_foreach_safe(_list_head, _iter)
Definition value.h:218
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:632
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:779
#define vb_length
Definition value.h:283
#define FR_VALUE_BOX_INITIALISER_NULL(_vb)
A static initialiser for stack/globally allocated boxes.
Definition value.h:499
#define VALUE_BOX_VERIFY(_x)
Definition value.h:1304
#define VALUE_BOX_LIST_VERIFY(_x)
Definition value.h:1305
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:643
static size_t char ** out
Definition value.h:1012