The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
xlat.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: 0209a7a008ebf2a3ebbcbe0676b67d08ce550190 $
19 *
20 * @file unlang/xlat.c
21 * @brief Integration between the unlang interpreter and xlats
22 *
23 * @copyright 2018 The FreeRADIUS server project
24 * @copyright 2018 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 */
26RCSID("$Id: 0209a7a008ebf2a3ebbcbe0676b67d08ce550190 $")
27
28#include <freeradius-devel/server/base.h>
29
30#include <ctype.h>
31#include <freeradius-devel/unlang/mod_action.h>
32#include <freeradius-devel/unlang/xlat_priv.h>
33#include <freeradius-devel/util/debug.h>
34#include "unlang_priv.h" /* Fixme - Should create a proper semi-public interface for the interpret */
35
36/** State of an xlat expansion
37 *
38 * State of one level of nesting within an xlat expansion.
39 */
40typedef struct {
41 TALLOC_CTX *ctx; //!< to allocate boxes and values in.
42 TALLOC_CTX *event_ctx; //!< for temporary events
43 xlat_exp_head_t const *head; //!< of the xlat list
44 xlat_exp_t const *exp; //!< current one we're evaluating
45 fr_dcursor_t values; //!< Values aggregated so far.
46
47 rindent_t indent; //!< indentation
48
49 void *env_data; //!< Expanded per call environment tmpls.
50 /*
51 * For func and alternate
52 */
53 fr_value_box_list_t out; //!< Head of the result of a nested
54 ///< expansion.
55 xlat_func_t resume; //!< called on resume
56 xlat_func_signal_t signal; //!< called on signal
57 fr_signal_t sigmask; //!< Signals to block
58 void *rctx; //!< for resume / signal
59
60 unlang_result_t *p_result; //!< If set, where to record the result
61 ///< of the execution.
63
64/** Wrap an #fr_timer_t providing data needed for unlang events
65 *
66 */
67typedef struct {
68 request_t *request; //!< Request this event pertains to.
69 int fd; //!< File descriptor to wait on.
70 fr_unlang_xlat_timeout_t timeout; //!< Function to call on timeout.
71 fr_unlang_xlat_fd_event_t fd_read; //!< Function to call when FD is readable.
72 fr_unlang_xlat_fd_event_t fd_write; //!< Function to call when FD is writable.
73 fr_unlang_xlat_fd_event_t fd_error; //!< Function to call when FD has errored.
74 xlat_inst_t *inst; //!< xlat instance data.
75 xlat_thread_inst_t *thread; //!< Thread specific xlat instance.
76 void const *rctx; //!< rctx data to pass to callbacks.
77 fr_timer_t *ev; //!< Event in this worker's event heap.
79
80typedef struct {
82 xlat_inst_t *inst; //!< xlat instance data.
83 xlat_thread_inst_t *thread; //!< Thread specific xlat instance.
84
85 fr_unlang_xlat_retry_t retry_cb; //!< callback to run on timeout
86 void *rctx; //!< rctx data to pass to timeout callback
87
88 fr_timer_t *ev; //!< retry timer just for this xlat
89 fr_retry_t retry; //!< retry timers, etc.
91
92/** Frees an unlang event, removing it from the request's event loop
93 *
94 * @param[in] ev The event to free.
95 *
96 * @return 0
97 */
99{
100 FR_TIMER_DELETE(&(ev->ev));
101
102 if (ev->fd >= 0) {
104 }
105
106 return 0;
107}
108
109/** Call the callback registered for a timeout event
110 *
111 * @param[in] tl the event timer was inserted into.
112 * @param[in] now The current time, as held by the event_list.
113 * @param[in] uctx unlang_module_event_t structure holding callbacks.
114 *
115 */
117{
118 unlang_xlat_event_t *ev = talloc_get_type_abort(uctx, unlang_xlat_event_t);
119
120 /*
121 * If the timeout's fired then the xlat must necessarily
122 * be yielded, so it's fine to pass in its rctx.
123 *
124 * It should be able to free the rctx if it wants to.
125 * We never free it explicitly, and instead rely on
126 * talloc parenting.
127 */
128 ev->timeout(XLAT_CTX(ev->inst->data,
129 ev->thread->data,
130 NULL,
131 ev->thread->mctx, NULL,
132 UNCONST(void *, ev->rctx)),
133 ev->request, now);
134
135 /* Remove old references from the request */
136 talloc_free(ev);
137}
138
139/** Add a timeout for an xlat handler
140 *
141 * @note The timeout is automatically removed when the xlat is cancelled or resumed.
142 *
143 * @param[in] request the request
144 * @param[in] callback to run when the timeout hits
145 * @param[in] rctx passed to the callback
146 * @param[in] when when the timeout fires
147 * @return
148 * - <0 on error
149 * - 0 on success
150 */
152 fr_unlang_xlat_timeout_t callback, void const *rctx, fr_time_t when)
153{
154 unlang_stack_t *stack = request->stack;
155 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
157 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
158
159 fr_assert(stack->depth > 0);
161
162 if (!state->event_ctx) MEM(state->event_ctx = talloc_zero(state, bool));
163
164 MEM(ev = talloc_zero(state->event_ctx, unlang_xlat_event_t));
165 ev->request = request;
166 ev->fd = -1;
167 ev->timeout = callback;
168 fr_assert(state->exp->type == XLAT_FUNC);
169 ev->inst = state->exp->call.inst;
171 ev->rctx = rctx;
172
173 if (fr_timer_at(request, unlang_interpret_event_list(request)->tl,
174 &ev->ev, when,
175 false, unlang_xlat_event_timeout_handler, ev) < 0) {
176 RPEDEBUG("Failed inserting event");
177 talloc_free(ev);
178 return -1;
179 }
180
181 talloc_set_destructor(ev, _unlang_xlat_event_free);
182
183 return 0;
184}
185
186/** Push a pre-compiled xlat onto the stack for evaluation
187 *
188 * @param[in] ctx To allocate value boxes and values in.
189 * @param[out] p_result If set, rcodes and priorities will be written here and
190 * not evaluated by the unlang interpreter.
191 * @param[out] out Where to write the result of the expansion.
192 * @param[in] request to push xlat onto.
193 * @param[in] xlat head of list
194 * @param[in] node to evaluate.
195 * @param[in] top_frame Set to UNLANG_TOP_FRAME if the interpreter should return.
196 * Set to UNLANG_SUB_FRAME if the interprer should continue.
197 * @return
198 * - 0 on success.
199 * - -1 on failure.
200 */
201static int unlang_xlat_push_internal(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out,
202 request_t *request, xlat_exp_head_t const *xlat, xlat_exp_t *node, bool top_frame)
203{
204 /** Static instruction for performing xlat evaluations
205 *
206 */
207 static unlang_t xlat_instruction = {
209 .name = "xlat",
210 .debug_name = "xlat",
212 };
213
215 unlang_stack_t *stack = request->stack;
217
218 /*
219 * Push a new xlat eval frame onto the stack
220 */
221 if (unlang_interpret_push(p_result, request, &xlat_instruction,
222 FRAME_CONF(RLM_MODULE_NOT_SET, top_frame), UNLANG_NEXT_STOP) < 0) return -1;
223 frame = &stack->frame[stack->depth];
224
225 /*
226 * Allocate its state, and setup a cursor for the xlat nodes
227 */
228 MEM(frame->state = state = talloc_zero(stack, unlang_frame_state_xlat_t));
229 state->head = xlat;
230 state->exp = node;
231 state->p_result = p_result;
232 state->ctx = ctx;
233
234 if (node) switch (node->type) {
235 case XLAT_GROUP:
236 case XLAT_BOX:
237 break;
238
239 case XLAT_TMPL:
240 if (tmpl_is_data(node->vpt)) break;
242
243 default:
244 RDEBUG("| %s", node->fmt);
245 break;
246 }
247
248 /*
249 * Initialise the input and output lists
250 */
251 fr_dcursor_init(&state->values, fr_value_box_list_dlist_head(out));
252 fr_value_box_list_init(&state->out);
253
254 return 0;
255}
256
257/** Push a pre-compiled xlat onto the stack for evaluation
258 *
259 * @param[in] ctx To allocate value boxes and values in.
260 * @param[out] p_result The frame result
261 * @param[out] out Where to write the result of the expansion.
262 * @param[in] request to push xlat onto.
263 * @param[in] xlat to evaluate.
264 * @param[in] top_frame Set to UNLANG_TOP_FRAME if the interpreter should return.
265 * Set to UNLANG_SUB_FRAME if the interprer should continue.
266 * @return
267 * - 0 on success.
268 * - -1 on failure.
269 */
270int unlang_xlat_push(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out,
271 request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
272{
274
275 return unlang_xlat_push_internal(ctx, p_result, out, request, xlat, xlat_exp_head(xlat), top_frame);
276}
277
278/** Push a pre-compiled xlat onto the stack for evaluation
279 *
280 * @param[in] ctx To allocate value boxes and values in.
281 * @param[out] p_result If set, and execution succeeds, true will be written
282 * here. If execution fails, false will be written.
283 * @param[out] out Where to write the result of the expansion.
284 * @param[in] request to push xlat onto.
285 * @param[in] node to evaluate. Only this node will be evaluated.
286 * @return
287 * - 0 on success.
288 * - -1 on failure.
289 */
290int unlang_xlat_push_node(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out,
291 request_t *request, xlat_exp_t *node)
292{
293 return unlang_xlat_push_internal(ctx, p_result, out, request, NULL, node, UNLANG_TOP_FRAME);
294}
295
297{
298 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
299 xlat_action_t xa;
300 xlat_exp_head_t const *child = NULL;
301
302 /*
303 * If the xlat is a function with a method_env, expand it before calling the function.
304 */
305 if ((state->exp->type == XLAT_FUNC) && state->exp->call.inst->call_env && !state->env_data) {
306 unlang_action_t ua = call_env_expand(state, request, NULL, &state->env_data,
307 state->exp->call.inst->call_env);
308 switch (ua) {
310 goto fail;
311
315
316 default:
317 break;
318 }
319 }
320
321 xa = xlat_frame_eval_repeat(state->ctx, &state->values, &child,
322 request, state->head, &state->exp, state->env_data, &state->out);
323 switch (xa) {
325 fr_assert(child);
326
327 repeatable_set(frame); /* Was cleared by the interpreter */
328
329 /*
330 * Clear out the results of any previous expansions
331 * at this level. A frame may be used to evaluate
332 * multiple sibling nodes.
333 */
334 fr_value_box_list_talloc_free(&state->out);
335 if (unlang_xlat_push(state->ctx, p_result, &state->out, request, child, false) < 0) {
336 REXDENT();
338 }
340
342 repeatable_set(frame); /* Call the xlat code on the way back down */
344
346 if (!state->resume) {
347 RWDEBUG("Missing call to unlang_xlat_yield()");
348 goto fail;
349 }
350 repeatable_set(frame);
351 return UNLANG_ACTION_YIELD;
352
353 case XLAT_ACTION_DONE:
355 REXDENT();
357
358 case XLAT_ACTION_FAIL:
359 fail:
361 REXDENT();
363
364 default:
365 fr_assert(0);
366 goto fail;
367 }
368}
369
370/** Stub function for calling the xlat interpreter
371 *
372 * Calls the xlat interpreter and translates its wants and needs into
373 * unlang_action_t codes.
374 */
376{
377 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
378 xlat_action_t xa;
379 xlat_exp_head_t const *child = NULL;
380
381 RINDENT_SAVE(state, request);
382 RINDENT();
383
384 xa = xlat_frame_eval(state->ctx, &state->values, &child, request, state->head, &state->exp);
385 switch (xa) {
387 fr_assert(child);
388
390
391 /*
392 * Clear out the results of any previous expansions
393 * at this level. A frame may be used to evaluate
394 * multiple sibling nodes.
395 */
396 fr_value_box_list_talloc_free(&state->out);
397 if (unlang_xlat_push(state->ctx, p_result, &state->out, request, child, false) < 0) {
398 RINDENT_RESTORE(request, state);
400 }
402
404 repeatable_set(frame); /* Call the xlat code on the way back down */
406
408 if (!state->resume) {
409 RWDEBUG("Missing call to unlang_xlat_yield()");
410 goto fail;
411 }
412 repeatable_set(frame);
413 return UNLANG_ACTION_YIELD;
414
415 case XLAT_ACTION_DONE:
417 RINDENT_RESTORE(request, state);
419
420 case XLAT_ACTION_FAIL:
421 fail:
423 RINDENT_RESTORE(request, state);
425
426 default:
427 fr_assert(0);
428 goto fail;
429 }
430}
431
432/** Send a signal (usually stop) to a request that's running an xlat expansions
433 *
434 * This is typically called via an "async" action, i.e. an action
435 * outside of the normal processing of the request.
436 *
437 * If there is no #xlat_func_signal_t callback defined, the action is ignored.
438 *
439 * @param[in] request The current request.
440 * @param[in] frame The current stack frame.
441 * @param[in] action What the request should do (the type of signal).
442 */
444{
445 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
446
447 /*
448 * Delete timers, etc. when the xlat is cancelled.
449 */
450 if (action == FR_SIGNAL_CANCEL) {
451 TALLOC_FREE(state->event_ctx);
452 }
453
454 if (!state->signal || (state->sigmask & action)) return;
455
456 xlat_signal(state->signal, state->exp, request, state->rctx, action);
457}
458
459/** Called when we're ready to resume processing the request
460 *
461 * @param[in] p_result the result of the xlat function.
462 * - RLM_MODULE_OK on success.
463 * - RLM_MODULE_FAIL on failure.
464 * @param[in] request to resume processing.
465 * @param[in] frame the current stack frame.
466 * @return
467 * - UNLANG_ACTION_YIELD if additional asynchronous
468 * operations need to be performed.
469 * - UNLANG_ACTION_CALCULATE_RESULT if done.
470 */
472{
473 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
474 xlat_action_t xa;
475 xlat_exp_head_t const *child = NULL;
476
477 fr_assert(state->resume != NULL);
478
479 /*
480 * Delete timers, etc. when the xlat is resumed.
481 */
482 TALLOC_FREE(state->event_ctx);
483
484 xa = xlat_frame_eval_resume(state->ctx, &state->values, &child, request, state->head, &state->exp,
485 &state->out, state->resume, state->rctx);
486 switch (xa) {
488 repeatable_set(frame);
489 return UNLANG_ACTION_YIELD;
490
491 case XLAT_ACTION_DONE:
493 RINDENT_RESTORE(request, state);
495
497 repeatable_set(frame);
499
501 fr_assert(child);
502
503 repeatable_set(frame); /* Was cleared by the interpreter */
504
505 /*
506 * Clear out the results of any previous expansions
507 * at this level. A frame may be used to evaluate
508 * multiple sibling nodes.
509 */
510 fr_value_box_list_talloc_free(&state->out);
511 if (unlang_xlat_push(state->ctx, state->p_result, &state->out, request, child, false) < 0) {
512 RINDENT_RESTORE(request, state);
514 }
516
517 case XLAT_ACTION_FAIL:
519 RINDENT_RESTORE(request, state);
521 /* DON'T SET DEFAULT */
522 }
523
524 fr_assert(0); /* Garbage xlat action */
525
527 RINDENT_RESTORE(request, state);
529}
530
531/** Yield a request back to the interpreter from within a module
532 *
533 * This passes control of the request back to the unlang interpreter, setting
534 * callbacks to execute when the request is 'signalled' asynchronously, or whatever
535 * timer or I/O event the module was waiting for occurs.
536 *
537 * @note The module function which calls #unlang_module_yield should return control
538 * of the C stack to the unlang interpreter immediately after calling #unlang_xlat_yield.
539 * A common pattern is to use ``return unlang_xlat_yield(...)``.
540 *
541 * @param[in] request The current request.
542 * @param[in] resume Called on unlang_interpret_mark_runnable().
543 * @param[in] signal Called on unlang_action().
544 * @param[in] sigmask Signals to block.
545 * @param[in] rctx to pass to the callbacks.
546 * @return always returns XLAT_ACTION_YIELD
547 */
549 xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask,
550 void *rctx)
551{
552 unlang_stack_t *stack = request->stack;
553 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
554 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
555
557
558 /*
559 * Over-ride whatever functions were there before.
560 */
561 state->resume = resume;
562 state->signal = signal;
563 state->sigmask = sigmask;
564 state->rctx = rctx;
565
566 return XLAT_ACTION_YIELD;
567}
568
569/** Frees an unlang event, removing it from the request's event loop
570 *
571 * @param[in] ev The event to free.
572 *
573 * @return 0
574 */
576{
577 FR_TIMER_DELETE(&(ev->ev));
578
579 return 0;
580}
581
582/** Call the callback registered for a timeout event
583 *
584 * @param[in] tl the event timer was inserted into.
585 * @param[in] now The current time, as held by the event_list.
586 * @param[in] uctx unlang_module_event_t structure holding callbacks.
587 *
588 */
590{
591 unlang_xlat_retry_t *ev = talloc_get_type_abort(uctx, unlang_xlat_retry_t);
592 request_t *request = ev->request;
593
594 switch (fr_retry_next(&ev->retry, now)) {
596 /*
597 * Call the module retry handler, with the state of the retry. On MRD / MRC, the
598 * module is made runnable again, and the "resume" function is called.
599 */
600 ev->retry_cb(XLAT_CTX(ev->inst->data,
601 ev->thread->data,
602 NULL,
603 ev->thread->mctx, NULL,
604 UNCONST(void *, ev->rctx)),
605 ev->request, &ev->retry);
606
607 /*
608 * Reset the timer.
609 */
610 if (fr_timer_at(ev, unlang_interpret_event_list(request)->tl, &ev->ev, ev->retry.next,
611 false, unlang_xlat_event_retry_handler, request) < 0) {
612 RPEDEBUG("Failed inserting event");
613 talloc_free(ev);
615 }
616 return;
617
618 case FR_RETRY_MRD:
619 RDEBUG("Reached max_rtx_duration (%pVs > %pVs) - sending timeout",
621 break;
622
623 case FR_RETRY_MRC:
624 RDEBUG("Reached max_rtx_count %u- sending timeout",
625 ev->retry.config->mrc);
626 break;
627 }
628
629 /*
630 * Run the retry handler on MRD / MRC, too.
631 */
632 ev->retry_cb(XLAT_CTX(ev->inst->data,
633 ev->thread->data,
634 NULL,
635 ev->thread->mctx, NULL,
636 UNCONST(void *, ev->rctx)),
637 ev->request, &ev->retry);
638
639 /*
640 * On final timeout, always mark the request as runnable.
641 */
642 talloc_free(ev);
644}
645
646
647/** Yield a request back to the interpreter, with retries
648 *
649 * This passes control of the request back to the unlang interpreter, setting
650 * callbacks to execute when the request is 'signalled' asynchronously, or when
651 * the retry timer hits.
652 *
653 * @note The module function which calls #unlang_module_yield_to_retry should return control
654 * of the C stack to the unlang interpreter immediately after calling #unlang_module_yield_to_retry.
655 * A common pattern is to use ``return unlang_module_yield_to_retry(...)``.
656 *
657 * @param[in] request The current request.
658 * @param[in] resume Called on unlang_interpret_mark_runnable().
659 * @param[in] retry Called on when a retry timer hits
660 * @param[in] signal Called on unlang_action().
661 * @param[in] sigmask Set of signals to block.
662 * @param[in] rctx to pass to the callbacks.
663 * @param[in] retry_cfg to set up the retries
664 * @return
665 * - XLAT_ACTION_YIELD on success
666 * - XLAT_ACTION_FAIL on failure
667 */
669 xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx,
670 fr_retry_config_t const *retry_cfg)
671{
672 unlang_stack_t *stack = request->stack;
673 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
675 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
676
677 fr_assert(stack->depth > 0);
679
680 if (!state->event_ctx) MEM(state->event_ctx = talloc_zero(state, bool));
681
682 MEM(ev = talloc_zero(state->event_ctx, unlang_xlat_retry_t));
683
684 ev->request = request;
685 fr_assert(state->exp->type == XLAT_FUNC);
686 ev->inst = state->exp->call.inst;
688 ev->retry_cb = retry;
689 ev->rctx = rctx;
690
691 fr_retry_init(&ev->retry, fr_time(), retry_cfg);
692
693 if (fr_timer_at(request, unlang_interpret_event_list(request)->tl,
694 &ev->ev, ev->retry.next,
695 false, unlang_xlat_event_retry_handler, ev) < 0) {
696 RPEDEBUG("Failed inserting event");
697 talloc_free(ev);
698 return XLAT_ACTION_FAIL;
699 }
700
701 talloc_set_destructor(ev, _unlang_xlat_retry_free);
702
703 return unlang_xlat_yield(request, resume, signal, sigmask, rctx);
704}
705
706/** Evaluate a "pure" (or not impure) xlat
707 *
708 * @param[in] ctx To allocate value boxes and values in.
709 * @param[out] out Where to write the result of the expansion.
710 * @param[in] request to push xlat onto.
711 * @param[in] xlat to evaluate.
712 * @return
713 * - 0 on success.
714 * - -1 on failure.
715 */
716int unlang_xlat_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat)
717{
719
720 if (xlat->flags.impure_func) {
721 fr_strerror_const("Expansion requires async operations");
722 return -1;
723 }
724
725 if (unlang_xlat_push(ctx, &result, out, request, xlat, UNLANG_TOP_FRAME) < 0) return -1;
726
728
729 if (!XLAT_RESULT_SUCCESS(&result)) return -1;
730
731 return 0;
732}
733
734/** Evaluate a "pure" (or not impure) xlat
735 *
736 * @param[in] ctx To allocate value boxes and values in.
737 * @param[out] vb output value-box
738 * @param[in] type expected type
739 * @param[in] enumv enum for type
740 * @param[in] request to push xlat onto.
741 * @param[in] xlat to evaluate.
742 * @return
743 * - 0 on success.
744 * - -1 on failure.
745 */
746int unlang_xlat_eval_type(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t type, fr_dict_attr_t const *enumv, request_t *request, xlat_exp_head_t const *xlat)
747{
748 fr_value_box_t *src;
749 fr_value_box_list_t list;
750
752 fr_strerror_const("Invalid type for output of evaluation");
753 return -1;
754 }
755
756 fr_value_box_list_init(&list);
757
758 if (unlang_xlat_eval(ctx, &list, request, xlat) < 0) return -1;
759
760 fr_value_box_init(vb, type, NULL, false);
761
762 switch (type) {
763 default:
764 /*
765 * Take only the first entry from the list.
766 */
767 src = fr_value_box_list_head(&list);
768 if (!src) {
769 fr_strerror_const("Expression returned no results");
770 fail:
771 fr_value_box_list_talloc_free(&list);
772 return -1;
773 }
774
775 if (fr_value_box_cast(ctx, vb, type, enumv, src) < 0) goto fail;
776 fr_value_box_list_talloc_free(&list);
777 break;
778
779 case FR_TYPE_STRING:
780 case FR_TYPE_OCTETS:
781 /*
782 * No output: create an empty string.
783 *
784 * The "concat in place" function returns an error for empty input, which is arguably not
785 * what we want to do here.
786 */
787 if (fr_value_box_list_empty(&list)) {
788 break;
789 }
790
791 if (fr_value_box_list_concat_in_place(ctx, vb, &list, type, FR_VALUE_BOX_LIST_FREE_BOX, false, SIZE_MAX) < 0) {
792 goto fail;
793 }
794 break;
795 }
796
797 return 0;
798}
799
801{
802 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
803 xlat_exp_t const *exp = state->exp;
804
805 if (exp) RDEBUG("expression %s", exp->fmt);
806}
807/** Register xlat operation with the interpreter
808 *
809 */
811{
813 .name = "xlat",
814 .type = UNLANG_TYPE_XLAT,
816
817 .interpret = unlang_xlat,
818 .signal = unlang_xlat_signal,
819 .dump = unlang_xlat_dump,
820
821 .frame_state_size = sizeof(unlang_frame_state_xlat_t),
822 .frame_state_type = "unlang_frame_state_xlat_t",
823 });
824}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ UNLANG_ACTION_STOP_PROCESSING
Break out of processing the current request (unwind).
Definition action.h:42
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:41
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:485
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define UNUSED
Definition build.h:317
unlang_action_t call_env_expand(TALLOC_CTX *ctx, request_t *request, call_env_result_t *env_result, void **env_data, call_env_t const *call_env)
Initialise the expansion of a call environment.
Definition call_env.c:331
#define fr_dcursor_init(_cursor, _head)
Initialise a cursor.
Definition dcursor.h:710
#define MEM(x)
Definition debug.h:36
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:84
rlm_rcode_t unlang_interpret(request_t *request, bool running)
Run the interpreter for a current request.
Definition interpret.c:949
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1612
int unlang_interpret_push(unlang_result_t *p_result, request_t *request, unlang_t const *instruction, unlang_frame_conf_t const *conf, bool do_next_sibling)
Push a new frame onto the stack.
Definition interpret.c:280
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:2009
#define UNLANG_RESULT_NOT_SET
Definition interpret.h:139
#define FRAME_CONF(_default_rcode, _top_frame)
Definition interpret.h:152
#define UNLANG_TOP_FRAME
Definition interpret.h:36
#define UNLANG_REQUEST_RUNNING
Definition interpret.h:42
#define UNLANG_RESULT_RCODE(_x)
Definition interpret.h:140
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:443
#define RWDEBUG(fmt,...)
Definition log.h:361
#define RINDENT_SAVE(_x, _request)
Save indentation for later restoral.
Definition log.h:388
#define RINDENT_RESTORE(_request, _x)
Definition log.h:392
#define RPEDEBUG(fmt,...)
Definition log.h:376
#define RINDENT()
Indent R* messages by one level.
Definition log.h:430
void unlang_register(unlang_op_t *op)
Register an operation with the interpreter.
Definition base.c:56
talloc_free(reap)
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Definition event.c:1203
static char * stack[MAX_STACK]
Definition radmin.c:159
fr_type_t
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_OCTETS
Raw octets.
#define MOD_ACTIONS_FAIL_TIMEOUT_RETURN
Definition mod_action.h:69
#define fr_assert(_expr)
Definition rad_assert.h:38
#define RDEBUG(fmt,...)
Definition radclient.h:53
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:45
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:44
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:41
#define tmpl_is_data(vpt)
Definition tmpl.h:206
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
fr_aka_sim_id_type_t type
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
#define talloc_get_type_abort_const
Definition talloc.h:287
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition time.h:229
"server local" time.
Definition time.h:69
An event timer list.
Definition timer.c:50
A timer event.
Definition timer.c:84
#define FR_TIMER_DELETE(_ev_p)
Definition timer.h:103
#define fr_timer_at(...)
Definition timer.h:81
fr_timer_t * ev
retry timer just for this xlat
Definition xlat.c:88
int unlang_xlat_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat)
Evaluate a "pure" (or not impure) xlat.
Definition xlat.c:716
xlat_exp_head_t const * head
of the xlat list
Definition xlat.c:43
TALLOC_CTX * ctx
to allocate boxes and values in.
Definition xlat.c:41
fr_unlang_xlat_fd_event_t fd_read
Function to call when FD is readable.
Definition xlat.c:71
int unlang_xlat_eval_type(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t type, fr_dict_attr_t const *enumv, request_t *request, xlat_exp_head_t const *xlat)
Evaluate a "pure" (or not impure) xlat.
Definition xlat.c:746
static void unlang_xlat_dump(request_t *request, unlang_stack_frame_t *frame)
Definition xlat.c:800
TALLOC_CTX * event_ctx
for temporary events
Definition xlat.c:42
xlat_func_signal_t signal
called on signal
Definition xlat.c:56
static void unlang_xlat_event_retry_handler(UNUSED fr_timer_list_t *tl, fr_time_t now, void *uctx)
Call the callback registered for a timeout event.
Definition xlat.c:589
unlang_result_t * p_result
If set, where to record the result of the execution.
Definition xlat.c:60
xlat_thread_inst_t * thread
Thread specific xlat instance.
Definition xlat.c:83
static int _unlang_xlat_event_free(unlang_xlat_event_t *ev)
Frees an unlang event, removing it from the request's event loop.
Definition xlat.c:98
void * rctx
for resume / signal
Definition xlat.c:58
int unlang_xlat_push_node(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out, request_t *request, xlat_exp_t *node)
Push a pre-compiled xlat onto the stack for evaluation.
Definition xlat.c:290
xlat_action_t unlang_xlat_yield_to_retry(request_t *request, xlat_func_t resume, fr_unlang_xlat_retry_t retry, xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx, fr_retry_config_t const *retry_cfg)
Yield a request back to the interpreter, with retries.
Definition xlat.c:668
fr_dcursor_t values
Values aggregated so far.
Definition xlat.c:45
fr_value_box_list_t out
Head of the result of a nested expansion.
Definition xlat.c:53
fr_timer_t * ev
Event in this worker's event heap.
Definition xlat.c:77
xlat_action_t unlang_xlat_yield(request_t *request, xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition xlat.c:548
xlat_func_t resume
called on resume
Definition xlat.c:55
fr_unlang_xlat_retry_t retry_cb
callback to run on timeout
Definition xlat.c:85
fr_retry_t retry
retry timers, etc.
Definition xlat.c:89
request_t * request
Request this event pertains to.
Definition xlat.c:68
int fd
File descriptor to wait on.
Definition xlat.c:69
static unlang_action_t unlang_xlat(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Stub function for calling the xlat interpreter.
Definition xlat.c:375
fr_unlang_xlat_timeout_t timeout
Function to call on timeout.
Definition xlat.c:70
request_t * request
Definition xlat.c:81
static void unlang_xlat_event_timeout_handler(UNUSED fr_timer_list_t *tl, fr_time_t now, void *uctx)
Call the callback registered for a timeout event.
Definition xlat.c:116
static int unlang_xlat_push_internal(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, xlat_exp_t *node, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
Definition xlat.c:201
xlat_inst_t * inst
xlat instance data.
Definition xlat.c:74
int unlang_xlat_push(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
Definition xlat.c:270
xlat_inst_t * inst
xlat instance data.
Definition xlat.c:82
void * rctx
rctx data to pass to timeout callback
Definition xlat.c:86
fr_unlang_xlat_fd_event_t fd_write
Function to call when FD is writable.
Definition xlat.c:72
static unlang_action_t unlang_xlat_repeat(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition xlat.c:296
fr_signal_t sigmask
Signals to block.
Definition xlat.c:57
static int _unlang_xlat_retry_free(unlang_xlat_retry_t *ev)
Frees an unlang event, removing it from the request's event loop.
Definition xlat.c:575
int unlang_xlat_timeout_add(request_t *request, fr_unlang_xlat_timeout_t callback, void const *rctx, fr_time_t when)
Add a timeout for an xlat handler.
Definition xlat.c:151
rindent_t indent
indentation
Definition xlat.c:47
void * env_data
Expanded per call environment tmpls.
Definition xlat.c:49
static unlang_action_t unlang_xlat_resume(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Called when we're ready to resume processing the request.
Definition xlat.c:471
void const * rctx
rctx data to pass to callbacks.
Definition xlat.c:76
static void unlang_xlat_signal(request_t *request, unlang_stack_frame_t *frame, fr_signal_t action)
Send a signal (usually stop) to a request that's running an xlat expansions.
Definition xlat.c:443
void unlang_xlat_init(void)
Register xlat operation with the interpreter.
Definition xlat.c:810
xlat_exp_t const * exp
current one we're evaluating
Definition xlat.c:44
fr_unlang_xlat_fd_event_t fd_error
Function to call when FD has errored.
Definition xlat.c:73
xlat_thread_inst_t * thread
Thread specific xlat instance.
Definition xlat.c:75
State of an xlat expansion.
Definition xlat.c:40
Wrap an fr_timer_t providing data needed for unlang events.
Definition xlat.c:67
void * data
Thread specific instance data.
Definition xlat.h:94
xlat_thread_inst_t * xlat_thread_instance_find(xlat_exp_t const *node)
Retrieve xlat/thread specific instance data.
Definition xlat_inst.c:405
void(* fr_unlang_xlat_fd_event_t)(xlat_ctx_t const *xctx, request_t *request, int fd)
A callback when the FD is ready for reading.
Definition xlat.h:212
#define XLAT_RESULT_SUCCESS(_p_result)
Definition xlat.h:503
void(* xlat_func_signal_t)(xlat_ctx_t const *xctx, request_t *request, fr_signal_t action)
A callback when the request gets a fr_signal_t.
Definition xlat.h:243
void(* fr_unlang_xlat_retry_t)(xlat_ctx_t const *xctx, request_t *request, fr_retry_t const *retry)
A callback when the the timeout occurs.
Definition xlat.h:199
xlat_action_t(* xlat_func_t)(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
xlat callback function
Definition xlat.h:232
void * data
xlat node specific instance data.
Definition xlat.h:78
void(* fr_unlang_xlat_timeout_t)(xlat_ctx_t const *xctx, request_t *request, fr_time_t fired)
A callback when the the timeout occurs.
Definition xlat.h:185
uint8_t impure_func
xlat contains an impure function
Definition xlat.h:111
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_YIELD
An xlat function pushed a resume frame onto the stack.
Definition xlat.h:42
@ XLAT_ACTION_PUSH_UNLANG
An xlat function pushed an unlang frame onto the unlang stack.
Definition xlat.h:39
@ XLAT_ACTION_PUSH_CHILD
A deeper level of nesting needs to be evaluated.
Definition xlat.h:38
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
module_ctx_t const * mctx
A synthesised module calling ctx containing module global and thread instance data.
Definition xlat.h:96
Instance data for an xlat expansion node.
Definition xlat.h:71
Thread specific instance data for xlat expansion node.
Definition xlat.h:85
Private interpreter structures and functions.
void * state
Stack frame specialisations.
#define UNLANG_NEXT_STOP
Definition unlang_priv.h:99
@ UNLANG_TYPE_XLAT
Represents one level of an xlat expansion.
Definition unlang_priv.h:81
static void frame_repeat(unlang_stack_frame_t *frame, unlang_process_t process)
Mark the current stack frame up for repeat, and set a new process function.
unlang_t const * instruction
The unlang node we're evaluating.
@ UNLANG_OP_FLAG_INTERNAL
it's not a real keyword
static void repeatable_set(unlang_stack_frame_t *frame)
unlang_process_t process
function to call for interpreting this stack frame
unlang_type_t type
The specialisation of this node.
An unlang operation.
A node in a graph of unlang_op_t (s) that we execute.
Our interpreter stack, as distinct from the C stack.
An unlang stack associated with a request.
fr_retry_state_t fr_retry_next(fr_retry_t *r, fr_time_t now)
Initialize a retransmission counter.
Definition retry.c:108
void fr_retry_init(fr_retry_t *r, fr_time_t now, fr_retry_config_t const *config)
Initialize a retransmission counter.
Definition retry.c:36
fr_time_t start
when we started the retransmission
Definition retry.h:53
uint32_t mrc
Maximum retransmission count.
Definition retry.h:36
fr_retry_config_t const * config
master configuration
Definition retry.h:52
@ FR_RETRY_MRC
reached maximum retransmission count
Definition retry.h:47
@ FR_RETRY_CONTINUE
Definition retry.h:46
@ FR_RETRY_MRD
reached maximum retransmission duration
Definition retry.h:48
fr_time_delta_t mrd
Maximum retransmission duration.
Definition retry.h:35
fr_time_t next
when the next timer should be set
Definition retry.h:55
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_type_is_structural(_x)
Definition types.h:390
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:3741
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:6273
@ FR_VALUE_BOX_LIST_FREE_BOX
Free each processed box.
Definition value.h:236
#define fr_box_time_delta(_val)
Definition value.h:365
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:609
static size_t char ** out
Definition value.h:1023
#define XLAT_CTX(_inst, _thread, _ex, _mctx, _env_data, _rctx)
Wrapper to create a xlat_ctx_t as a compound literal.
Definition xlat_ctx.h:95
xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_t const **child, request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in, void *env_data, fr_value_box_list_t *result)
Process the result of a previous nested expansion.
Definition xlat_eval.c:1124
void xlat_signal(xlat_func_signal_t signal, xlat_exp_t const *exp, request_t *request, void *rctx, fr_signal_t action)
Signal an xlat function.
Definition xlat_eval.c:1016
xlat_action_t xlat_frame_eval_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_t const **child, request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in, fr_value_box_list_t *result, xlat_func_t resume, void *rctx)
Call an xlat's resumption method.
Definition xlat_eval.c:1050
xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_t const **child, request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in)
Converts xlat nodes to value boxes.
Definition xlat_eval.c:1314
xlat_flags_t flags
Flags that control resolution and evaluation.
Definition xlat_priv.h:190
@ XLAT_BOX
fr_value_box_t
Definition xlat_priv.h:108
@ XLAT_TMPL
xlat attribute
Definition xlat_priv.h:112
@ XLAT_FUNC
xlat module
Definition xlat_priv.h:110
@ XLAT_GROUP
encapsulated string of xlats
Definition xlat_priv.h:116
char const *_CONST fmt
The original format string (a talloced buffer).
Definition xlat_priv.h:151
xlat_type_t _CONST type
type of this expansion.
Definition xlat_priv.h:155
static xlat_exp_t * xlat_exp_head(xlat_exp_head_t const *head)
Definition xlat_priv.h:209
An xlat expansion node.
Definition xlat_priv.h:148