The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
interpret.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: 3873376d28a586241b1b9a6b0824f3e7e97f264c $
19  *
20  * @file unlang/interpret.c
21  * @brief Execute compiled unlang structures using an iterative interpret.
22  *
23  * @copyright 2006-2016 The FreeRADIUS server project
24  */
25 RCSID("$Id: 3873376d28a586241b1b9a6b0824f3e7e97f264c $")
26 
27 #include <freeradius-devel/server/base.h>
28 #include <freeradius-devel/server/modpriv.h>
29 #include <freeradius-devel/unlang/xlat_func.h>
30 #include <freeradius-devel/unlang/xlat.h>
31 #include <freeradius-devel/util/time.h>
32 
33 #include "interpret_priv.h"
34 #include "module_priv.h"
35 #include "parallel_priv.h"
36 
37 
38 /** The default interpreter instance for this thread
39  */
41 
43  { L("unwind"), UNLANG_ACTION_UNWIND },
44  { L("calculate-result"), UNLANG_ACTION_CALCULATE_RESULT },
45  { L("next"), UNLANG_ACTION_EXECUTE_NEXT },
46  { L("pushed-child"), UNLANG_ACTION_PUSHED_CHILD },
47  { L("stop"), UNLANG_ACTION_STOP_PROCESSING },
48  { L("yield"), UNLANG_ACTION_YIELD }
49 };
51 
53  { L("pop"), UNLANG_FRAME_ACTION_POP },
54  { L("next"), UNLANG_FRAME_ACTION_NEXT },
55  { L("yield"), UNLANG_FRAME_ACTION_YIELD }
56 };
58 
59 #ifndef NDEBUG
60 static void instruction_dump(request_t *request, unlang_t const *instruction)
61 {
62  RINDENT();
63  if (!instruction) {
64  RDEBUG2("instruction <none>");
65  REXDENT();
66  return;
67  }
68 
69  RDEBUG2("type %s", unlang_ops[instruction->type].name);
70  RDEBUG2("name %s", instruction->name);
71  RDEBUG2("debug_name %s", instruction->debug_name);
72  REXDENT();
73 }
74 
75 static void frame_dump(request_t *request, unlang_stack_frame_t *frame)
76 {
77  unlang_op_t *op = NULL;
78 
79  if (frame->instruction) op = &unlang_ops[frame->instruction->type];
80 
81  instruction_dump(request, frame->instruction);
82 
83  RINDENT();
84  if (frame->state) RDEBUG2("state %s (%p)", talloc_get_name(frame->state), frame->state);
85  if (frame->next) {
86  RDEBUG2("next %s", frame->next->debug_name);
87  } else {
88  RDEBUG2("next <none>");
89  }
90  RDEBUG2("result %s", fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"));
91  RDEBUG2("priority %d", frame->priority);
92  RDEBUG2("top_frame %s", is_top_frame(frame) ? "yes" : "no");
93  RDEBUG2("repeat %s", is_repeatable(frame) ? "yes" : "no");
94  RDEBUG2("break_point %s", is_break_point(frame) ? "yes" : "no");
95  RDEBUG2("return_point %s", is_return_point(frame) ? "yes" : "no");
96  RDEBUG2("resumable %s", is_yielded(frame) ? "yes" : "no");
97 
98  /*
99  * Call the custom frame dump function
100  */
101  if (op && op->dump) op->dump(request, frame);
102 
103  REXDENT();
104 }
105 
106 static char *stack_unwind_flag_dump(uint8_t unwind)
107 {
108  static __thread char buf[256];
109  size_t len;
110 
111 #define UNWIND_FLAG_DUMP(attrib) \
112  if (unwind & attrib) strcat(buf, #attrib" ")
113 
114  snprintf(buf, sizeof(buf), "unwind=0x%x (", unwind);
115 
119 
120  len = strlen(buf);
121  if (buf[len - 1] == ' ') buf[len - 1] = '\0'; /* Trim trailing space */
122  strcat(buf, ")");
123 
124 #undef UNWIND_FLAG_DUMP
125 
126  return buf;
127 }
128 
129 static void stack_dump(request_t *request)
130 {
131  int i;
132  unlang_stack_t *stack = request->stack;
133 
134  RDEBUG2("----- Begin stack debug [depth %i, %s] -----", stack->depth, stack_unwind_flag_dump(stack->unwind));
135  for (i = stack->depth; i >= 0; i--) {
136  unlang_stack_frame_t *frame = &stack->frame[i];
137 
138  RDEBUG2("[%d] Frame contents", i);
139  frame_dump(request, frame);
140  }
141  RDEBUG2("----- End stack debug [depth %i, %s] -------", stack->depth, stack_unwind_flag_dump(stack->unwind));
142 }
143 #define DUMP_STACK if (DEBUG_ENABLED5) stack_dump(request)
144 #else
145 #define DUMP_STACK
146 #endif
147 
148 /** Push a new frame onto the stack
149  *
150  * @param[in] request to push the frame onto.
151  * @param[in] instruction One or more unlang_t nodes describing the operations to execute.
152  * @param[in] default_rcode The default result.
153  * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
154  * or to execute subsequent nodes.
155  * @param[in] top_frame Return out of the unlang interpret when popping this frame.
156  * Hands execution back to whatever called the interpret.
157  * @return
158  * - 0 on success.
159  * - -1 on call stack too deep.
160  */
161 int unlang_interpret_push(request_t *request, unlang_t const *instruction,
162  rlm_rcode_t default_rcode, bool do_next_sibling, bool top_frame)
163 {
164  unlang_stack_t *stack = request->stack;
165  unlang_stack_frame_t *frame;
166 
167  fr_assert(instruction || top_frame);
168 
169 #ifndef NDEBUG
170  if (DEBUG_ENABLED5) RDEBUG3("unlang_interpret_push called with instruction type \"%s\" - args %s %s",
171  instruction ? instruction->debug_name : "<none>",
172  do_next_sibling ? "UNLANG_NEXT_SIBLING" : "UNLANG_NEXT_STOP",
173  top_frame ? "UNLANG_TOP_FRAME" : "UNLANG_SUB_FRAME");
174 #endif
175 
176  /*
177  * This is not a cancellation point.
178  *
179  * If we cancel here bad things happen inside the interpret.
180  */
181  if (stack->depth >= (UNLANG_STACK_MAX - 1)) {
182  RERROR("Call stack is too deep");
183  return - 1;
184  }
185 
186  stack->depth++;
187 
188  /*
189  * Initialize the next stack frame.
190  */
191  frame = &stack->frame[stack->depth];
192  memset(frame, 0, sizeof(*frame));
193 
194  frame->instruction = instruction;
195 
196  if (do_next_sibling) {
197  fr_assert(instruction != NULL);
198  frame->next = instruction->next;
199  }
200  /* else frame->next MUST be NULL */
201 
202  frame->uflags = UNWIND_FLAG_NONE;
203  if (top_frame) top_frame_set(frame);
204 
205  frame->result = default_rcode;
206  frame->priority = -1;
207 
208  if (!instruction) return 0;
209 
210  frame_state_init(stack, frame);
211 
212  return 0;
213 }
214 
215 typedef struct {
216  fr_dict_t const *dict;
219 
221 {
222  fr_pair_list_foreach(&ref->request->local_pairs, vp) {
223  if (vp->da->dict != ref->dict) break;
224 
225  (void) fr_pair_delete(&ref->request->local_pairs, vp);
226  }
227 
228  return 0;
229 }
230 
231 /** Push the children of the current frame onto a new frame onto the stack
232  *
233  * @param[out] p_result set to RLM_MOULDE_FAIL if pushing the children fails
234  * @param[in] request to push the frame onto.
235  * @param[in] default_rcode The default result.
236  * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
237  * or to execute subsequent nodes.
238  * @return
239  * - UNLANG_ACTION_PUSHED_CHILD on success.
240  * - UNLANG_ACTION_EXECUTE_NEXT do nothing, but just go to the next sibling instruction
241  * - UNLANG_ACTION_STOP_PROCESSING, fatal error, usually stack overflow.
242  */
244  rlm_rcode_t default_rcode, bool do_next_sibling)
245 {
246  unlang_stack_t *stack = request->stack;
247  unlang_stack_frame_t *frame = &stack->frame[stack->depth]; /* Quiet static analysis */
248  unlang_group_t *g;
250 
252 
254 
255  /*
256  * The compiler catches most of these, EXCEPT for the
257  * top-level 'recv Access-Request' etc. Which can exist,
258  * and can be empty.
259  */
260  if (!g->children) {
261  RDEBUG2("<ignoring empty subsection>");
263  }
264 
265  if (unlang_interpret_push(request, g->children, default_rcode, do_next_sibling, UNLANG_SUB_FRAME) < 0) {
266  *p_result = RLM_MODULE_FAIL;
268  }
269 
270  if (!g->variables) return UNLANG_ACTION_PUSHED_CHILD;
271 
272  /*
273  * Note that we do NOT create the variables, This way we don't have to worry about any
274  * uninitialized values. If the admin tries to use the variable without initializing it, they
275  * will get a "no such attribute" error.
276  */
277  if (!frame->state) {
278  MEM(ref = talloc(stack, unlang_variable_ref_t));
279  frame->state = ref;
280  } else {
281  MEM(ref = talloc(frame->state, unlang_variable_ref_t));
282  }
283 
284  /*
285  * Set the destructor to clean up local variables.
286  */
287  ref->dict = g->variables->dict;
288  ref->request = request;
289  talloc_set_destructor(ref, _local_variables_free);
290 
292 }
293 
295 
296 /** Update the current result after each instruction, and after popping each stack frame
297  *
298  * @param[in] request The current request.
299  * @param[in] frame The current stack frame.
300  * @param[in,out] result The current section result.
301  * @param[in,out] priority The current section priority.
302  * @return
303  * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions.
304  * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
305  */
306 static inline CC_HINT(always_inline)
308  rlm_rcode_t *result, int *priority)
309 {
310  unlang_t const *instruction = frame->instruction;
311  unlang_stack_t *stack = request->stack;
312 
313  RDEBUG4("** [%i] %s - have (%s %d) module returned (%s %d)",
314  stack->depth, __FUNCTION__,
315  fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
316  frame->priority,
317  fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
318  *priority);
319 
320  /*
321  * Don't set action or priority if we don't have one.
322  */
323  if (*result == RLM_MODULE_NOT_SET) return UNLANG_FRAME_ACTION_NEXT;
324 
325  /*
326  * The child's action says return. Do so.
327  */
328  if (instruction->actions.actions[*result] == MOD_ACTION_RETURN) {
329  if (*priority < 0) *priority = 0;
330 
331  RDEBUG4("** [%i] %s - action says to return with (%s %d)",
332  stack->depth, __FUNCTION__,
333  fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
334  *priority);
335  frame->result = *result;
336  frame->priority = *priority;
338  }
339 
340  /*
341  * If "reject", break out of the loop and return
342  * reject.
343  */
344  if (instruction->actions.actions[*result] == MOD_ACTION_REJECT) {
345  if (*priority < 0) *priority = 0;
346 
347  RDEBUG4("** [%i] %s - action says to return with (%s %d)",
348  stack->depth, __FUNCTION__,
350  *priority);
351  frame->result = RLM_MODULE_REJECT;
352  frame->priority = *priority;
354  }
355 
356  /*
357  * The instruction says it should be retried from the beginning.
358  */
359  if (instruction->actions.actions[*result] == MOD_ACTION_RETRY) {
360  unlang_retry_t *retry = frame->retry;
361 
362  RDEBUG4("** [%i] %s - action says to retry with",
363  stack->depth, __FUNCTION__);
364 
365  if (*priority < 0) *priority = 0;
366 
367  /*
368  * If this is the first time doing the retry,
369  * then allocate the structure and set the timer.
370  */
371  if (!retry) {
372  frame->retry = retry = talloc_zero(stack, unlang_retry_t);
373  if (!frame->retry) goto fail;
374 
375  retry->request = request;
376  retry->depth = stack->depth;
377  retry->state = FR_RETRY_CONTINUE;
378  retry->count = 1;
379 
380  /*
381  * Set a timer which automatically fires
382  * if there's a timeout. And parent it
383  * from the retry structure, so that the
384  * timer is automatically freed when the
385  * frame is cleaned up.
386  */
387  if (fr_time_delta_ispos(instruction->actions.retry.mrd)) {
388  retry->timeout = fr_time_add(fr_time(), instruction->actions.retry.mrd);
389 
390  if (fr_event_timer_at(retry, unlang_interpret_event_list(request), &retry->ev, retry->timeout,
391  instruction_timeout_handler, request) < 0) {
392  RPEDEBUG("Failed inserting event");
393  goto fail;
394  }
395  }
396 
397  } else {
398  /*
399  * We've been told to stop doing retries,
400  * probably from a timeout.
401  */
402  if (retry->state != FR_RETRY_CONTINUE) goto fail;
403 
404  /*
405  * Clamp it at the maximum count.
406  */
407  if (instruction->actions.retry.mrc > 0) {
408  retry->count++;
409 
410  if (retry->count >= instruction->actions.retry.mrc) {
411  retry->state = FR_RETRY_MRC;
412 
413  REDEBUG("Retries hit max_rtx_count (%d) - returning 'fail'", instruction->actions.retry.mrc);
414 
415  fail:
416  *result = RLM_MODULE_FAIL;
417  goto finalize;
418  }
419  }
420  }
421 
422  RINDENT();
423  if (instruction->actions.retry.mrc) {
424  RDEBUG("... retrying (%d/%d)", retry->count, instruction->actions.retry.mrc);
425  } else {
426  RDEBUG("... retrying");
427  }
428  REXDENT();
429 
430  talloc_free(frame->state);
432  frame_state_init(stack, frame);
434  }
435 
436 finalize:
437  /*
438  * The array holds a default priority for this return
439  * code. Grab it in preference to any unset priority.
440  */
441  if (*priority < 0) {
442  *priority = instruction->actions.actions[*result];
443 
444  RDEBUG4("** [%i] %s - setting priority to (%s %d)",
445  stack->depth, __FUNCTION__,
446  fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
447  *priority);
448  }
449 
450  /*
451  * We're higher than any previous priority, remember this
452  * return code and priority.
453  */
454  if (*priority > frame->priority) {
455  frame->result = *result;
456  frame->priority = *priority;
457 
458  RDEBUG4("** [%i] %s - over-riding result from higher priority to (%s %d)",
459  stack->depth, __FUNCTION__,
460  fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
461  *priority);
462  }
463 
464  /*
465  * Not allowed in frame uflags...
466  */
467  fr_assert(!(frame->uflags & UNWIND_FLAG_NO_CLEAR));
468 
469  /*
470  * If we are unwinding the stack due to a break / return,
471  * then handle it now.
472  */
473  if (stack->unwind) {
474  /*
475  * Continue unwinding...
476  */
477  if (!(stack->unwind & frame->uflags) || (stack->unwind & UNWIND_FLAG_NO_CLEAR)) {
478  RDEBUG4("** [%i] %s - unwinding current frame with (%s %d) - flags - stack (%i), frame (%i)",
479  stack->depth, __FUNCTION__,
480  fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
481  frame->priority, stack->unwind, frame->uflags);
482 
484  }
485 
486  /*
487  * If we've been told to unwind, and we've hit
488  * the frame we should be unwinding to,
489  * and the "NO_CLEAR" flag hasn't been set, then
490  * clear the unwind field so we stop unwinding.
491  */
492  stack->unwind = UNWIND_FLAG_NONE;
493 
494  RDEBUG4("** [%i] %s - unwind stop (%s %d) - flags - stack unwind (%i), frame uflags (%i)",
495  stack->depth, __FUNCTION__,
496  fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
497  frame->priority, stack->unwind, frame->uflags);
498  }
499 
500  return frame->next ? UNLANG_FRAME_ACTION_NEXT : UNLANG_FRAME_ACTION_POP;
501 }
502 
503 /** Evaluates all the unlang nodes in a section
504  *
505  * @param[in] request The current request.
506  * @param[in] frame The current stack frame.
507  * @param[in,out] result The current section result.
508  * @param[in,out] priority The current section priority.
509  * @return
510  * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions in the current stack frame
511  * which may not be the same frame as when this function
512  * was called.
513  * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
514  */
515 static inline CC_HINT(always_inline)
517 {
518  unlang_stack_t *stack = request->stack;
519 
520  /*
521  * Loop over all the instructions in this list.
522  */
523  while (frame->instruction) {
524  unlang_t const *instruction = frame->instruction;
527 
528  DUMP_STACK;
529 
530  fr_assert(instruction->debug_name != NULL); /* if this happens, all bets are off. */
531  fr_assert(unlang_ops[instruction->type].interpret != NULL);
532 
533  REQUEST_VERIFY(request);
534 
535  /*
536  * We're running this frame, so it can't possibly be yielded.
537  */
538  if (is_yielded(frame)) {
539  RDEBUG("%s - Resuming execution", instruction->debug_name);
540  yielded_clear(frame);
541  }
542 
543 #ifndef NDEBUG
544  /*
545  * Failure testing!
546  */
547  if (request->ins_max && (request->master_state != REQUEST_STOP_PROCESSING)) {
548  request->ins_count++;
549 
550  if (request->ins_count >= request->ins_max) {
551  RERROR("Failing request due to maximum instruction count %" PRIu64, request->ins_max);
552 
553  unlang_interpret_signal(request, FR_SIGNAL_CANCEL);
554  request->master_state = REQUEST_STOP_PROCESSING;
555  }
556  }
557 #endif
558 
559  /*
560  * unlang_interpret_signal() takes care of
561  * marking the requests as STOP on a CANCEL
562  * signal.
563  */
564  if (request->master_state == REQUEST_STOP_PROCESSING) {
565  do_stop:
566  frame->result = RLM_MODULE_FAIL;
567  frame->priority = MOD_PRIORITY_MAX;
568 
569  RDEBUG4("** [%i] %s - STOP current subsection with (%s %d)",
570  stack->depth, __FUNCTION__,
571  fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
572  frame->priority);
573 
574  unwind_all(stack);
576  }
577 
578  if (!is_repeatable(frame) && (unlang_ops[instruction->type].debug_braces)) {
579  RDEBUG2("%s {", instruction->debug_name);
580  RINDENT();
581  }
582 
583  /*
584  * Execute an operation
585  */
586  RDEBUG4("** [%i] %s >> %s", stack->depth, __FUNCTION__,
587  unlang_ops[instruction->type].name);
588 
589  fr_assert(frame->process != NULL);
590 
591  /*
592  * Clear the repeatable flag so this frame
593  * won't get executed again unless it specifically
594  * requests it.
595  *
596  * The flag may still be set again during the
597  * process function to indicate that the frame
598  * should be evaluated again.
599  */
600  repeatable_clear(frame);
602  ua = frame->process(result, request, frame);
603 
604  /*
605  * If this frame is breaking or returning
606  * frame then clear that unwind flag,
607  * it's been consumed by this call.
608  *
609  * We leave the unwind flags for the eval
610  * call so that the process function knows
611  * that the stack is being unwound.
612  */
613  if (is_break_point(frame)) {
616  }
617  if (is_return_point(frame)) {
620  }
621 
622  RDEBUG4("** [%i] %s << %s (%d)", stack->depth, __FUNCTION__,
623  fr_table_str_by_value(unlang_action_table, ua, "<INVALID>"), *priority);
624 
625  fr_assert(*priority >= -1);
626  fr_assert(*priority <= MOD_PRIORITY_MAX);
627 
628  switch (ua) {
629  /*
630  * The request is now defunct, and we should not
631  * continue processing it.
632  */
634  goto do_stop;
635 
636  /*
637  * The operation resulted in additional frames
638  * being pushed onto the stack, execution should
639  * now continue at the deepest frame.
640  */
642  fr_assert_msg(&stack->frame[stack->depth] > frame,
643  "Instruction %s returned UNLANG_ACTION_PUSHED_CHILD, "
644  "but stack depth was not increased",
645  instruction->name);
647  *result = frame->result;
649 
650  /*
651  * We're in a looping construct and need to stop
652  * execution of the current section.
653  */
655  if (*priority < 0) *priority = 0;
656  frame->result = *result;
657  frame->priority = *priority;
658  frame->next = NULL;
659  fr_assert(stack->unwind != UNWIND_FLAG_NONE);
661 
662  /*
663  * Yield control back to the scheduler, or whatever
664  * called the interpreter.
665  */
666  case UNLANG_ACTION_YIELD:
667  fr_assert_msg(&stack->frame[stack->depth] == frame,
668  "Instruction %s returned UNLANG_ACTION_YIELD, but pushed additional "
669  "frames for evaluation. Instruction should return UNLANG_ACTION_PUSHED_CHILD "
670  "instead", instruction->name);
672  yielded_set(frame);
673  RDEBUG4("** [%i] %s - yielding with current (%s %d)", stack->depth, __FUNCTION__,
674  fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
675  frame->priority);
676  DUMP_STACK;
678 
679  /*
680  * This action is intended to be returned by library
681  * functions. It reduces boilerplate.
682  */
683  case UNLANG_ACTION_FAIL:
684  *result = RLM_MODULE_FAIL;
685  FALL_THROUGH;
686 
687  /*
688  * Instruction finished execution,
689  * check to see what we need to do next, and update
690  * the section rcode and priority.
691  */
693  if (unlang_ops[instruction->type].debug_braces) {
694  REXDENT();
695 
696  /*
697  * If we're at debug level 1, don't emit the closing
698  * brace as the opening brace wasn't emitted.
699  */
701  RDEBUG("# %s (%s)", instruction->debug_name,
702  fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"));
703  } else {
704  RDEBUG2("} # %s (%s)", instruction->debug_name,
705  fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"));
706  }
707  }
708 
709  /*
710  * RLM_MODULE_NOT_SET means the instruction
711  * doesn't want to modify the result.
712  */
713  if (*result != RLM_MODULE_NOT_SET) *priority = instruction->actions.actions[*result];
714 
715  fa = result_calculate(request, frame, result, priority);
716  switch (fa) {
719 
721  if (unlang_ops[instruction->type].debug_braces) {
722  REXDENT();
723  RDEBUG2("} # retrying the same section");
724  }
725  continue; /* with the current frame */
726 
727  default:
728  break;
729  }
730  break;
731 
732  /*
733  * Execute the next instruction in this frame
734  */
736  if (unlang_ops[instruction->type].debug_braces) {
737  REXDENT();
738  RDEBUG2("}");
739  }
740  break;
741  } /* switch over return code from the interpret function */
742 
743  frame_next(stack, frame);
744  }
745 
746  RDEBUG4("** [%i] %s - done current subsection with (%s %d)",
747  stack->depth, __FUNCTION__,
748  fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
749  frame->priority);
750 
752 }
753 
754 /** Run the interpreter for a current request
755  *
756  * @param[in] request to run. If this is an internal request
757  * the request may be freed by the interpreter.
758  * @return The final request rcode.
759  */
760 CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request)
761 {
763  rlm_rcode_t rcode;
764 
765  /*
766  * We don't have a return code yet.
767  */
768  unlang_stack_t *stack = request->stack;
769  unlang_interpret_t *intp = stack->intp;
770  unlang_stack_frame_t *frame = &stack->frame[stack->depth]; /* Quiet static analysis */
771 
772  stack->priority = -1; /* Reset */
773 
774 #ifndef NDEBUG
775  if (DEBUG_ENABLED5) DEBUG("###### unlang_interpret is starting");
776  DUMP_STACK;
777 #endif
778 
779  fr_assert(!unlang_request_is_scheduled(request)); /* if we're running it, it can't be scheduled */
780  fr_assert_msg(intp, "request has no interpreter associated");
781 
782  RDEBUG4("** [%i] %s - interpret entered", stack->depth, __FUNCTION__);
783  intp->funcs.resume(request, intp->uctx);
784 
785  for (;;) {
786  fr_assert(request->master_state != REQUEST_STOP_PROCESSING);
787 
788  RDEBUG4("** [%i] %s - frame action %s", stack->depth, __FUNCTION__,
790  switch (fa) {
791  case UNLANG_FRAME_ACTION_NEXT: /* Evaluate the current frame */
792  fr_assert(stack->depth > 0);
793  fr_assert(stack->depth < UNLANG_STACK_MAX);
794 
795  frame = &stack->frame[stack->depth];
796  fa = frame_eval(request, frame, &stack->result, &stack->priority);
797 
798  if (fa != UNLANG_FRAME_ACTION_POP) continue;
799 
800  /*
801  * We're supposed to stop processing. Don't pop anything, just stop.
802  */
803  if (request->master_state == REQUEST_STOP_PROCESSING) return RLM_MODULE_FAIL;
804 
805  /*
806  * We were executing a frame, frame_eval()
807  * indicated we should pop it, but we're now at
808  * a top_frame, so we need to break out of the loop
809  * and calculate the final result for this substack.
810  *
811  * Note that we only stop on a top frame.
812  * If there's a return point such as in a
813  * policy, then the "return" causes a
814  * "pop" until the return point. BUT we
815  * then continue execution with the next
816  * instruction. And we don't return all
817  * of the way up the stack.
818  */
819  if (is_top_frame(frame)) break;
820 
821  continue;
822 
823  case UNLANG_FRAME_ACTION_POP: /* Pop this frame and check the one beneath it */
824  /*
825  * The result / priority is returned from the sub-section,
826  * and made into our current result / priority, as
827  * if we had performed a module call.
828  */
829  stack->result = frame->result;
830  stack->priority = frame->priority;
831 
832  /*
833  * Head on back up the stack
834  */
835  frame_pop(request, stack);
836  frame = &stack->frame[stack->depth];
837  DUMP_STACK;
838 
839  /*
840  * Resume a "foreach" loop, or a "load-balance" section
841  * or anything else that needs to be checked on the way
842  * back on up the stack.
843  */
844  if (is_repeatable(frame)) {
846  continue;
847  }
848 
849  /*
850  * Close out the section we entered earlier
851  */
852  if (unlang_ops[frame->instruction->type].debug_braces) {
853  REXDENT();
854 
855  /*
856  * If we're at debug level 1, don't emit the closing
857  * brace as the opening brace wasn't emitted.
858  */
860  RDEBUG("# %s (%s)", frame->instruction->debug_name,
861  fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"));
862  } else {
863  RDEBUG2("} # %s (%s)", frame->instruction->debug_name,
864  fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"));
865  }
866  }
867 
868  /*
869  * If we're done, merge the last stack->result / priority in.
870  */
871  if (is_top_frame(frame)) break; /* stop */
872 
873  fa = result_calculate(request, frame, &stack->result, &stack->priority);
874 
875  /*
876  * If we're continuing after popping a frame
877  * then we advance the instruction else we
878  * end up executing the same code over and over...
879  */
880  if (fa == UNLANG_FRAME_ACTION_NEXT) {
881  RDEBUG4("** [%i] %s - continuing after subsection with (%s %d)",
882  stack->depth, __FUNCTION__,
883  fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"),
884  stack->priority);
885  frame_next(stack, frame);
886 
887  /*
888  * Else if we're really done with this frame
889  * print some helpful debug...
890  */
891  } else {
892  RDEBUG4("** [%i] %s - done current subsection with (%s %d)",
893  stack->depth, __FUNCTION__,
894  fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
895  frame->priority);
896  }
897  continue;
898 
900  RDEBUG4("** [%i] %s - interpret yielding", stack->depth, __FUNCTION__);
901  intp->funcs.yield(request, intp->uctx);
902  return stack->result;
903 
904  case UNLANG_FRAME_ACTION_RETRY: /* retry the current frame */
906  continue;
907  }
908  break;
909  }
910 
911  /*
912  * Nothing in this section, use the top frame stack->result.
913  */
914  if ((stack->priority < 0) || (stack->result == RLM_MODULE_NOT_SET)) {
915  RDEBUG4("** [%i] %s - empty section, using stack result (%s %d)", stack->depth, __FUNCTION__,
916  fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"), stack->priority);
917  stack->result = frame->result;
918  stack->priority = frame->priority;
919  }
920 
921  if (stack->priority > frame->priority) {
922  frame->result = stack->result;
923  frame->priority = stack->priority;
924 
925  RDEBUG4("** [%i] %s - over-riding stack->result from higher priority to (%s %d)",
926  stack->depth, __FUNCTION__,
927  fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"),
928  stack->priority);
929  }
930 
931  /*
932  * We're at the top frame, return the result from the
933  * stack, and get rid of the top frame.
934  */
935  RDEBUG4("** [%i] %s - interpret exiting, returning %s", stack->depth, __FUNCTION__,
936  fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"));
937 
938  stack->result = frame->result;
939 
940  stack->depth--;
941  DUMP_STACK;
942 
943  /*
944  * Record this now as the done functions may free
945  * the request.
946  */
947  rcode = stack->result;
948 
949  /*
950  * This usually means the request is complete in its
951  * entirety.
952  */
953  if (stack->depth == 0) unlang_interpret_request_done(request);
954 
955  return rcode;
956 }
957 
959  .self = {
961  .debug_name = "empty-group",
962  .actions = {
963  .actions = {
973  },
974  .retry = RETRY_INIT,
975  },
976  },
977 };
978 
979 /** Push a configuration section onto the request stack for later interpretation.
980  *
981  */
982 int unlang_interpret_push_section(request_t *request, CONF_SECTION *cs, rlm_rcode_t default_rcode, bool top_frame)
983 {
984  unlang_t *instruction = NULL;
985 
986  /*
987  * Interpretable unlang instructions are stored as CONF_DATA
988  * associated with sections.
989  */
990  if (cs) {
991  instruction = (unlang_t *)cf_data_value(cf_data_find(cs, unlang_group_t, NULL));
992  if (!instruction) {
993  REDEBUG("Failed to find pre-compiled unlang for section %s %s { ... }",
995  return -1;
996  }
997  }
998 
999  return unlang_interpret_push_instruction(request, instruction, default_rcode, top_frame);
1000 }
1001 
1002 /** Push an instruction onto the request stack for later interpretation.
1003  *
1004  */
1005 int unlang_interpret_push_instruction(request_t *request, void *instruction, rlm_rcode_t default_rcode, bool top_frame)
1006 {
1007  unlang_stack_t *stack = request->stack;
1008 
1009  if (!instruction) {
1010  instruction = unlang_group_to_generic(&empty_group);
1011  }
1012 
1013  /*
1014  * Push the default action, and the instruction which has
1015  * no action.
1016  */
1017  if (unlang_interpret_push(request,
1018  instruction, default_rcode, UNLANG_NEXT_SIBLING, top_frame) < 0) {
1019  return -1;
1020  }
1021 
1022  RDEBUG4("** [%i] %s - substack begins", stack->depth, __FUNCTION__);
1023 
1024  DUMP_STACK;
1025 
1026  return 0;
1027 }
1028 
1029 /** Allocate a new unlang stack
1030  *
1031  * @param[in] ctx to allocate stack in.
1032  * @return
1033  * - A new stack on success.
1034  * - NULL on OOM.
1035  */
1036 void *unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
1037 {
1039 
1040  /*
1041  * If we have talloc_pooled_object allocate the
1042  * stack as a combined chunk/pool, with memory
1043  * to hold at mutable data for at least a quarter
1044  * of the maximum number of stack frames.
1045  *
1046  * Having a dedicated pool for mutable stack data
1047  * means we don't have memory fragmentations issues
1048  * as we would if request were used as the pool.
1049  *
1050  * This number is pretty arbitrary, but it seems
1051  * like too low level to make into a tuneable.
1052  */
1053  MEM(stack = talloc_zero_pooled_object(ctx, unlang_stack_t, UNLANG_STACK_MAX, 128)); /* 128 bytes per state */
1054  stack->result = RLM_MODULE_NOT_SET;
1055 
1056  return stack;
1057 }
1058 
1059 /** Indicate to the caller of the interpreter that this request is complete
1060  *
1061  */
1063 {
1064  unlang_stack_t *stack = request->stack;
1065  unlang_interpret_t *intp;
1066 
1067  if (!fr_cond_assert(stack != NULL)) return;
1068 
1069  intp = stack->intp;
1070 
1071  switch (request->type) {
1072  case REQUEST_TYPE_EXTERNAL:
1073  intp->funcs.done_external(request, stack->result, intp->uctx);
1074  break;
1075 
1076  case REQUEST_TYPE_INTERNAL:
1077  intp->funcs.done_internal(request, stack->result, intp->uctx);
1078  break;
1079 
1080  case REQUEST_TYPE_DETACHED:
1081  intp->funcs.done_detached(request, stack->result, intp->uctx); /* Callback will usually free the request */
1082  break;
1083  }
1084 }
1085 
1086 static inline CC_HINT(always_inline)
1088 {
1089  unlang_stack_t *stack = request->stack;
1090  unlang_interpret_t *intp;
1091 
1092  if (!fr_cond_assert(stack != NULL)) return;
1093 
1094  intp = stack->intp;
1095  intp->funcs.stop(request, intp->uctx);
1096  request->log.indent.unlang = 0; /* nothing unwinds the indentation stack */
1097  request->master_state = REQUEST_STOP_PROCESSING;
1098 }
1099 
1100 static inline CC_HINT(always_inline)
1102 {
1103  unlang_stack_t *stack = request->stack;
1104  unlang_interpret_t *intp;
1105 
1106  if (!fr_cond_assert(stack != NULL)) return;
1107 
1108  if (!request_is_detachable(request)) return;
1109 
1110  intp = stack->intp;
1111 
1112  intp->funcs.detach(request, intp->uctx);
1113 }
1114 
1115 /** Send a signal (usually stop) to a request
1116  *
1117  * This is typically called via an "async" action, i.e. an action
1118  * outside of the normal processing of the request.
1119  *
1120  * If there is no #unlang_module_signal_t callback defined, the action is ignored.
1121  *
1122  * The signaling stops at the "limit" frame. This is so that keywords
1123  * such as "timeout" and "limit" can signal frames *lower* than theirs
1124  * to stop, but then continue with their own work.
1125  *
1126  * @param[in] request The current request.
1127  * @param[in] action to signal.
1128  * @param[in] limit the frame at which to stop signaling.
1129  */
1130 void unlang_frame_signal(request_t *request, fr_signal_t action, int limit)
1131 {
1132  unlang_stack_frame_t *frame;
1133  unlang_stack_t *stack = request->stack;
1134  int i, depth = stack->depth;
1135 
1136  (void)talloc_get_type_abort(request, request_t); /* Check the request hasn't already been freed */
1137 
1138  fr_assert(stack->depth > 0);
1139 
1140  /*
1141  * Destructive signal where we clean each of the
1142  * stack frames up in turn.
1143  *
1144  * We do this to avoid possible free ordering
1145  * issues where memory allocated by modules higher
1146  * in the stack is used by modules lower in the
1147  * stack.
1148  */
1149  if (action == FR_SIGNAL_CANCEL) {
1150  for (i = depth; i > limit; i--) {
1151  frame = &stack->frame[i];
1152  if (frame->signal) frame->signal(request, frame, action);
1153  frame_cleanup(frame);
1154  }
1155  stack->depth = i;
1156  return;
1157  }
1158 
1159  /*
1160  * Walk back up the stack, calling signal handlers
1161  * to cancel any pending operations and free/release
1162  * any resources.
1163  *
1164  * There may be multiple resumption points in the
1165  * stack, as modules can push xlats and function
1166  * calls.
1167  */
1168  for (i = depth; i > limit; i--) {
1169  frame = &stack->frame[i];
1170  if (frame->signal) frame->signal(request, frame, action);
1171  }
1172 }
1173 
1174 /** Send a signal (usually stop) to a request
1175  *
1176  * This is typically called via an "async" action, i.e. an action
1177  * outside of the normal processing of the request.
1178  *
1179  * If there is no #unlang_module_signal_t callback defined, the action is ignored.
1180  *
1181  * @param[in] request The current request.
1182  * @param[in] action to signal.
1183  */
1185 {
1186  unlang_stack_t *stack = request->stack;
1187 
1188  switch (action) {
1189  case FR_SIGNAL_DETACH:
1190  /*
1191  * Ensure the request is able to be detached
1192  * else don't signal.
1193  */
1194  if (!fr_cond_assert(request_is_detachable(request))) return;
1195  break;
1196 
1197  default:
1198  break;
1199  }
1200 
1201  /*
1202  * Requests that haven't been run through the interpreter
1203  * yet should have a stack depth of zero, so we don't
1204  * need to do anything.
1205  */
1206  if (stack && (stack->depth > 0)) unlang_frame_signal(request, action, 0);
1207 
1208  switch (action) {
1209  case FR_SIGNAL_CANCEL:
1210  /*
1211  * Detach the request from the parent to cleanup
1212  * any cross-request pointers. This is a noop
1213  * if the request is not detachable.
1214  */
1216 
1217  /*
1218  * Get the request into a consistent state,
1219  * removing it from any runnable lists.
1220  */
1222 
1223  /*
1224  * As the request is detached, we call the done_detached
1225  * callback which should free the request.
1226  */
1228  break;
1229 
1230  case FR_SIGNAL_DETACH:
1231  /*
1232  * Cleanup any cross-request pointers, and mark the
1233  * request as detached. When the request completes it
1234  * should by automatically freed.
1235  */
1237  break;
1238 
1239  default:
1240  break;
1241  }
1242 }
1243 
1245 {
1246  unlang_retry_t *retry = talloc_get_type_abort(ctx, unlang_retry_t);
1247  request_t *request = talloc_get_type_abort(retry->request, request_t);
1248 
1249  RDEBUG("retry timeout reached, signalling interpreter to cancel.");
1250 
1251  /*
1252  * Signal all lower frames to exit.
1253  */
1254  unlang_frame_signal(request, FR_SIGNAL_CANCEL, retry->depth);
1255 
1256  retry->state = FR_RETRY_MRD;
1258 }
1259 
1260 /** Return the depth of the request's stack
1261  *
1262  */
1264 {
1265  unlang_stack_t *stack = request->stack;
1266 
1267  return stack->depth;
1268 }
1269 
1270 /** Get the current rcode for the frame
1271  *
1272  * This can be useful for getting the result of unlang_function_t pushed
1273  * onto the stack for evaluation.
1274  *
1275  * @param[in] request The current request.
1276  * @return the current rcode for the frame.
1277  */
1279 {
1280  unlang_stack_t *stack = request->stack;
1281 
1282  return stack->result;
1283 }
1284 
1285 /** Overwrite the current stack rcode
1286  *
1287  * @param[in] request The current request.
1288  * @param[in] rcode to set.
1289  */
1291 {
1292  unlang_stack_t *stack = request->stack;
1293 
1294  stack->result = rcode;
1295 }
1296 
1297 /** Return whether a request is currently scheduled
1298  *
1299  */
1301 {
1302  unlang_stack_t *stack = request->stack;
1303  unlang_interpret_t *intp = stack->intp;
1304 
1305  return intp->funcs.scheduled(request, intp->uctx);
1306 }
1307 
1308 /** Return whether a request has been cancelled
1309  */
1311 {
1312  return (request->master_state == REQUEST_STOP_PROCESSING);
1313 }
1314 
1315 /** Check if a request as resumable.
1316  *
1317  * @param[in] request The current request.
1318  * @return
1319  * - true if the request is resumable (i.e. has yielded)
1320  * - false if the request is not resumable (i.e. has not yielded)
1321  */
1323 {
1324  unlang_stack_t *stack = request->stack;
1325  unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1326 
1327  return is_yielded(frame);
1328 }
1329 
1330 /** Mark a request as resumable.
1331  *
1332  * It's not called "unlang_interpret", because it doesn't actually
1333  * resume the request, it just schedules it for resumption.
1334  *
1335  * @note that this schedules the request for resumption. It does not immediately
1336  * start running the request.
1337  *
1338  * @param[in] request The current request.
1339  */
1341 {
1342  unlang_stack_t *stack = request->stack;
1343  unlang_interpret_t *intp = stack->intp;
1344  unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1345 
1346  bool scheduled = unlang_request_is_scheduled(request);
1347 
1348  /*
1349  * The request hasn't yielded, OR it's already been
1350  * marked as runnable. Don't do anything.
1351  *
1352  * The IO code, or children have no idea where they're
1353  * being called from. They just ask to mark the parent
1354  * resumable when they're done. So we have to check here
1355  * if this request is resumable.
1356  *
1357  * If the parent called the child directly, then the
1358  * parent hasn't yielded, so it isn't resumable. When
1359  * the child is done, the parent will automatically
1360  * continue running. We therefore don't need to insert
1361  * the parent into the backlog.
1362  *
1363  * Multiple child request may also mark a parent request
1364  * runnable, before the parent request starts running.
1365  */
1366  if (!is_yielded(frame) || scheduled) {
1367  RDEBUG3("Not marking runnable due to%s%s",
1368  !is_yielded(frame) ?
1369  " it not being yielded " : "", scheduled ? " it already being scheduled" : "");
1370  return;
1371  }
1372 
1373  RDEBUG3("Interpreter - Request marked as runnable");
1374 
1375  intp->funcs.mark_runnable(request, intp->uctx);
1376 }
1377 
1378 /** Get a talloc_ctx which is valid only for this frame
1379  *
1380  * @param[in] request The current request.
1381  * @return
1382  * - a TALLOC_CTX which is valid only for this stack frame
1383  */
1385 {
1386  unlang_stack_t *stack = request->stack;
1387  unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1388 
1389  if (frame->state) return (TALLOC_CTX *)frame->state;
1390 
1391  /*
1392  * If the frame doesn't ordinarily have a
1393  * state, assume the caller knows what it's
1394  * doing and allocate one.
1395  */
1396  return (TALLOC_CTX *)(frame->state = talloc_new(request));
1397 }
1398 
1400  { .required = false, .single = true, .type = FR_TYPE_TIME_DELTA },
1402 };
1403 
1404 static xlat_action_t unlang_cancel_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
1405  UNUSED xlat_ctx_t const *xctx,
1406  request_t *request, fr_value_box_list_t *args);
1407 
1408 /** Signal the request to stop executing
1409  *
1410  * The request can't be running at this point because we're in the event
1411  * loop. This means the request is always in a consistent state when
1412  * the timeout event fires, even if that's state is waiting on I/O.
1413  */
1415 {
1416  request_t *request = talloc_get_type_abort(uctx, request_t);
1417 
1418  RDEBUG2("Request canceled by dynamic timeout");
1419 
1420  unlang_interpret_signal(request, FR_SIGNAL_CANCEL);
1421 
1422  /*
1423  * Cleans up the memory allocated to hold
1424  * the pointer, not the event itself.
1425  */
1426  talloc_free(request_data_get(request, (void *)unlang_cancel_xlat, 0));
1427 }
1428 
1430  UNUSED xlat_ctx_t const *xctx,
1431  UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
1432 {
1433  fr_assert_msg(0, "Should never be run");
1434  return XLAT_ACTION_FAIL;
1435 }
1436 
1437 /** Allows a request to dynamically alter its own lifetime
1438  *
1439  * %cancel(<timeout>)
1440  *
1441  * If timeout is 0, then the request is immediately cancelled.
1442  */
1444  UNUSED xlat_ctx_t const *xctx,
1445  request_t *request, fr_value_box_list_t *args)
1446 {
1449  fr_event_timer_t const **ev_p, **ev_p_og;
1450  fr_value_box_t *vb;
1451  fr_time_t when = fr_time_from_sec(0); /* Invalid clang complaints if we don't set this */
1452 
1453  XLAT_ARGS(args, &timeout);
1454 
1455  /*
1456  * First see if we already have a timeout event
1457  * that was previously added by this xlat.
1458  */
1459  ev_p = ev_p_og = request_data_get(request, (void *)unlang_cancel_xlat, 0);
1460  if (ev_p) {
1461  if (*ev_p) when = fr_event_timer_when(*ev_p); /* *ev_p should never be NULL, really... */
1462  } else {
1463  /*
1464  * Must not be parented from the request
1465  * as this is freed by request data.
1466  */
1467  MEM(ev_p = talloc_zero(NULL, fr_event_timer_t const *));
1468  }
1469 
1470  if (unlikely(fr_event_timer_in(ev_p, el, ev_p,
1471  timeout ? timeout->vb_time_delta : fr_time_delta_from_sec(0),
1472  unlang_cancel_event, request) < 0)) {
1473  RPERROR("Failed inserting cancellation event");
1474  talloc_free(ev_p);
1475  return XLAT_ACTION_FAIL;
1476  }
1477  if (unlikely(request_data_add(request, (void *)unlang_cancel_xlat, 0,
1478  UNCONST(fr_event_timer_t **, ev_p), true, true, false) < 0)) {
1479  RPERROR("Failed associating cancellation event with request");
1480  talloc_free(ev_p);
1481  return XLAT_ACTION_FAIL;
1482  }
1483 
1484  /*
1485  * No timeout means cancel immediately, so yield allowing
1486  * the interpreter to run the event we added to cancel
1487  * the request.
1488  *
1489  * We call unlang_xlat_yield to keep the interpreter happy
1490  * as it expects to see a resume function set.
1491  */
1492  if (!timeout || fr_time_delta_eq(timeout->vb_time_delta, fr_time_delta_from_sec(0))) {
1493  return unlang_xlat_yield(request, unlang_cancel_never_run, NULL, 0, NULL);
1494  }
1495 
1496  if (ev_p_og) {
1497  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
1498 
1499  /*
1500  * Return how long before the previous
1501  * cancel event would have fired.
1502  *
1503  * This can be useful for doing stacked
1504  * cancellations in policy.
1505  */
1506  vb->vb_time_delta = fr_time_sub(when, fr_time());
1507  fr_dcursor_insert(out, vb);
1508  }
1509 
1510  /*
1511  * No value if this is the first cleanup event
1512  */
1513  return XLAT_ACTION_DONE;
1514 }
1515 
1517  { .required = true, .single = true, .type = FR_TYPE_STRING },
1519 };
1520 
1521 /** Get information about the interpreter state
1522  *
1523  * @ingroup xlat_functions
1524  */
1526  UNUSED xlat_ctx_t const *xctx,
1527  request_t *request, fr_value_box_list_t *in)
1528 {
1529  unlang_stack_t *stack = request->stack;
1530  int depth = stack->depth;
1531  unlang_stack_frame_t *frame;
1532  unlang_t const *instruction;
1533  fr_value_box_t *arg = fr_value_box_list_head(in);
1534  char const *fmt = arg->vb_strvalue;
1535  fr_value_box_t *vb;
1536 
1537  MEM(vb = fr_value_box_alloc_null(ctx));
1538 
1539  /*
1540  * Find the correct stack frame.
1541  */
1542  while (*fmt == '.') {
1543  if (depth <= 1) {
1544  if (fr_value_box_bstrndup(vb, vb, NULL, "<underflow>", 11, false) < 0) {
1545  error:
1546  talloc_free(vb);
1547  return XLAT_ACTION_FAIL;
1548  }
1549  goto finish;
1550  }
1551 
1552  fmt++;
1553  depth--;
1554  }
1555 
1556  /*
1557  * Get the current instruction.
1558  */
1559  frame = &stack->frame[depth];
1560  instruction = frame->instruction;
1561 
1562  /*
1563  * Nothing there...
1564  */
1565  if (!instruction) {
1566  talloc_free(vb);
1567  return XLAT_ACTION_DONE;
1568  }
1569 
1570  /*
1571  * How deep the current stack is.
1572  */
1573  if (strcmp(fmt, "depth") == 0) {
1574  fr_value_box_int32(vb, NULL, depth, false);
1575  goto finish;
1576  }
1577 
1578  /*
1579  * The current module
1580  */
1581  if (strcmp(fmt, "module") == 0) {
1582  if (fr_value_box_strdup(vb, vb, NULL, request->module, false) < 0) goto error;
1583 
1584  goto finish;
1585  }
1586 
1587  /*
1588  * Name of the instruction.
1589  */
1590  if (strcmp(fmt, "name") == 0) {
1591  if (fr_value_box_bstrndup(vb, vb, NULL, instruction->name,
1592  strlen(instruction->name), false) < 0) goto error;
1593  goto finish;
1594  }
1595 
1596  /*
1597  * The request processing stage.
1598  */
1599  if (strcmp(fmt, "processing_stage") == 0) {
1600  if (fr_value_box_strdup(vb, vb, NULL, request->component, false) < 0) goto error;
1601 
1602  goto finish;
1603  }
1604 
1605  /*
1606  * The current return code.
1607  */
1608  if (strcmp(fmt, "rcode") == 0) {
1609  if (fr_value_box_strdup(vb, vb, NULL, fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"), false) < 0) goto error;
1610 
1611  goto finish;
1612  }
1613 
1614  /*
1615  * The virtual server handling the request
1616  */
1617  if (strcmp(fmt, "server") == 0) {
1618  if (!unlang_call_current(request)) goto finish;
1619 
1620  if (fr_value_box_strdup(vb, vb, NULL, cf_section_name2(unlang_call_current(request)), false) < 0) goto error;
1621 
1622  goto finish;
1623  }
1624 
1625  /*
1626  * Unlang instruction type.
1627  */
1628  if (strcmp(fmt, "type") == 0) {
1629  if (fr_value_box_bstrndup(vb, vb, NULL, unlang_ops[instruction->type].name,
1630  strlen(unlang_ops[instruction->type].name), false) < 0) goto error;
1631 
1632  goto finish;
1633  }
1634 
1635  /*
1636  * All of the remaining things need a CONF_ITEM.
1637  */
1638  if (!instruction->ci) {
1639  if (fr_value_box_bstrndup(vb, vb, NULL, "<INVALID>", 3, false) < 0) goto error;
1640 
1641  goto finish;
1642  }
1643 
1644  /*
1645  * Line number of the current section.
1646  */
1647  if (strcmp(fmt, "line") == 0) {
1648  fr_value_box_int32(vb, NULL, cf_lineno(instruction->ci), false);
1649 
1650  goto finish;
1651  }
1652 
1653  /*
1654  * Filename of the current section.
1655  */
1656  if (strcmp(fmt, "filename") == 0) {
1657  if (fr_value_box_strdup(vb, vb, NULL, cf_filename(instruction->ci), false) < 0) goto error;
1658 
1659  goto finish;
1660  }
1661 
1662 finish:
1663  if (vb->type != FR_TYPE_NULL) {
1664  fr_dcursor_append(out, vb);
1665  } else {
1666  talloc_free(vb);
1667  }
1668 
1669  return XLAT_ACTION_DONE;
1670 }
1671 
1672 /** Initialize a unlang compiler / interpret.
1673  *
1674  * @param[in] ctx to bind lifetime of the interpret to.
1675  * Shouldn't be any free order issues here as
1676  * the interpret itself has no state.
1677  * But event loop should be stopped before
1678  * freeing the interpret.
1679  * @param[in] el for any timer or I/O events.
1680  * @param[in] funcs Callbacks to used to communicate request
1681  * state to our owner.
1682  * @param[in] uctx Data to pass to callbacks.
1683  */
1685  fr_event_list_t *el, unlang_request_func_t *funcs, void *uctx)
1686 {
1687  unlang_interpret_t *intp;
1688 
1689  fr_assert(funcs->init_internal);
1690 
1691  fr_assert(funcs->done_internal);
1692  fr_assert(funcs->done_detached);
1693  fr_assert(funcs->done_external);
1694 
1695  fr_assert(funcs->detach);
1696  fr_assert(funcs->stop);
1697  fr_assert(funcs->yield);
1698  fr_assert(funcs->resume);
1699  fr_assert(funcs->mark_runnable);
1700  fr_assert(funcs->scheduled);
1701 
1702  MEM(intp = talloc(ctx, unlang_interpret_t));
1703  *intp = (unlang_interpret_t){
1704  .el = el,
1705  .funcs = *funcs,
1706  .uctx = uctx
1707  };
1708 
1709  return intp;
1710 }
1711 
1712 /** Discard the bottom most frame on the request's stack
1713  *
1714  * This is used for cleaning up after errors. i.e. the caller
1715  * uses a push function, and experiences an error and needs to
1716  * remove the frame that was just pushed.
1717  */
1719 {
1720  frame_pop(request, request->stack);
1721 }
1722 
1723 /** Set a specific interpreter for a request
1724  *
1725  */
1727 {
1728  unlang_stack_t *stack = request->stack;
1729  stack->intp = intp;
1730 }
1731 
1732 /** Get the interpreter set for a request
1733  *
1734  */
1736 {
1737  unlang_stack_t *stack = request->stack;
1738 
1739  return stack->intp;
1740 }
1741 
1742 /** Get the event list for the current interpreter
1743  *
1744  */
1746 {
1747  unlang_stack_t *stack = request->stack;
1748 
1749  if (!stack->intp) return NULL;
1750 
1751  return stack->intp->el;
1752 }
1753 
1754 /** Set the default interpreter for this thread
1755  *
1756  */
1758 {
1759  if (intp) (void)talloc_get_type_abort(intp, unlang_interpret_t);
1760 
1761  intp_thread_default = intp;
1762 }
1763 
1764 /** Get the default interpreter for this thread
1765  *
1766  * This allows detached requests to be executed asynchronously
1767  */
1769 {
1770  if (!intp_thread_default) return NULL;
1771 
1772  return talloc_get_type_abort(intp_thread_default, unlang_interpret_t);
1773 }
1774 
1775 int unlang_interpret_init_global(TALLOC_CTX *ctx)
1776 {
1777  xlat_t *xlat;
1778  /*
1779  * Should be void, but someone decided not to register multiple xlats
1780  * breaking the convention we use everywhere else in the server...
1781  */
1782  if (unlikely((xlat = xlat_func_register(ctx, "interpreter", unlang_interpret_xlat, FR_TYPE_VOID)) == NULL)) return -1;
1784 
1785  if (unlikely((xlat = xlat_func_register(ctx, "cancel", unlang_cancel_xlat, FR_TYPE_VOID)) == NULL)) return -1;
1787 
1788  return 0;
1789 }
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
@ UNLANG_ACTION_UNWIND
Break out of the current group.
Definition: action.h:41
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition: action.h:39
@ UNLANG_ACTION_EXECUTE_NEXT
Execute the next unlang_t.
Definition: action.h:38
@ 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
va_list args
Definition: acutest.h:770
static int const char * fmt
Definition: acutest.h:573
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define RCSID(id)
Definition: build.h:444
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
#define unlikely(_x)
Definition: build.h:378
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
CONF_SECTION * unlang_call_current(request_t *request)
Return the last virtual server that was called.
Definition: call.c:225
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1126
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition: cf_util.c:1680
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1112
#define cf_lineno(_cf)
Definition: cf_util.h:101
#define cf_data_find(_cf, _type, _name)
Definition: cf_util.h:220
#define cf_filename(_cf)
Definition: cf_util.h:104
fr_table_num_sorted_t const mod_rcode_table[]
Definition: compile.c:72
int actions[RLM_MODULE_NUMCODES]
Definition: compile.h:37
fr_retry_config_t retry
Definition: compile.h:38
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:405
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition: dcursor.h:434
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition: debug.h:208
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
static fr_time_delta_t timeout
Definition: dhcpclient.c:54
static fr_slen_t in
Definition: dict.h:645
#define fr_event_timer_at(...)
Definition: event.h:250
#define fr_event_timer_in(...)
Definition: event.h:255
static xlat_action_t unlang_interpret_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Get information about the interpreter state.
Definition: interpret.c:1525
static size_t unlang_action_table_len
Definition: interpret.c:50
static fr_table_num_ordered_t const unlang_frame_action_table[]
Definition: interpret.c:52
static void unlang_interpret_request_detach(request_t *request)
Definition: interpret.c:1101
rlm_rcode_t unlang_interpret(request_t *request)
Run the interpreter for a current request.
Definition: interpret.c:760
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition: interpret.c:1745
static unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame, rlm_rcode_t *result, int *priority)
Evaluates all the unlang nodes in a section.
Definition: interpret.c:516
static unlang_group_t empty_group
Definition: interpret.c:958
void unlang_interpet_frame_discard(request_t *request)
Discard the bottom most frame on the request's stack.
Definition: interpret.c:1718
static unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t *frame, rlm_rcode_t *result, int *priority)
Update the current result after each instruction, and after popping each stack frame.
Definition: interpret.c:307
int unlang_interpret_push_instruction(request_t *request, void *instruction, rlm_rcode_t default_rcode, bool top_frame)
Push an instruction onto the request stack for later interpretation.
Definition: interpret.c:1005
void unlang_interpret_request_done(request_t *request)
Indicate to the caller of the interpreter that this request is complete.
Definition: interpret.c:1062
unlang_interpret_t * unlang_interpret_get(request_t *request)
Get the interpreter set for a request.
Definition: interpret.c:1735
void unlang_interpret_set(request_t *request, unlang_interpret_t *intp)
Set a specific interpreter for a request.
Definition: interpret.c:1726
rlm_rcode_t unlang_interpret_stack_result(request_t *request)
Get the current rcode for the frame.
Definition: interpret.c:1278
int unlang_interpret_stack_depth(request_t *request)
Return the depth of the request's stack.
Definition: interpret.c:1263
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition: interpret.c:1340
static xlat_arg_parser_t const unlang_interpret_xlat_args[]
Definition: interpret.c:1516
bool unlang_request_is_scheduled(request_t const *request)
Return whether a request is currently scheduled.
Definition: interpret.c:1300
void unlang_frame_signal(request_t *request, fr_signal_t action, int limit)
Send a signal (usually stop) to a request.
Definition: interpret.c:1130
int unlang_interpret_init_global(TALLOC_CTX *ctx)
Definition: interpret.c:1775
void unlang_interpret_set_thread_default(unlang_interpret_t *intp)
Set the default interpreter for this thread.
Definition: interpret.c:1757
#define DUMP_STACK
Definition: interpret.c:143
unlang_interpret_t * unlang_interpret_init(TALLOC_CTX *ctx, fr_event_list_t *el, unlang_request_func_t *funcs, void *uctx)
Initialize a unlang compiler / interpret.
Definition: interpret.c:1684
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
bool unlang_request_is_cancelled(request_t const *request)
Return whether a request has been cancelled.
Definition: interpret.c:1310
static void unlang_interpret_request_stop(request_t *request)
Definition: interpret.c:1087
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition: interpret.c:1184
static char * stack_unwind_flag_dump(uint8_t unwind)
Definition: interpret.c:106
static xlat_arg_parser_t const unlang_cancel_xlat_args[]
Definition: interpret.c:1399
static void instruction_timeout_handler(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *ctx)
Definition: interpret.c:1244
static fr_table_num_ordered_t const unlang_action_table[]
Definition: interpret.c:42
static void stack_dump(request_t *request)
Definition: interpret.c:129
static int _local_variables_free(unlang_variable_ref_t *ref)
Definition: interpret.c:220
static void instruction_dump(request_t *request, unlang_t const *instruction)
Definition: interpret.c:60
bool unlang_interpret_is_resumable(request_t *request)
Check if a request as resumable.
Definition: interpret.c:1322
unlang_action_t unlang_interpret_push_children(rlm_rcode_t *p_result, request_t *request, rlm_rcode_t default_rcode, bool do_next_sibling)
Push the children of the current frame onto a new frame onto the stack.
Definition: interpret.c:243
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition: interpret.c:1384
int unlang_interpret_push_section(request_t *request, CONF_SECTION *cs, rlm_rcode_t default_rcode, bool top_frame)
Push a configuration section onto the request stack for later interpretation.
Definition: interpret.c:982
void unlang_interpret_stack_result_set(request_t *request, rlm_rcode_t rcode)
Overwrite the current stack rcode.
Definition: interpret.c:1290
#define UNWIND_FLAG_DUMP(attrib)
request_t * request
Definition: interpret.c:217
static void frame_dump(request_t *request, unlang_stack_frame_t *frame)
Definition: interpret.c:75
void * unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
Allocate a new unlang stack.
Definition: interpret.c:1036
static xlat_action_t unlang_cancel_never_run(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
Definition: interpret.c:1429
fr_dict_t const * dict
Definition: interpret.c:216
static xlat_action_t unlang_cancel_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Allows a request to dynamically alter its own lifetime.
Definition: interpret.c:1443
static size_t unlang_frame_action_table_len
Definition: interpret.c:57
unlang_interpret_t * unlang_interpret_get_thread_default(void)
Get the default interpreter for this thread.
Definition: interpret.c:1768
static void unlang_cancel_event(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Signal the request to stop executing.
Definition: interpret.c:1414
static _Thread_local unlang_interpret_t * intp_thread_default
The default interpreter instance for this thread.
Definition: interpret.c:40
unlang_request_stop_t stop
function called when a request is signalled to stop.
Definition: interpret.h:113
#define UNLANG_STACK_MAX
The maximum depth of the stack.
Definition: interpret.h:38
unlang_request_done_t done_internal
Function called when an internal request completes.
Definition: interpret.h:109
unlang_request_resume_t resume
Function called when a request is resumed.
Definition: interpret.h:115
#define UNLANG_SUB_FRAME
Definition: interpret.h:36
unlang_request_done_t done_external
Function called when a external request completes.
Definition: interpret.h:108
unlang_request_init_t detach
Function called when a request is detached.
Definition: interpret.h:112
unlang_request_runnable_t mark_runnable
Function called when a request needs to be added back to the runnable queue.
Definition: interpret.h:116
unlang_request_yield_t yield
Function called when a request yields.
Definition: interpret.h:114
unlang_request_done_t done_detached
Function called when a detached request completes.
Definition: interpret.h:110
unlang_request_scheduled_t scheduled
Function to check if a request is already scheduled.
Definition: interpret.h:118
unlang_request_init_t init_internal
Function called to initialise an internal request.
Definition: interpret.h:106
struct unlang_interpret_s unlang_interpret_t
Interpreter handle.
Definition: interpret.h:44
External functions provided by the owner of the interpret.
Definition: interpret.h:100
Private declarations for the unlang interpreter.
fr_event_list_t * el
unlang_request_func_t funcs
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:443
#define DEBUG_ENABLED5
True if global debug level 1-5 messages are enabled.
Definition: log.h:261
#define RDEBUG3(fmt,...)
Definition: log.h:343
#define RERROR(fmt,...)
Definition: log.h:298
#define RPERROR(fmt,...)
Definition: log.h:302
#define RPEDEBUG(fmt,...)
Definition: log.h:376
#define RDEBUG4(fmt,...)
Definition: log.h:344
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:430
unlang_op_t unlang_ops[UNLANG_TYPE_MAX]
Different operations the interpreter can execute.
Definition: base.c:33
fr_time_t fr_event_timer_when(fr_event_timer_t const *ev)
Internal timestamp representing when the timer should fire.
Definition: event.c:1626
talloc_free(reap)
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_TIME_DELTA
A period of time measured in nanoseconds.
Definition: merged_model.c:113
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
Definition: merged_model.c:81
@ FR_TYPE_VOID
User data.
Definition: merged_model.c:127
unsigned char uint8_t
Definition: merged_model.c:30
static uint8_t depth(fr_minmax_heap_index_t i)
Definition: minmax_heap.c:83
Declarations for the unlang module interface.
fr_pair_t * fr_pair_delete(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list and free.
Definition: pair.c:1819
Declarations for the unlang "parallel" keyword.
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG_ENABLED2()
Definition: radclient.h:50
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
#define RDEBUG(fmt,...)
Definition: radclient.h:53
#define RDEBUG_ENABLED()
Definition: radclient.h:49
fr_table_num_sorted_t const rcode_table[]
Definition: rcode.c:35
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition: rcode.h:42
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition: rcode.h:41
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition: rcode.h:51
#define REQUEST_VERIFY(_x)
Definition: request.h:275
@ REQUEST_TYPE_EXTERNAL
A request received on the wire.
Definition: request.h:152
@ REQUEST_TYPE_INTERNAL
A request generated internally.
Definition: request.h:153
@ REQUEST_TYPE_DETACHED
A request that was generated internally, but is now detached (not associated with a parent request....
Definition: request.h:154
#define request_is_detachable(_x)
Definition: request.h:161
@ REQUEST_STOP_PROCESSING
Definition: request.h:62
void * request_data_get(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request.
Definition: request_data.c:292
#define request_data_add(_request, _unique_ptr, _unique_int, _opaque, _free_on_replace, _free_on_parent, _persist)
Add opaque data to a request_t.
Definition: request_data.h:59
fr_signal_t
Definition: signal.h:48
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:689
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition: state_test.c:8
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition: table.h:253
An element in an arbitrarily ordered array of name to num mappings.
Definition: table.h:53
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition: talloc.h:165
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:588
#define fr_time_delta_ispos(_a)
Definition: time.h:288
#define fr_time_delta_eq(_a, _b)
Definition: time.h:285
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition: time.h:196
static fr_time_t fr_time_from_sec(time_t when)
Convert a time_t (wallclock time) to a fr_time_t (internal time)
Definition: time.h:856
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition: time.h:229
"server local" time.
Definition: time.h:69
static fr_event_list_t * el
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
bool required
Argument must be present, and non-empty.
Definition: xlat.h:146
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition: xlat.h:365
#define XLAT_ARG_PARSER_TERMINATOR
Definition: xlat.h:166
xlat_action_t
Definition: xlat.h:35
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition: xlat.h:42
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition: xlat.h:41
Definition for a single argument consumend by an xlat function.
Definition: xlat.h:145
#define UNWIND_FLAG_RETURN_POINT
'return' stops here.
Definition: unlang_priv.h:349
fr_retry_state_t state
Definition: unlang_priv.h:270
#define unlang_frame_perf_resume(_x)
Definition: unlang_priv.h:261
static void frame_pop(request_t *request, unlang_stack_t *stack)
Pop a stack frame, removing any associated dynamically allocated state.
Definition: unlang_priv.h:490
unlang_t * next
Next node (executed on UNLANG_ACTION_EXECUTE_NEXT et al).
Definition: unlang_priv.h:124
uint32_t count
Definition: unlang_priv.h:272
static void frame_next(unlang_stack_t *stack, unlang_stack_frame_t *frame)
Advance to the next sibling instruction.
Definition: unlang_priv.h:473
static bool is_repeatable(unlang_stack_frame_t const *frame)
Definition: unlang_priv.h:365
#define UNWIND_FLAG_TOP_FRAME
are we the top frame of the stack?
Definition: unlang_priv.h:344
#define UNLANG_NEXT_SIBLING
Definition: unlang_priv.h:103
static void repeatable_clear(unlang_stack_frame_t *frame)
Definition: unlang_priv.h:359
unlang_signal_t signal
function to call when signalling this stack frame
Definition: unlang_priv.h:293
char const * debug_name
Printed in log messages when the node is executed.
Definition: unlang_priv.h:126
void * state
Stack frame specialisations.
Definition: unlang_priv.h:304
static unlang_t * unlang_group_to_generic(unlang_group_t const *p)
Definition: unlang_priv.h:546
#define MOD_ACTION_RETRY
Definition: unlang_priv.h:46
static void frame_state_init(unlang_stack_t *stack, unlang_stack_frame_t *frame)
Definition: unlang_priv.h:408
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
Definition: unlang_priv.h:539
#define MOD_ACTION_REJECT
Definition: unlang_priv.h:45
int priority
Result priority.
Definition: unlang_priv.h:309
unlang_dump_t dump
Dump additional information about the frame state.
Definition: unlang_priv.h:221
static unlang_action_t unwind_all(unlang_stack_t *stack)
Definition: unlang_priv.h:381
#define UNWIND_FLAG_NO_CLEAR
Keep unwinding, don't clear the unwind flag.
Definition: unlang_priv.h:350
#define UNWIND_FLAG_BREAK_POINT
'break' stops here.
Definition: unlang_priv.h:348
unlang_process_t interpret
Function to interpret the keyword.
Definition: unlang_priv.h:217
#define UNWIND_FLAG_NONE
No flags.
Definition: unlang_priv.h:342
uint8_t uflags
Unwind markers.
Definition: unlang_priv.h:313
int depth
of this retry structure
Definition: unlang_priv.h:269
static void frame_cleanup(unlang_stack_frame_t *frame)
Cleanup any lingering frame state.
Definition: unlang_priv.h:456
request_t * request
Definition: unlang_priv.h:268
CONF_ITEM * ci
used to generate this item
Definition: unlang_priv.h:129
static bool is_top_frame(unlang_stack_frame_t const *frame)
Definition: unlang_priv.h:366
fr_event_timer_t const * ev
Definition: unlang_priv.h:273
#define MOD_ACTION_RETURN
Definition: unlang_priv.h:44
static void stack_unwind_break_clear(unlang_stack_t *stack)
Definition: unlang_priv.h:391
unlang_actions_t actions
Priorities, etc. for the various return codes.
Definition: unlang_priv.h:131
char const * name
Unknown...
Definition: unlang_priv.h:125
#define MOD_PRIORITY_MAX
Definition: unlang_priv.h:47
static bool is_break_point(unlang_stack_frame_t const *frame)
Definition: unlang_priv.h:367
@ UNLANG_TYPE_GROUP
Grouping section.
Definition: unlang_priv.h:58
unlang_t const * instruction
The unlang node we're evaluating.
Definition: unlang_priv.h:289
unlang_t self
Definition: unlang_priv.h:156
bool debug_braces
Whether the operation needs to print braces in debug mode.
Definition: unlang_priv.h:228
static bool is_yielded(unlang_stack_frame_t const *frame)
Definition: unlang_priv.h:369
static void top_frame_set(unlang_stack_frame_t *frame)
Definition: unlang_priv.h:354
unlang_variable_t * variables
rarely used, so we don't usually need it
Definition: unlang_priv.h:163
rlm_rcode_t result
The result from executing the instruction.
Definition: unlang_priv.h:308
char const * name
Name of the operation.
Definition: unlang_priv.h:215
unlang_frame_action_t
Allows the frame evaluator to signal the interpreter.
Definition: unlang_priv.h:93
@ UNLANG_FRAME_ACTION_POP
Pop the current frame, and check the next one further up in the stack for what to do next.
Definition: unlang_priv.h:94
@ UNLANG_FRAME_ACTION_YIELD
Temporarily return control back to the caller on the C stack.
Definition: unlang_priv.h:98
@ UNLANG_FRAME_ACTION_NEXT
Process the next instruction at this level.
Definition: unlang_priv.h:97
@ UNLANG_FRAME_ACTION_RETRY
retry the current frame
Definition: unlang_priv.h:96
static void yielded_set(unlang_stack_frame_t *frame)
Definition: unlang_priv.h:357
static void yielded_clear(unlang_stack_frame_t *frame)
Definition: unlang_priv.h:363
#define unlang_frame_perf_yield(_x)
Definition: unlang_priv.h:260
fr_time_t timeout
Definition: unlang_priv.h:271
#define unlang_frame_perf_cleanup(_x)
Definition: unlang_priv.h:262
unlang_t const * next
The next unlang node we will evaluate.
Definition: unlang_priv.h:290
static void stack_unwind_return_clear(unlang_stack_t *stack)
Definition: unlang_priv.h:392
fr_dict_t * dict
our dictionary
Definition: unlang_priv.h:146
static bool is_return_point(unlang_stack_frame_t const *frame)
Definition: unlang_priv.h:368
unlang_type_t type
The specialisation of this node.
Definition: unlang_priv.h:127
unlang_t * children
Children beneath this group.
Definition: unlang_priv.h:157
static void stack_unwind_top_frame_clear(unlang_stack_t *stack)
Definition: unlang_priv.h:390
Generic representation of a grouping.
Definition: unlang_priv.h:155
An unlang operation.
Definition: unlang_priv.h:214
A node in a graph of unlang_op_t (s) that we execute.
Definition: unlang_priv.h:122
Our interpreter stack, as distinct from the C stack.
Definition: unlang_priv.h:288
An unlang stack associated with a request.
Definition: unlang_priv.h:322
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition: pair.h:260
#define RETRY_INIT
Definition: retry.h:39
uint32_t mrc
Maximum retransmission count.
Definition: retry.h:36
@ FR_RETRY_MRC
reached maximum retransmission count
Definition: retry.h:57
@ FR_RETRY_CONTINUE
Definition: retry.h:56
@ FR_RETRY_MRD
reached maximum retransmission duration
Definition: retry.h:58
fr_time_delta_t mrd
Maximum retransmission duration.
Definition: retry.h:35
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
Definition: value.c:3876
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
Definition: value.c:4097
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:608
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition: value.h:619
static size_t char ** out
Definition: value.h:984
An xlat calling ctx.
Definition: xlat_ctx.h:42
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition: xlat_func.c:360
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition: xlat_func.c:195