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: d03c559b1d0fa7fe927b272df935b5f5c20b3214 $
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: d03c559b1d0fa7fe927b272df935b5f5c20b3214 $")
27
28#include <freeradius-devel/server/base.h>
29#include <freeradius-devel/util/debug.h>
30
31#include <ctype.h>
32#include <freeradius-devel/unlang/xlat_priv.h>
33#include "unlang_priv.h" /* Fixme - Should create a proper semi-public interface for the interpret */
34
35/** State of an xlat expansion
36 *
37 * State of one level of nesting within an xlat expansion.
38 */
39typedef struct {
40 TALLOC_CTX *ctx; //!< to allocate boxes and values in.
41 TALLOC_CTX *event_ctx; //!< for temporary events
42 xlat_exp_head_t const *head; //!< of the xlat list
43 xlat_exp_t const *exp; //!< current one we're evaluating
44 fr_dcursor_t values; //!< Values aggregated so far.
45
46 rindent_t indent; //!< indentation
47
48 void *env_data; //!< Expanded per call environment tmpls.
49 /*
50 * For func and alternate
51 */
52 fr_value_box_list_t out; //!< Head of the result of a nested
53 ///< expansion.
54 xlat_func_t resume; //!< called on resume
55 xlat_func_signal_t signal; //!< called on signal
56 fr_signal_t sigmask; //!< Signals to block
57 void *rctx; //!< for resume / signal
58
59 bool *success; //!< If set, where to record the result
60 ///< of the execution.
62
63/** Wrap an #fr_event_timer_t providing data needed for unlang events
64 *
65 */
66typedef struct {
67 request_t *request; //!< Request this event pertains to.
68 int fd; //!< File descriptor to wait on.
69 fr_unlang_xlat_timeout_t timeout; //!< Function to call on timeout.
70 fr_unlang_xlat_fd_event_t fd_read; //!< Function to call when FD is readable.
71 fr_unlang_xlat_fd_event_t fd_write; //!< Function to call when FD is writable.
72 fr_unlang_xlat_fd_event_t fd_error; //!< Function to call when FD has errored.
73 xlat_inst_t *inst; //!< xlat instance data.
74 xlat_thread_inst_t *thread; //!< Thread specific xlat instance.
75 void const *rctx; //!< rctx data to pass to callbacks.
76 fr_event_timer_t const *ev; //!< Event in this worker's event heap.
78
79typedef struct {
81 xlat_inst_t *inst; //!< xlat instance data.
82 xlat_thread_inst_t *thread; //!< Thread specific xlat instance.
83
84 fr_unlang_xlat_retry_t retry_cb; //!< callback to run on timeout
85 void *rctx; //!< rctx data to pass to timeout callback
86
87 fr_event_timer_t const *ev; //!< retry timer just for this xlat
88 fr_retry_t retry; //!< retry timers, etc.
90
91/** Frees an unlang event, removing it from the request's event loop
92 *
93 * @param[in] ev The event to free.
94 *
95 * @return 0
96 */
98{
99 if (ev->ev) {
100 (void) fr_event_timer_delete(&(ev->ev));
101 return 0;
102 }
103
104 if (ev->fd >= 0) {
106 }
107
108 return 0;
109}
110
111/** Call the callback registered for a timeout event
112 *
113 * @param[in] el the event timer was inserted into.
114 * @param[in] now The current time, as held by the event_list.
115 * @param[in] uctx unlang_module_event_t structure holding callbacks.
116 *
117 */
119{
120 unlang_xlat_event_t *ev = talloc_get_type_abort(uctx, unlang_xlat_event_t);
121
122 /*
123 * If the timeout's fired then the xlat must necessarily
124 * be yielded, so it's fine to pass in its rctx.
125 *
126 * It should be able to free the rctx if it wants to.
127 * We never free it explicitly, and instead rely on
128 * talloc parenting.
129 */
130 ev->timeout(XLAT_CTX(ev->inst->data,
131 ev->thread->data,
132 ev->thread->mctx, NULL,
133 UNCONST(void *, ev->rctx)),
134 ev->request, now);
135
136 /* Remove old references from the request */
137 talloc_free(ev);
138}
139
140/** Add a timeout for an xlat handler
141 *
142 * @note The timeout is automatically removed when the xlat is cancelled or resumed.
143 *
144 * @param[in] request the request
145 * @param[in] callback to run when the timeout hits
146 * @param[in] rctx passed to the callback
147 * @param[in] when when the timeout fires
148 * @return
149 * - <0 on error
150 * - 0 on success
151 */
153 fr_unlang_xlat_timeout_t callback, void const *rctx, fr_time_t when)
154{
155 unlang_stack_t *stack = request->stack;
156 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
158 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
159
160 fr_assert(stack->depth > 0);
162
163 if (!state->event_ctx) MEM(state->event_ctx = talloc_zero(state, bool));
164
165 ev = talloc_zero(state->event_ctx, unlang_xlat_event_t);
166 if (unlikely(!ev)) return -1;
167
168 ev->request = request;
169 ev->fd = -1;
170 ev->timeout = callback;
171 fr_assert(state->exp->type == XLAT_FUNC);
172 ev->inst = state->exp->call.inst;
174 ev->rctx = rctx;
175
177 &ev->ev, when, unlang_xlat_event_timeout_handler, ev) < 0) {
178 RPEDEBUG("Failed inserting event");
179 talloc_free(ev);
180 return -1;
181 }
182
183 talloc_set_destructor(ev, _unlang_xlat_event_free);
184
185 return 0;
186}
187
188/** Push a pre-compiled xlat onto the stack for evaluation
189 *
190 * @param[in] ctx To allocate value boxes and values in.
191 * @param[out] p_success If set, and execution succeeds, true will be written
192 * here. If execution fails, false will be written.
193 * @param[out] out Where to write the result of the expansion.
194 * @param[in] request to push xlat onto.
195 * @param[in] xlat head of list
196 * @param[in] node to evaluate.
197 * @param[in] top_frame Set to UNLANG_TOP_FRAME if the interpreter should return.
198 * Set to UNLANG_SUB_FRAME if the interprer should continue.
199 * @return
200 * - 0 on success.
201 * - -1 on failure.
202 */
203static int unlang_xlat_push_internal(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out,
204 request_t *request, xlat_exp_head_t const *xlat, xlat_exp_t *node, bool top_frame)
205{
206 /** Static instruction for performing xlat evaluations
207 *
208 */
209 static unlang_t xlat_instruction = {
211 .name = "xlat",
212 .debug_name = "xlat",
213 .actions = {
214 .actions = {
215 [RLM_MODULE_REJECT] = 0,
216 [RLM_MODULE_FAIL] = MOD_ACTION_RETURN, /* Exit out of nested levels */
217 [RLM_MODULE_OK] = 0,
218 [RLM_MODULE_HANDLED] = 0,
219 [RLM_MODULE_INVALID] = 0,
222 [RLM_MODULE_NOOP] = 0,
224 },
225 .retry = RETRY_INIT,
226 },
227 };
228
230 unlang_stack_t *stack = request->stack;
232
233 /*
234 * Push a new xlat eval frame onto the stack
235 */
236 if (unlang_interpret_push(request, &xlat_instruction,
237 RLM_MODULE_NOT_SET, UNLANG_NEXT_STOP, top_frame) < 0) return -1;
238 frame = &stack->frame[stack->depth];
239
240 /*
241 * Allocate its state, and setup a cursor for the xlat nodes
242 */
243 MEM(frame->state = state = talloc_zero(stack, unlang_frame_state_xlat_t));
244 state->head = xlat;
245 state->exp = node;
246 state->success = p_success;
247 state->ctx = ctx;
248
249 if (node) switch (node->type) {
250 case XLAT_GROUP:
251 case XLAT_BOX:
252 break;
253
254 case XLAT_TMPL:
255 if (tmpl_is_data(node->vpt)) break;
257
258 default:
259 RDEBUG("| %s", node->fmt);
260 break;
261 }
262
263 /*
264 * Initialise the input and output lists
265 */
266 fr_dcursor_init(&state->values, fr_value_box_list_dlist_head(out));
267 fr_value_box_list_init(&state->out);
268
269 return 0;
270}
271
272/** Push a pre-compiled xlat onto the stack for evaluation
273 *
274 * @param[in] ctx To allocate value boxes and values in.
275 * @param[out] p_success If set, and execution succeeds, true will be written
276 * here. If execution fails, false will be written.
277 * @param[out] out Where to write the result of the expansion.
278 * @param[in] request to push xlat onto.
279 * @param[in] xlat to evaluate.
280 * @param[in] top_frame Set to UNLANG_TOP_FRAME if the interpreter should return.
281 * Set to UNLANG_SUB_FRAME if the interprer should continue.
282 * @return
283 * - 0 on success.
284 * - -1 on failure.
285 */
286int unlang_xlat_push(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out,
287 request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
288{
290
291 return unlang_xlat_push_internal(ctx, p_success, out, request, xlat, xlat_exp_head(xlat), top_frame);
292}
293
294/** Push a pre-compiled xlat onto the stack for evaluation
295 *
296 * @param[in] ctx To allocate value boxes and values in.
297 * @param[out] p_success If set, and execution succeeds, true will be written
298 * here. If execution fails, false will be written.
299 * @param[out] out Where to write the result of the expansion.
300 * @param[in] request to push xlat onto.
301 * @param[in] node to evaluate. Only this node will be evaluated.
302 * @return
303 * - 0 on success.
304 * - -1 on failure.
305 */
306int unlang_xlat_push_node(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out,
307 request_t *request, xlat_exp_t *node)
308{
309 return unlang_xlat_push_internal(ctx, p_success, out, request, NULL, node, UNLANG_TOP_FRAME);
310}
311
313{
314 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
315 xlat_action_t xa;
316 xlat_exp_head_t const *child = NULL;
317
318 /*
319 * If the xlat is a function with a method_env, expand it before calling the function.
320 */
321 if ((state->exp->type == XLAT_FUNC) && state->exp->call.inst->call_env && !state->env_data) {
322 unlang_action_t ua = call_env_expand(state, request, NULL, &state->env_data,
323 state->exp->call.inst->call_env);
324 switch (ua) {
326 goto fail;
327
331
332 default:
333 break;
334 }
335 }
336
337 xa = xlat_frame_eval_repeat(state->ctx, &state->values, &child,
338 request, state->head, &state->exp, state->env_data, &state->out);
339 switch (xa) {
341 fr_assert(child);
342
343 repeatable_set(frame); /* Was cleared by the interpreter */
344
345 /*
346 * Clear out the results of any previous expansions
347 * at this level. A frame may be used to evaluate
348 * multiple sibling nodes.
349 */
350 fr_value_box_list_talloc_free(&state->out);
351 if (unlang_xlat_push(state->ctx, state->success, &state->out, request, child, false) < 0) {
352 *p_result = RLM_MODULE_FAIL;
353 REXDENT();
355 }
357
359 repeatable_set(frame); /* Call the xlat code on the way back down */
361
363 if (!state->resume) {
364 RWDEBUG("Missing call to unlang_xlat_yield()");
365 goto fail;
366 }
367 repeatable_set(frame);
368 return UNLANG_ACTION_YIELD;
369
370 case XLAT_ACTION_DONE:
371 if (state->success) *state->success = true;
372 *p_result = RLM_MODULE_OK;
373 REXDENT();
375
376 case XLAT_ACTION_FAIL:
377 fail:
378 if (state->success) *state->success = false;
379 *p_result = RLM_MODULE_FAIL;
380 REXDENT();
382
383 default:
384 fr_assert(0);
385 goto fail;
386 }
387}
388
389/** Stub function for calling the xlat interpreter
390 *
391 * Calls the xlat interpreter and translates its wants and needs into
392 * unlang_action_t codes.
393 */
395{
396 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
397 xlat_action_t xa;
398 xlat_exp_head_t const *child = NULL;
399
400 RINDENT_SAVE(state, request);
401 RINDENT();
402
403 xa = xlat_frame_eval(state->ctx, &state->values, &child, request, state->head, &state->exp);
404 switch (xa) {
406 fr_assert(child);
407
409
410 /*
411 * Clear out the results of any previous expansions
412 * at this level. A frame may be used to evaluate
413 * multiple sibling nodes.
414 */
415 fr_value_box_list_talloc_free(&state->out);
416 if (unlang_xlat_push(state->ctx, state->success, &state->out, request, child, false) < 0) {
417 *p_result = RLM_MODULE_FAIL;
418 RINDENT_RESTORE(request, state);
420 }
422
424 repeatable_set(frame); /* Call the xlat code on the way back down */
426
428 if (!state->resume) {
429 RWDEBUG("Missing call to unlang_xlat_yield()");
430 goto fail;
431 }
432 repeatable_set(frame);
433 return UNLANG_ACTION_YIELD;
434
435 case XLAT_ACTION_DONE:
436 if (state->success) *state->success = true;
437 *p_result = RLM_MODULE_OK;
438 RINDENT_RESTORE(request, state);
440
441 case XLAT_ACTION_FAIL:
442 fail:
443 if (state->success) *state->success = false;
444 *p_result = RLM_MODULE_FAIL;
445 RINDENT_RESTORE(request, state);
447
448 default:
449 fr_assert(0);
450 goto fail;
451 }
452}
453
454/** Send a signal (usually stop) to a request that's running an xlat expansions
455 *
456 * This is typically called via an "async" action, i.e. an action
457 * outside of the normal processing of the request.
458 *
459 * If there is no #xlat_func_signal_t callback defined, the action is ignored.
460 *
461 * @param[in] request The current request.
462 * @param[in] frame The current stack frame.
463 * @param[in] action What the request should do (the type of signal).
464 */
466{
467 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
468
469 /*
470 * Delete timers, etc. when the xlat is cancelled.
471 */
472 if (action == FR_SIGNAL_CANCEL) {
473 TALLOC_FREE(state->event_ctx);
474 }
475
476 if (!state->signal || (state->sigmask & action)) return;
477
478 xlat_signal(state->signal, state->exp, request, state->rctx, action);
479}
480
481/** Called when we're ready to resume processing the request
482 *
483 * @param[in] p_result the result of the xlat function.
484 * - RLM_MODULE_OK on success.
485 * - RLM_MODULE_FAIL on failure.
486 * @param[in] request to resume processing.
487 * @param[in] frame the current stack frame.
488 * @return
489 * - UNLANG_ACTION_YIELD if additional asynchronous
490 * operations need to be performed.
491 * - UNLANG_ACTION_CALCULATE_RESULT if done.
492 */
494{
495 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
496 xlat_action_t xa;
497 xlat_exp_head_t const *child = NULL;
498
499 fr_assert(state->resume != NULL);
500
501 /*
502 * Delete timers, etc. when the xlat is resumed.
503 */
504 TALLOC_FREE(state->event_ctx);
505
506 xa = xlat_frame_eval_resume(state->ctx, &state->values, &child, request, state->head, &state->exp,
507 &state->out, state->resume, state->rctx);
508 switch (xa) {
510 repeatable_set(frame);
511 return UNLANG_ACTION_YIELD;
512
513 case XLAT_ACTION_DONE:
514 if (state->success) *state->success = true;
515 *p_result = RLM_MODULE_OK;
516 RINDENT_RESTORE(request, state);
518
520 repeatable_set(frame);
522
524 fr_assert(child);
525
526 repeatable_set(frame); /* Was cleared by the interpreter */
527
528 /*
529 * Clear out the results of any previous expansions
530 * at this level. A frame may be used to evaluate
531 * multiple sibling nodes.
532 */
533 fr_value_box_list_talloc_free(&state->out);
534 if (unlang_xlat_push(state->ctx, state->success, &state->out, request, child, false) < 0) {
535 *p_result = RLM_MODULE_FAIL;
536 RINDENT_RESTORE(request, state);
538 }
540
541 case XLAT_ACTION_FAIL:
542 if (state->success) *state->success = false;
543 *p_result = RLM_MODULE_FAIL;
544 RINDENT_RESTORE(request, state);
546 /* DON'T SET DEFAULT */
547 }
548
549 fr_assert(0); /* Garbage xlat action */
550
551 *p_result = RLM_MODULE_FAIL;
552 RINDENT_RESTORE(request, state);
554}
555
556/** Yield a request back to the interpreter from within a module
557 *
558 * This passes control of the request back to the unlang interpreter, setting
559 * callbacks to execute when the request is 'signalled' asynchronously, or whatever
560 * timer or I/O event the module was waiting for occurs.
561 *
562 * @note The module function which calls #unlang_module_yield should return control
563 * of the C stack to the unlang interpreter immediately after calling #unlang_xlat_yield.
564 * A common pattern is to use ``return unlang_xlat_yield(...)``.
565 *
566 * @param[in] request The current request.
567 * @param[in] resume Called on unlang_interpret_mark_runnable().
568 * @param[in] signal Called on unlang_action().
569 * @param[in] sigmask Signals to block.
570 * @param[in] rctx to pass to the callbacks.
571 * @return always returns XLAT_ACTION_YIELD
572 */
574 xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask,
575 void *rctx)
576{
577 unlang_stack_t *stack = request->stack;
578 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
579 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
580
582
583 /*
584 * Over-ride whatever functions were there before.
585 */
586 state->resume = resume;
587 state->signal = signal;
588 state->sigmask = sigmask;
589 state->rctx = rctx;
590
591 return XLAT_ACTION_YIELD;
592}
593
594/** Frees an unlang event, removing it from the request's event loop
595 *
596 * @param[in] ev The event to free.
597 *
598 * @return 0
599 */
601{
602 if (ev->ev) (void) fr_event_timer_delete(&(ev->ev));
603
604 return 0;
605}
606
607/** Call the callback registered for a timeout event
608 *
609 * @param[in] el the event timer was inserted into.
610 * @param[in] now The current time, as held by the event_list.
611 * @param[in] uctx unlang_module_event_t structure holding callbacks.
612 *
613 */
615{
616 unlang_xlat_retry_t *ev = talloc_get_type_abort(uctx, unlang_xlat_retry_t);
617 request_t *request = ev->request;
618
619 switch (fr_retry_next(&ev->retry, now)) {
621 /*
622 * Call the module retry handler, with the state of the retry. On MRD / MRC, the
623 * module is made runnable again, and the "resume" function is called.
624 */
625 ev->retry_cb(XLAT_CTX(ev->inst->data,
626 ev->thread->data,
627 ev->thread->mctx, NULL,
628 UNCONST(void *, ev->rctx)),
629 ev->request, &ev->retry);
630
631 /*
632 * Reset the timer.
633 */
634 if (fr_event_timer_at(ev, unlang_interpret_event_list(request), &ev->ev, ev->retry.next,
635 unlang_xlat_event_retry_handler, request) < 0) {
636 RPEDEBUG("Failed inserting event");
637 talloc_free(ev);
639 }
640 return;
641
642 case FR_RETRY_MRD:
643 RDEBUG("Reached max_rtx_duration (%pVs > %pVs) - sending timeout",
645 break;
646
647 case FR_RETRY_MRC:
648 RDEBUG("Reached max_rtx_count %u- sending timeout",
649 ev->retry.config->mrc);
650 break;
651 }
652
653 /*
654 * Run the retry handler on MRD / MRC, too.
655 */
656 ev->retry_cb(XLAT_CTX(ev->inst->data,
657 ev->thread->data,
658 ev->thread->mctx, NULL,
659 UNCONST(void *, ev->rctx)),
660 ev->request, &ev->retry);
661
662 /*
663 * On final timeout, always mark the request as runnable.
664 */
665 talloc_free(ev);
667}
668
669
670/** Yield a request back to the interpreter, with retries
671 *
672 * This passes control of the request back to the unlang interpreter, setting
673 * callbacks to execute when the request is 'signalled' asynchronously, or when
674 * the retry timer hits.
675 *
676 * @note The module function which calls #unlang_module_yield_to_retry should return control
677 * of the C stack to the unlang interpreter immediately after calling #unlang_module_yield_to_retry.
678 * A common pattern is to use ``return unlang_module_yield_to_retry(...)``.
679 *
680 * @param[in] request The current request.
681 * @param[in] resume Called on unlang_interpret_mark_runnable().
682 * @param[in] retry Called on when a retry timer hits
683 * @param[in] signal Called on unlang_action().
684 * @param[in] sigmask Set of signals to block.
685 * @param[in] rctx to pass to the callbacks.
686 * @param[in] retry_cfg to set up the retries
687 * @return
688 * - XLAT_ACTION_YIELD on success
689 * - XLAT_ACTION_FAIL on failure
690 */
692 xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx,
693 fr_retry_config_t const *retry_cfg)
694{
695 unlang_stack_t *stack = request->stack;
696 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
698 unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
699
700 fr_assert(stack->depth > 0);
702
703 if (!state->event_ctx) MEM(state->event_ctx = talloc_zero(state, bool));
704
705 ev = talloc_zero(state->event_ctx, unlang_xlat_retry_t);
706 if (unlikely(!ev)) return XLAT_ACTION_FAIL;
707
708 ev->request = request;
709 fr_assert(state->exp->type == XLAT_FUNC);
710 ev->inst = state->exp->call.inst;
712 ev->retry_cb = retry;
713 ev->rctx = rctx;
714
715 fr_retry_init(&ev->retry, fr_time(), retry_cfg);
716
718 &ev->ev, ev->retry.next, unlang_xlat_event_retry_handler, ev) < 0) {
719 RPEDEBUG("Failed inserting event");
720 talloc_free(ev);
721 return XLAT_ACTION_FAIL;
722 }
723
724 talloc_set_destructor(ev, _unlang_xlat_retry_free);
725
726 return unlang_xlat_yield(request, resume, signal, sigmask, rctx);
727}
728
729/** Evaluate a "pure" (or not impure) xlat
730 *
731 * @param[in] ctx To allocate value boxes and values in.
732 * @param[out] out Where to write the result of the expansion.
733 * @param[in] request to push xlat onto.
734 * @param[in] xlat to evaluate.
735 * @return
736 * - 0 on success.
737 * - -1 on failure.
738 */
739int unlang_xlat_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat)
740{
741 bool success = false;
742
743 if (xlat->flags.impure_func) {
744 fr_strerror_const("Expansion requires async operations");
745 return -1;
746 }
747
748 if (unlang_xlat_push(ctx, &success, out, request, xlat, UNLANG_TOP_FRAME) < 0) return -1;
749
750 (void) unlang_interpret(request);
751
752 if (!success) return -1;
753
754 return 0;
755}
756
757/** Evaluate a "pure" (or not impure) xlat
758 *
759 * @param[in] ctx To allocate value boxes and values in.
760 * @param[out] vb output value-box
761 * @param[in] type expected type
762 * @param[in] enumv enum for type
763 * @param[in] request to push xlat onto.
764 * @param[in] xlat to evaluate.
765 * @return
766 * - 0 on success.
767 * - -1 on failure.
768 */
769int 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)
770{
771 fr_value_box_t *src;
772 fr_value_box_list_t list;
773
775 fr_strerror_const("Invalid type for output of evaluation");
776 return -1;
777 }
778
779 fr_value_box_list_init(&list);
780
781 if (unlang_xlat_eval(ctx, &list, request, xlat) < 0) return -1;
782
783 fr_value_box_init(vb, type, NULL, false);
784
785 switch (type) {
786 default:
787 /*
788 * Take only the first entry from the list.
789 */
790 src = fr_value_box_list_head(&list);
791 if (!src) {
792 fr_strerror_const("Expression returned no results");
793 fail:
794 fr_value_box_list_talloc_free(&list);
795 return -1;
796 }
797
798 if (fr_value_box_cast(ctx, vb, type, enumv, src) < 0) goto fail;
799 fr_value_box_list_talloc_free(&list);
800 break;
801
802 case FR_TYPE_STRING:
803 case FR_TYPE_OCTETS:
804 /*
805 * No output: create an empty string.
806 *
807 * The "concat in place" function returns an error for empty input, which is arguably not
808 * what we want to do here.
809 */
810 if (fr_value_box_list_empty(&list)) {
811 break;
812 }
813
814 if (fr_value_box_list_concat_in_place(ctx, vb, &list, type, FR_VALUE_BOX_LIST_FREE_BOX, false, SIZE_MAX) < 0) {
815 goto fail;
816 }
817 break;
818 }
819
820 return 0;
821}
822
823
824/** Register xlat operation with the interpreter
825 *
826 */
828{
830 &(unlang_op_t){
831 .name = "xlat_eval",
832 .interpret = unlang_xlat,
833 .signal = unlang_xlat_signal,
834 .debug_braces = false,
835 .frame_state_size = sizeof(unlang_frame_state_xlat_t),
836 .frame_state_type = "unlang_frame_state_xlat_t",
837 });
838}
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:43
@ 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:42
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:483
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:322
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
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:295
#define fr_dcursor_init(_cursor, _head)
Initialise a cursor.
Definition dcursor.h:732
#define MEM(x)
Definition debug.h:36
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:62
#define fr_event_timer_at(...)
Definition event.h:250
rlm_rcode_t unlang_interpret(request_t *request)
Run the interpreter for a current request.
Definition interpret.c:770
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1359
int unlang_interpret_push(request_t *request, unlang_t const *instruction, rlm_rcode_t default_rcode, bool do_next_sibling, bool top_frame)
Push a new frame onto the stack.
Definition interpret.c:161
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:1764
#define UNLANG_TOP_FRAME
Definition interpret.h:35
#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(int type, unlang_op_t *op)
Register an operation with the interpreter.
Definition base.c:63
talloc_free(reap)
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
Definition event.c:1611
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:1260
Stores all information relating to an event list.
Definition event.c:411
A timer event.
Definition event.c:102
static char * stack[MAX_STACK]
Definition radmin.c:158
fr_type_t
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_OCTETS
Raw octets.
@ MOD_ACTION_RETURN
Definition mod_action.h:40
#define fr_assert(_expr)
Definition rad_assert.h:38
#define RDEBUG(fmt,...)
Definition radclient.h:53
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition rcode.h:45
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:43
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:42
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition rcode.h:46
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:41
@ RLM_MODULE_NOTFOUND
User not found.
Definition rcode.h:47
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:49
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:51
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition rcode.h:48
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition rcode.h:44
#define tmpl_is_data(vpt)
Definition tmpl.h:211
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:282
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition time.h:229
"server local" time.
Definition time.h:69
goto success
Definition tmpl_eval.c:1455
static fr_event_list_t * el
static void unlang_xlat_event_retry_handler(UNUSED fr_event_list_t *el, fr_time_t now, void *uctx)
Call the callback registered for a timeout event.
Definition xlat.c:614
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:739
static int unlang_xlat_push_internal(TALLOC_CTX *ctx, bool *p_success, 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:203
xlat_exp_head_t const * head
of the xlat list
Definition xlat.c:42
TALLOC_CTX * ctx
to allocate boxes and values in.
Definition xlat.c:40
fr_unlang_xlat_fd_event_t fd_read
Function to call when FD is readable.
Definition xlat.c:70
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:769
TALLOC_CTX * event_ctx
for temporary events
Definition xlat.c:41
xlat_func_signal_t signal
called on signal
Definition xlat.c:55
xlat_thread_inst_t * thread
Thread specific xlat instance.
Definition xlat.c:82
fr_event_timer_t const * ev
Event in this worker's event heap.
Definition xlat.c:76
static void unlang_xlat_event_timeout_handler(UNUSED fr_event_list_t *el, fr_time_t now, void *uctx)
Call the callback registered for a timeout event.
Definition xlat.c:118
static unlang_action_t unlang_xlat_resume(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Called when we're ready to resume processing the request.
Definition xlat.c:493
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:97
void * rctx
for resume / signal
Definition xlat.c:57
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:691
fr_dcursor_t values
Values aggregated so far.
Definition xlat.c:44
fr_value_box_list_t out
Head of the result of a nested expansion.
Definition xlat.c:52
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:573
xlat_func_t resume
called on resume
Definition xlat.c:54
fr_unlang_xlat_retry_t retry_cb
callback to run on timeout
Definition xlat.c:84
fr_retry_t retry
retry timers, etc.
Definition xlat.c:88
request_t * request
Request this event pertains to.
Definition xlat.c:67
bool * success
If set, where to record the result of the execution.
Definition xlat.c:59
int fd
File descriptor to wait on.
Definition xlat.c:68
fr_unlang_xlat_timeout_t timeout
Function to call on timeout.
Definition xlat.c:69
request_t * request
Definition xlat.c:80
int unlang_xlat_push_node(TALLOC_CTX *ctx, bool *p_success, 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:306
xlat_inst_t * inst
xlat instance data.
Definition xlat.c:73
static unlang_action_t unlang_xlat(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Stub function for calling the xlat interpreter.
Definition xlat.c:394
xlat_inst_t * inst
xlat instance data.
Definition xlat.c:81
void * rctx
rctx data to pass to timeout callback
Definition xlat.c:85
fr_unlang_xlat_fd_event_t fd_write
Function to call when FD is writable.
Definition xlat.c:71
fr_signal_t sigmask
Signals to block.
Definition xlat.c:56
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:600
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:152
rindent_t indent
indentation
Definition xlat.c:46
int unlang_xlat_push(TALLOC_CTX *ctx, bool *p_success, 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:286
void * env_data
Expanded per call environment tmpls.
Definition xlat.c:48
void const * rctx
rctx data to pass to callbacks.
Definition xlat.c:75
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:465
static unlang_action_t unlang_xlat_repeat(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition xlat.c:312
void unlang_xlat_init(void)
Register xlat operation with the interpreter.
Definition xlat.c:827
xlat_exp_t const * exp
current one we're evaluating
Definition xlat.c:43
fr_event_timer_t const * ev
retry timer just for this xlat
Definition xlat.c:87
fr_unlang_xlat_fd_event_t fd_error
Function to call when FD has errored.
Definition xlat.c:72
xlat_thread_inst_t * thread
Thread specific xlat instance.
Definition xlat.c:74
State of an xlat expansion.
Definition xlat.c:39
Wrap an fr_event_timer_t providing data needed for unlang events.
Definition xlat.c:66
void * data
Thread specific instance data.
Definition xlat.h:98
xlat_thread_inst_t * xlat_thread_instance_find(xlat_exp_t const *node)
Retrieve xlat/thread specific instance data.
Definition xlat_inst.c:407
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:210
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:241
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:197
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:230
void * data
xlat node specific instance data.
Definition xlat.h:82
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:183
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
bool impure_func
xlat contains an impure function
Definition xlat.h:115
module_ctx_t const * mctx
A synthesised module calling ctx containing module global and thread instance data.
Definition xlat.h:100
Instance data for an xlat expansion node.
Definition xlat.h:75
Thread specific instance data for xlat expansion node.
Definition xlat.h:89
Private interpreter structures and functions.
void * state
Stack frame specialisations.
#define UNLANG_NEXT_STOP
Definition unlang_priv.h:92
@ UNLANG_TYPE_XLAT
Represents one level of an xlat expansion.
Definition unlang_priv.h:74
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.
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
#define RETRY_INIT
Definition retry.h:39
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:371
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
Definition value.c:3352
int fr_value_box_list_concat_in_place(TALLOC_CTX *ctx, fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type, fr_value_box_list_action_t proc_action, bool flatten, size_t max_size)
Concatenate a list of value boxes.
Definition value.c:5777
@ FR_VALUE_BOX_LIST_FREE_BOX
Free each processed box.
Definition value.h:218
#define fr_box_time_delta(_val)
Definition value.h:343
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:587
static size_t char ** out
Definition value.h:997
#define XLAT_CTX(_inst, _thread, _mctx, _env_data, _rctx)
Wrapper to create a xlat_ctx_t as a compound literal.
Definition xlat_ctx.h:93
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:944
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:836
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:870
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:1119
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:107
@ XLAT_TMPL
xlat attribute
Definition xlat_priv.h:113
@ XLAT_FUNC
xlat module
Definition xlat_priv.h:109
@ XLAT_GROUP
encapsulated string of xlats
Definition xlat_priv.h:117
char const *_CONST fmt
The original format string (a talloced buffer).
Definition xlat_priv.h:154
xlat_type_t _CONST type
type of this expansion.
Definition xlat_priv.h:158
static xlat_exp_t * xlat_exp_head(xlat_exp_head_t const *head)
Definition xlat_priv.h:207
An xlat expansion node.
Definition xlat_priv.h:151