The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: b85edbafb1d0895524878007a184188a285aaa91 $
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  */
26 RCSID("$Id: b85edbafb1d0895524878007a184188a285aaa91 $")
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  */
39 typedef 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  */
66 typedef 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 
79 /** Frees an unlang event, removing it from the request's event loop
80  *
81  * @param[in] ev The event to free.
82  *
83  * @return 0
84  */
86 {
87  if (ev->ev) {
88  (void) fr_event_timer_delete(&(ev->ev));
89  return 0;
90  }
91 
92  if (ev->fd >= 0) {
94  }
95 
96  return 0;
97 }
98 
99 /** Call the callback registered for a timeout event
100  *
101  * @param[in] el the event timer was inserted into.
102  * @param[in] now The current time, as held by the event_list.
103  * @param[in] uctx unlang_module_event_t structure holding callbacks.
104  *
105  */
107 {
108  unlang_xlat_event_t *ev = talloc_get_type_abort(uctx, unlang_xlat_event_t);
109 
110  /*
111  * If the timeout's fired then the xlat must necessarily
112  * be yielded, so it's fine to pass in its rctx.
113  *
114  * It should be able to free the rctx if it wants to.
115  * We never free it explicitly, and instead rely on
116  * talloc parenting.
117  */
118  ev->timeout(XLAT_CTX(ev->inst->data,
119  ev->thread->data,
120  ev->thread->mctx, NULL,
121  UNCONST(void *, ev->rctx)),
122  ev->request, now);
123 
124  /* Remove old references from the request */
125  talloc_free(ev);
126 }
127 
128 /** Add a timeout for an xlat handler
129  *
130  * @note The timeout is automatically removed when the xlat is cancelled or resumed.
131  *
132  * @param[in] request the request
133  * @param[in] callback to run when the timeout hits
134  * @param[in] rctx passed to the callback
135  * @param[in] when when the timeout fires
136  * @return
137  * - <0 on error
138  * - 0 on success
139  */
141  fr_unlang_xlat_timeout_t callback, void const *rctx, fr_time_t when)
142 {
143  unlang_stack_t *stack = request->stack;
144  unlang_stack_frame_t *frame = &stack->frame[stack->depth];
146  unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
147 
148  fr_assert(stack->depth > 0);
150 
151  if (!state->event_ctx) MEM(state->event_ctx = talloc_zero(state, bool));
152 
153  ev = talloc_zero(state->event_ctx, unlang_xlat_event_t);
154  if (unlikely(!ev)) return -1;
155 
156  ev->request = request;
157  ev->fd = -1;
158  ev->timeout = callback;
159  fr_assert(state->exp->type == XLAT_FUNC);
160  ev->inst = state->exp->call.inst;
161  ev->thread = xlat_thread_instance_find(state->exp);
162  ev->rctx = rctx;
163 
164  if (fr_event_timer_at(request, unlang_interpret_event_list(request),
165  &ev->ev, when, unlang_xlat_event_timeout_handler, ev) < 0) {
166  RPEDEBUG("Failed inserting event");
167  talloc_free(ev);
168  return -1;
169  }
170 
171  talloc_set_destructor(ev, _unlang_xlat_event_free);
172 
173  return 0;
174 }
175 
176 /** Push a pre-compiled xlat onto the stack for evaluation
177  *
178  * @param[in] ctx To allocate value boxes and values in.
179  * @param[out] p_success If set, and execution succeeds, true will be written
180  * here. If execution fails, false will be written.
181  * @param[out] out Where to write the result of the expansion.
182  * @param[in] request to push xlat onto.
183  * @param[in] xlat head of list
184  * @param[in] node to evaluate.
185  * @param[in] top_frame Set to UNLANG_TOP_FRAME if the interpreter should return.
186  * Set to UNLANG_SUB_FRAME if the interprer should continue.
187  * @return
188  * - 0 on success.
189  * - -1 on failure.
190  */
191 static int unlang_xlat_push_internal(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out,
192  request_t *request, xlat_exp_head_t const *xlat, xlat_exp_t *node, bool top_frame)
193 {
194  /** Static instruction for performing xlat evaluations
195  *
196  */
197  static unlang_t xlat_instruction = {
199  .name = "xlat",
200  .debug_name = "xlat",
201  .actions = {
202  .actions = {
203  [RLM_MODULE_REJECT] = 0,
204  [RLM_MODULE_FAIL] = MOD_ACTION_RETURN, /* Exit out of nested levels */
205  [RLM_MODULE_OK] = 0,
206  [RLM_MODULE_HANDLED] = 0,
207  [RLM_MODULE_INVALID] = 0,
208  [RLM_MODULE_DISALLOW] = 0,
209  [RLM_MODULE_NOTFOUND] = 0,
210  [RLM_MODULE_NOOP] = 0,
211  [RLM_MODULE_UPDATED] = 0
212  },
213  .retry = RETRY_INIT,
214  },
215  };
216 
218  unlang_stack_t *stack = request->stack;
219  unlang_stack_frame_t *frame;
220 
221  /*
222  * Push a new xlat eval frame onto the stack
223  */
224  if (unlang_interpret_push(request, &xlat_instruction,
225  RLM_MODULE_NOT_SET, UNLANG_NEXT_STOP, top_frame) < 0) return -1;
226  frame = &stack->frame[stack->depth];
227 
228  /*
229  * Allocate its state, and setup a cursor for the xlat nodes
230  */
231  MEM(frame->state = state = talloc_zero(stack, unlang_frame_state_xlat_t));
232  state->head = xlat;
233  state->exp = node;
234  state->success = p_success;
235  state->ctx = ctx;
236 
237  if (node) switch (node->type) {
238  case XLAT_GROUP:
239  case XLAT_BOX:
240  break;
241 
242  case XLAT_TMPL:
243  if (tmpl_is_data(node->vpt)) break;
244  FALL_THROUGH;
245 
246  default:
247  RDEBUG("| %s", node->fmt);
248  break;
249  }
250 
251  /*
252  * Initialise the input and output lists
253  */
254  fr_dcursor_init(&state->values, fr_value_box_list_dlist_head(out));
255  fr_value_box_list_init(&state->out);
256 
257  return 0;
258 }
259 
260 /** Push a pre-compiled xlat onto the stack for evaluation
261  *
262  * @param[in] ctx To allocate value boxes and values in.
263  * @param[out] p_success If set, and execution succeeds, true will be written
264  * here. If execution fails, false will be written.
265  * @param[out] out Where to write the result of the expansion.
266  * @param[in] request to push xlat onto.
267  * @param[in] xlat to evaluate.
268  * @param[in] top_frame Set to UNLANG_TOP_FRAME if the interpreter should return.
269  * Set to UNLANG_SUB_FRAME if the interprer should continue.
270  * @return
271  * - 0 on success.
272  * - -1 on failure.
273  */
274 int unlang_xlat_push(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out,
275  request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
276 {
278 
279  return unlang_xlat_push_internal(ctx, p_success, out, request, xlat, xlat_exp_head(xlat), top_frame);
280 }
281 
282 /** Push a pre-compiled xlat onto the stack for evaluation
283  *
284  * @param[in] ctx To allocate value boxes and values in.
285  * @param[out] p_success If set, and execution succeeds, true will be written
286  * here. If execution fails, false will be written.
287  * @param[out] out Where to write the result of the expansion.
288  * @param[in] request to push xlat onto.
289  * @param[in] node to evaluate. Only this node will be evaluated.
290  * @return
291  * - 0 on success.
292  * - -1 on failure.
293  */
294 int unlang_xlat_push_node(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out,
295  request_t *request, xlat_exp_t *node)
296 {
297  return unlang_xlat_push_internal(ctx, p_success, out, request, NULL, node, UNLANG_TOP_FRAME);
298 }
299 
301 {
302  unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
303  xlat_action_t xa;
304  xlat_exp_head_t const *child = NULL;
305 
306  /*
307  * If the xlat is a function with a method_env, expand it before calling the function.
308  */
309  if ((state->exp->type == XLAT_FUNC) && state->exp->call.inst->call_env && !state->env_data) {
310  unlang_action_t ua = call_env_expand(state, request, NULL, &state->env_data,
311  state->exp->call.inst->call_env);
312  switch (ua) {
313  case UNLANG_ACTION_FAIL:
314  goto fail;
315 
319 
320  default:
321  break;
322  }
323  }
324 
325  xa = xlat_frame_eval_repeat(state->ctx, &state->values, &child,
326  request, state->head, &state->exp, state->env_data, &state->out);
327  switch (xa) {
329  fr_assert(child);
330 
331  repeatable_set(frame); /* Was cleared by the interpreter */
332 
333  /*
334  * Clear out the results of any previous expansions
335  * at this level. A frame may be used to evaluate
336  * multiple sibling nodes.
337  */
338  fr_value_box_list_talloc_free(&state->out);
339  if (unlang_xlat_push(state->ctx, state->success, &state->out, request, child, false) < 0) {
340  *p_result = RLM_MODULE_FAIL;
341  REXDENT();
343  }
345 
347  repeatable_set(frame); /* Call the xlat code on the way back down */
349 
350  case XLAT_ACTION_YIELD:
351  if (!state->resume) {
352  RWDEBUG("Missing call to unlang_xlat_yield()");
353  goto fail;
354  }
355  repeatable_set(frame);
356  return UNLANG_ACTION_YIELD;
357 
358  case XLAT_ACTION_DONE:
359  if (state->success) *state->success = true;
360  *p_result = RLM_MODULE_OK;
361  REXDENT();
363 
364  case XLAT_ACTION_FAIL:
365  fail:
366  if (state->success) *state->success = false;
367  *p_result = RLM_MODULE_FAIL;
368  REXDENT();
370 
371  default:
372  fr_assert(0);
373  goto fail;
374  }
375 }
376 
377 /** Stub function for calling the xlat interpreter
378  *
379  * Calls the xlat interpreter and translates its wants and needs into
380  * unlang_action_t codes.
381  */
383 {
384  unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
385  xlat_action_t xa;
386  xlat_exp_head_t const *child = NULL;
387 
388  RINDENT_SAVE(state, request);
389  RINDENT();
390 
391  xa = xlat_frame_eval(state->ctx, &state->values, &child, request, state->head, &state->exp);
392  switch (xa) {
394  fr_assert(child);
395 
397 
398  /*
399  * Clear out the results of any previous expansions
400  * at this level. A frame may be used to evaluate
401  * multiple sibling nodes.
402  */
403  fr_value_box_list_talloc_free(&state->out);
404  if (unlang_xlat_push(state->ctx, state->success, &state->out, request, child, false) < 0) {
405  *p_result = RLM_MODULE_FAIL;
406  RINDENT_RESTORE(request, state);
408  }
410 
412  repeatable_set(frame); /* Call the xlat code on the way back down */
414 
415  case XLAT_ACTION_YIELD:
416  if (!state->resume) {
417  RWDEBUG("Missing call to unlang_xlat_yield()");
418  goto fail;
419  }
420  repeatable_set(frame);
421  return UNLANG_ACTION_YIELD;
422 
423  case XLAT_ACTION_DONE:
424  if (state->success) *state->success = true;
425  *p_result = RLM_MODULE_OK;
426  RINDENT_RESTORE(request, state);
428 
429  case XLAT_ACTION_FAIL:
430  fail:
431  if (state->success) *state->success = false;
432  *p_result = RLM_MODULE_FAIL;
433  RINDENT_RESTORE(request, state);
435 
436  default:
437  fr_assert(0);
438  goto fail;
439  }
440 }
441 
442 /** Send a signal (usually stop) to a request that's running an xlat expansions
443  *
444  * This is typically called via an "async" action, i.e. an action
445  * outside of the normal processing of the request.
446  *
447  * If there is no #xlat_func_signal_t callback defined, the action is ignored.
448  *
449  * @param[in] request The current request.
450  * @param[in] frame The current stack frame.
451  * @param[in] action What the request should do (the type of signal).
452  */
453 static void unlang_xlat_signal(request_t *request, unlang_stack_frame_t *frame, fr_signal_t action)
454 {
455  unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
456 
457  /*
458  * Delete timers, etc. when the xlat is cancelled.
459  */
460  if (action == FR_SIGNAL_CANCEL) {
461  TALLOC_FREE(state->event_ctx);
462  }
463 
464  if (!state->signal || (state->sigmask & action)) return;
465 
466  xlat_signal(state->signal, state->exp, request, state->rctx, action);
467 }
468 
469 /** Called when we're ready to resume processing the request
470  *
471  * @param[in] p_result the result of the xlat function.
472  * - RLM_MODULE_OK on success.
473  * - RLM_MODULE_FAIL on failure.
474  * @param[in] request to resume processing.
475  * @param[in] frame the current stack frame.
476  * @return
477  * - UNLANG_ACTION_YIELD if additional asynchronous
478  * operations need to be performed.
479  * - UNLANG_ACTION_CALCULATE_RESULT if done.
480  */
482 {
483  unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
484  xlat_action_t xa;
485  xlat_exp_head_t const *child = NULL;
486 
487  fr_assert(state->resume != NULL);
488 
489  /*
490  * Delete timers, etc. when the xlat is resumed.
491  */
492  TALLOC_FREE(state->event_ctx);
493 
494  xa = xlat_frame_eval_resume(state->ctx, &state->values, &child, request, state->head, &state->exp,
495  &state->out, state->resume, state->rctx);
496  switch (xa) {
497  case XLAT_ACTION_YIELD:
498  repeatable_set(frame);
499  return UNLANG_ACTION_YIELD;
500 
501  case XLAT_ACTION_DONE:
502  if (state->success) *state->success = true;
503  *p_result = RLM_MODULE_OK;
504  RINDENT_RESTORE(request, state);
506 
508  repeatable_set(frame);
510 
512  fr_assert(child);
513 
514  repeatable_set(frame); /* Was cleared by the interpreter */
515 
516  /*
517  * Clear out the results of any previous expansions
518  * at this level. A frame may be used to evaluate
519  * multiple sibling nodes.
520  */
521  fr_value_box_list_talloc_free(&state->out);
522  if (unlang_xlat_push(state->ctx, state->success, &state->out, request, child, false) < 0) {
523  *p_result = RLM_MODULE_FAIL;
524  RINDENT_RESTORE(request, state);
526  }
528 
529  case XLAT_ACTION_FAIL:
530  if (state->success) *state->success = false;
531  *p_result = RLM_MODULE_FAIL;
532  RINDENT_RESTORE(request, state);
534  /* DON'T SET DEFAULT */
535  }
536 
537  fr_assert(0); /* Garbage xlat action */
538 
539  *p_result = RLM_MODULE_FAIL;
540  RINDENT_RESTORE(request, state);
542 }
543 
544 /** Yield a request back to the interpreter from within a module
545  *
546  * This passes control of the request back to the unlang interpreter, setting
547  * callbacks to execute when the request is 'signalled' asynchronously, or whatever
548  * timer or I/O event the module was waiting for occurs.
549  *
550  * @note The module function which calls #unlang_module_yield should return control
551  * of the C stack to the unlang interpreter immediately after calling #unlang_xlat_yield.
552  * A common pattern is to use ``return unlang_xlat_yield(...)``.
553  *
554  * @param[in] request The current request.
555  * @param[in] resume Called on unlang_interpret_mark_runnable().
556  * @param[in] signal Called on unlang_action().
557  * @param[in] sigmask Signals to block.
558  * @param[in] rctx to pass to the callbacks.
559  * @return always returns XLAT_ACTION_YIELD
560  */
562  xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask,
563  void *rctx)
564 {
565  unlang_stack_t *stack = request->stack;
566  unlang_stack_frame_t *frame = &stack->frame[stack->depth];
567  unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
568 
569  frame->process = unlang_xlat_resume;
570 
571  /*
572  * Over-ride whatever functions were there before.
573  */
574  state->resume = resume;
575  state->signal = signal;
576  state->sigmask = sigmask;
577  state->rctx = rctx;
578 
579  return XLAT_ACTION_YIELD;
580 }
581 
582 /** Evaluate a "pure" (or not impure) xlat
583  *
584  * @param[in] ctx To allocate value boxes and values in.
585  * @param[out] out Where to write the result of the expansion.
586  * @param[in] request to push xlat onto.
587  * @param[in] xlat to evaluate.
588  * @return
589  * - 0 on success.
590  * - -1 on failure.
591  */
592 int unlang_xlat_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat)
593 {
594  bool success = false;
595 
596  if (xlat->flags.impure_func) {
597  fr_strerror_const("Expansion requires async operations");
598  return -1;
599  }
600 
601  if (unlang_xlat_push(ctx, &success, out, request, xlat, UNLANG_TOP_FRAME) < 0) return -1;
602 
603  (void) unlang_interpret(request);
604 
605  if (!success) return -1;
606 
607  return 0;
608 }
609 
610 /** Evaluate a "pure" (or not impure) xlat
611  *
612  * @param[in] ctx To allocate value boxes and values in.
613  * @param[out] vb output value-box
614  * @param[in] type expected type
615  * @param[in] enumv enum for type
616  * @param[in] request to push xlat onto.
617  * @param[in] xlat to evaluate.
618  * @return
619  * - 0 on success.
620  * - -1 on failure.
621  */
622 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)
623 {
624  fr_value_box_t *src;
625  fr_value_box_list_t list;
626 
628  fr_strerror_const("Invalid type for output of evaluation");
629  return -1;
630  }
631 
632  fr_value_box_list_init(&list);
633 
634  if (unlang_xlat_eval(ctx, &list, request, xlat) < 0) return -1;
635 
636  fr_value_box_init(vb, type, NULL, false);
637 
638  switch (type) {
639  default:
640  /*
641  * Take only the first entry from the list.
642  */
643  src = fr_value_box_list_head(&list);
644  if (!src) {
645  fr_strerror_const("Expression returned no results");
646  fail:
647  fr_value_box_list_talloc_free(&list);
648  return -1;
649  }
650 
651  if (fr_value_box_cast(ctx, vb, type, enumv, src) < 0) goto fail;
652  fr_value_box_list_talloc_free(&list);
653  break;
654 
655  case FR_TYPE_STRING:
656  case FR_TYPE_OCTETS:
657  /*
658  * No output: create an empty string.
659  *
660  * The "concat in place" function returns an error for empty input, which is arguably not
661  * what we want to do here.
662  */
663  if (fr_value_box_list_empty(&list)) {
664  break;
665  }
666 
667  if (fr_value_box_list_concat_in_place(ctx, vb, &list, type, FR_VALUE_BOX_LIST_FREE_BOX, false, SIZE_MAX) < 0) {
668  goto fail;
669  }
670  break;
671  }
672 
673  return 0;
674 }
675 
676 
677 /** Register xlat operation with the interpreter
678  *
679  */
681 {
683  &(unlang_op_t){
684  .name = "xlat_eval",
685  .interpret = unlang_xlat,
686  .signal = unlang_xlat_signal,
687  .debug_braces = false,
688  .frame_state_size = sizeof(unlang_frame_state_xlat_t),
689  .frame_state_type = "unlang_frame_state_xlat_t",
690  });
691 }
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:165
#define RCSID(id)
Definition: build.h:481
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
#define unlikely(_x)
Definition: build.h:379
#define UNUSED
Definition: build.h:313
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
fr_dcursor_eval_t void const * uctx
Definition: dcursor.h:546
@ 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
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition: interpret.c:1764
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
#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
Definition: log.h:40
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
Definition: merged_model.c:80
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
@ MOD_ACTION_RETURN
Definition: mod_action.h:40
#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
Definition: signal.h:48
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_aka_sim_id_type_t type
#define talloc_get_type_abort_const
Definition: talloc.h:282
"server local" time.
Definition: time.h:69
goto success
Definition: tmpl_eval.c:1455
static fr_event_list_t * el
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:592
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:191
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:622
TALLOC_CTX * event_ctx
for temporary events
Definition: xlat.c:41
xlat_func_signal_t signal
called on signal
Definition: xlat.c:55
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:106
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:481
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:85
void * rctx
for resume / signal
Definition: xlat.c:57
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:561
xlat_func_t resume
called on resume
Definition: xlat.c:54
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
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:294
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:382
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
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:140
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:274
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:453
static unlang_action_t unlang_xlat_repeat(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition: xlat.c:300
void unlang_xlat_init(void)
Register xlat operation with the interpreter.
Definition: xlat.c:680
xlat_exp_t const * exp
current one we're evaluating
Definition: xlat.c:43
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:96
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:194
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(* 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:225
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:214
void * data
xlat node specific instance data.
Definition: xlat.h:80
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:181
xlat_action_t
Definition: xlat.h:35
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition: xlat.h:42
@ XLAT_ACTION_YIELD
An xlat function pushed a resume frame onto the stack.
Definition: xlat.h:40
@ XLAT_ACTION_PUSH_UNLANG
An xlat function pushed an unlang frame onto the unlang stack.
Definition: xlat.h:37
@ XLAT_ACTION_PUSH_CHILD
A deeper level of nesting needs to be evaluated.
Definition: xlat.h:36
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition: xlat.h:41
bool impure_func
xlat contains an impure function
Definition: xlat.h:113
module_ctx_t const * mctx
A synthesised module calling ctx containing module global and thread instance data.
Definition: xlat.h:98
Instance data for an xlat expansion node.
Definition: xlat.h:73
Thread specific instance data for xlat expansion node.
Definition: xlat.h:87
Private interpreter structures and functions.
void * state
Stack frame specialisations.
Definition: unlang_priv.h:296
#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.
Definition: unlang_priv.h:518
unlang_t const * instruction
The unlang node we're evaluating.
Definition: unlang_priv.h:281
static void repeatable_set(unlang_stack_frame_t *frame)
Definition: unlang_priv.h:345
unlang_process_t process
function to call for interpreting this stack frame
Definition: unlang_priv.h:284
unlang_type_t type
The specialisation of this node.
Definition: unlang_priv.h:117
An unlang operation.
Definition: unlang_priv.h:204
A node in a graph of unlang_op_t (s) that we execute.
Definition: unlang_priv.h:112
Our interpreter stack, as distinct from the C stack.
Definition: unlang_priv.h:280
An unlang stack associated with a request.
Definition: unlang_priv.h:314
#define RETRY_INIT
Definition: retry.h:39
#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_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:1110
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
static xlat_exp_t * xlat_exp_head(xlat_exp_head_t const *head)
Definition: xlat_priv.h:207
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
An xlat expansion node.
Definition: xlat_priv.h:151