The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
foreach.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: ae1abd172f1c138f3a209e97cb6fb630feeca3db $
19  *
20  * @file unlang/foreach.c
21  * @brief Unlang "foreach" keyword evaluation.
22  *
23  * @copyright 2006-2019 The FreeRADIUS server project
24  */
25 RCSID("$Id: ae1abd172f1c138f3a209e97cb6fb630feeca3db $")
26 
27 #include <freeradius-devel/server/request_data.h>
28 #include <freeradius-devel/server/tmpl_dcursor.h>
29 #include <freeradius-devel/unlang/xlat_func.h>
30 
31 #include "foreach_priv.h"
32 #include "return_priv.h"
33 #include "xlat_priv.h"
34 
35 static char const * const xlat_foreach_names[] = {"Foreach-Variable-0",
36  "Foreach-Variable-1",
37  "Foreach-Variable-2",
38  "Foreach-Variable-3",
39  "Foreach-Variable-4",
40  "Foreach-Variable-5",
41  "Foreach-Variable-6",
42  "Foreach-Variable-7",
43  "Foreach-Variable-8",
44  "Foreach-Variable-9"};
45 
46 static int xlat_foreach_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; /* up to 10 for foreach */
47 
48 #define BUFFER_SIZE (256)
49 
50 /** State of a foreach loop
51  *
52  */
53 typedef struct {
54  request_t *request; //!< The current request.
55  fr_dcursor_t cursor; //!< Used to track our place in the list
56  fr_pair_t *key; //!< local variable which contains the key
57  fr_pair_t *value; //!< local variable which contains the value
58  tmpl_t const *vpt; //!< pointer to the vpt
59 
60  uint32_t index; //!< for xlat results
61  char *buffer; //!< for key values
62 
63  bool success; //!< for xlat expansion
64  fr_value_box_list_t list; //!< value box list for looping over xlats
65 
66  tmpl_dcursor_ctx_t cc; //!< tmpl cursor state
67 
68  ///< we're iterating over.
69  fr_pair_list_t vps; //!< List containing the attribute(s) we're
70  ///< iterating over.
71  int depth; //!< Level of nesting of this foreach loop.
72 #ifndef NDEBUG
73  int indent; //!< for catching indentation issues
74 #endif
76 
77 /*
78  * Brute-force things instead of doing it the "right" way.
79  *
80  * We would ideally like to have the local variable be a ref to the current vp from the cursor. However,
81  * that isn't (yet) supported. In order to support that, we would likely have to add a new data type
82  * FR_TYPE_DCURSOR, and put the cursor into in vp->vp_ptr. We would then have to update a lot of things:
83  *
84  * - the foreach code has to put the dcursor into state->value->vp_ptr.
85  * - the pair code (all of it, perhaps) has to check for "is this thing a cursor), and if so
86  * return the next pair from the cursor instead of the given pair. This is a huge change.
87  * - update all of the pair / value-box APIs to handle the new data type
88  * - check performance, etc, and that nothing else breaks.
89  * - also need to ensure that the pair with the cursor _cannot_ be copied, as that would add two
90  * refs to the cursor.
91  * - if we're lucky, we could perhaps _instead_ update only the tmpl code, but the cursor
92  * still has to be in the pair.
93  * - we can update tmpl_eval_pair(), because that's what's used in the xlat code. That gets us all
94  * references to the _source_ VP.
95  * - we also have to update the edit.c code, which calls tmpl_dcursor_init() to get pairs from
96  * a tmpl_t of type ATTR.
97  * - for LHS assignment, the edit code has to be updated: apply_edits_to_leaf() and apply_edits_to_list()
98  * which calls fr_edit_list_apply_pair_assignment() to do the actual work. But we could likely just
99  * check current->lhs.vp, and dereference that to get the underlying thing.
100  *
101  * What we ACTUALLY do instead is in the compiler when we call define_local_variable(), we clone the "da"
102  * hierarchy via fr_dict_attr_acopy_local(). That function which should go away when we add refs.
103  *
104  * Then this horrific function copies the pairs by number, which re-parents them to the correct
105  * destination da. It's brute-force and expensive, but it's easy. And for now, it's less work than
106  * re-doing substantial parts of the server core and utility libraries.
107  */
108 static int unlang_foreach_pair_copy(fr_pair_t *to, fr_pair_t *from, fr_dict_attr_t const *from_parent)
109 {
110  fr_assert(fr_type_is_structural(to->vp_type));
111  fr_assert(fr_type_is_structural(from->vp_type));
112 
113  fr_pair_list_foreach(&from->vp_group, vp) {
114  fr_pair_t *child;
115 
116  /*
117  * We only copy children of the parent TLV, but we can copy internal attributes, as they
118  * can exist anywhere.
119  */
120  if (vp->da->parent != from_parent) {
121  if (vp->da->flags.internal) {
122  child = fr_pair_copy(to, vp);
123  if (child) fr_pair_append(&to->vp_group, child);
124  }
125  continue;
126  }
127 
128  child = fr_pair_afrom_child_num(to, to->da, vp->da->attr);
129  if (!child) continue;
130 
131  fr_pair_append(&to->vp_group, child);
132 
133  if (fr_type_is_leaf(child->vp_type)) {
134  if (fr_value_box_copy(child, &child->data, &vp->data) < 0) return -1;
135  continue;
136  }
137 
138  if (unlang_foreach_pair_copy(child, vp, vp->da) < 0) return -1;
139  }
140 
141  return 0;
142 }
143 
144 static xlat_action_t unlang_foreach_xlat_func(TALLOC_CTX *ctx, fr_dcursor_t *out,
145  xlat_ctx_t const *xctx,
146  request_t *request, UNUSED fr_value_box_list_t *in);
147 
148 #define FOREACH_REQUEST_DATA (void *)unlang_foreach_xlat_func
149 
150 /** Ensure request data is pulled out of the request if the frame is popped
151  *
152  */
154 {
155  if (state->value) {
156  fr_pair_t *vp;
157 
158  if (tmpl_is_xlat(state->vpt)) return 0;
159 
160  tmpl_dcursor_clear(&state->cc);
161 
162  /*
163  * Now that we're done, the leaf entries can be changed again.
164  */
165  vp = tmpl_dcursor_init(NULL, NULL, &state->cc, &state->cursor, state->request, state->vpt);
166  fr_assert(vp != NULL);
167 
168  do {
169  vp->vp_edit = false;
170  } while ((vp = fr_dcursor_next(&state->cursor)) != NULL);
171  tmpl_dcursor_clear(&state->cc);
172 
173  } else {
175  }
176 
177  return 0;
178 }
179 
181 {
182  unlang_frame_state_foreach_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
183  fr_pair_t *vp;
184 
186 
187  vp = fr_dcursor_next(&state->cursor);
188 
189  /*
190  * Skip any non-leaf attributes - adds sanity to foreach &request.[*]
191  */
192  while (vp) {
193  switch (vp->vp_type) {
194  case FR_TYPE_LEAF:
195  break;
196  default:
197  vp = fr_dcursor_next(&state->cursor);
198  continue;
199  }
200  break;
201  }
202 
203  if (!vp) {
204  *p_result = frame->result;
205 #ifndef NDEBUG
206  fr_assert(state->indent == request->log.indent.unlang);
207 #endif
209  }
210 
211 #ifndef NDEBUG
212  RDEBUG2("# looping with: Foreach-Variable-%d = %pV", state->depth, &vp->data);
213 #endif
214 
215  repeatable_set(frame);
216 
217  /*
218  * Push the child, and yield for a later return.
219  */
220  return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
221 }
222 
224 {
225  fr_value_box_t box;
226 
227  if (!state->key) return 0;
228 
229  fr_value_box_clear_value(&state->key->data);
230 
231  fr_value_box(&box, state->index, false);
232 
233  if (fr_value_box_cast(state->key, &state->key->data, state->key->vp_type, state->key->da, &box) < 0) {
234  RDEBUG("Failed casting 'foreach' key variable '%s' from %u", state->key->da->name, state->index);
235  return -1;
236  }
237 
238  return 0;
239 }
240 
241 
243 {
244  unlang_frame_state_foreach_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
245  fr_value_box_t *box;
246 
247 next:
248  state->index++;
249 
250  box = fr_dcursor_next(&state->cursor);
251  if (!box) {
252  *p_result = frame->result;
254  }
255 
256  if (unlang_foreach_xlat_key_update(request, state) < 0) goto next;
257 
258  fr_value_box_clear_value(&state->value->data);
259  if (fr_value_box_cast(state->value, &state->value->data, state->value->vp_type, state->value->da, box) < 0) {
260  RDEBUG("Failed casting 'foreach' iteration variable '%s' from %pV", state->value->da->name, box);
261  goto next;
262  }
263 
264  repeatable_set(frame);
265 
266  /*
267  * Push the child, and yield for a later return.
268  */
269  return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
270 }
271 
272 
274 {
275  unlang_frame_state_foreach_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
276  fr_value_box_t *box;
277 
278  if (!state->success) {
279  RDEBUG("Failed expanding 'foreach' list");
280  *p_result = RLM_MODULE_FAIL;
282  }
283 
284  box = fr_dcursor_init(&state->cursor, fr_value_box_list_dlist_head(&state->list));
285  if (!box) {
286  done:
287  *p_result = RLM_MODULE_NOOP;
289  }
290 
291  fr_value_box_clear_value(&state->value->data);
292 
293 next:
294  if (fr_value_box_cast(state->value, &state->value->data, state->value->vp_type, state->value->da, box) < 0) {
295  RDEBUG("Failed casting 'foreach' iteration variable '%s' from %pV", state->value->da->name, box);
296  box = fr_dcursor_next(&state->cursor);
297  if (!box) goto done;
298 
299  goto next;
300  }
301 
303  repeatable_set(frame);
304 
305  /*
306  * Push the child, and yield for a later return.
307  */
308  return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
309 }
310 
311 
312 /*
313  * Loop over an xlat expansion
314  */
317 {
318  fr_value_box_list_init(&state->list);
319 
320  if (unlang_xlat_push(state, &state->success, &state->list, request, tmpl_xlat(state->vpt), false) < 0) {
321  REDEBUG("Failed starting expansion of %s", state->vpt->name);
322  *p_result = RLM_MODULE_FAIL;
324  }
325 
326  if (unlang_foreach_xlat_key_update(request, state) < 0) {
327  *p_result = RLM_MODULE_FAIL;
329  }
330 
332  repeatable_set(frame);
333 
335 }
336 
338 {
339  if (!state->key) return;
340 
341  fr_value_box_clear_value(&state->key->data);
342  if (tmpl_dcursor_print(&FR_SBUFF_IN(state->buffer, BUFFER_SIZE), &state->cc) > 0) {
343  fr_value_box_strdup(state->key, &state->key->data, NULL, state->buffer, false);
344  }
345 }
346 
348 {
349  unlang_frame_state_foreach_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
350  fr_pair_t *vp;
351 
353 
354  vp = fr_dcursor_current(&state->cursor);
355  fr_assert(vp != NULL);
356 
357  /*
358  * If we modified the value, copy it back to the original pair. Note that the copy does NOT
359  * check the "immutable" flag. That flag is for the people using unlang, not for the
360  * interpreter.
361  */
362  if (fr_type_is_leaf(vp->vp_type)) {
363  if (vp->vp_type == state->value->vp_type) {
365  (void) fr_value_box_copy(vp, &vp->data, &state->value->data);
366  }
367  } else {
368  /*
369  * @todo - copy the pairs back?
370  */
371  }
372 
373 next:
374  vp = fr_dcursor_next(&state->cursor);
375  if (!vp) {
376  *p_result = frame->result;
377 #ifndef NDEBUG
378  fr_assert(state->indent == request->log.indent.unlang);
379 #endif
381  }
382 
383  unlang_foreach_attr_key_update(request, state);
384 
385  /*
386  * Copy the data.
387  */
388  if (vp->vp_type == FR_TYPE_GROUP) {
389  fr_assert(state->value->vp_type == FR_TYPE_GROUP);
390 
391  fr_pair_list_free(&state->value->vp_group);
392 
393  if (fr_pair_list_copy(state->value, &state->value->vp_group, &vp->vp_group) < 0) {
394  REDEBUG("Failed copying members of %s", state->value->da->name);
395  *p_result = RLM_MODULE_FAIL;
397  }
398 
399  } else if (fr_type_is_structural(vp->vp_type)) {
400  fr_assert(state->value->vp_type == vp->vp_type);
401 
402  fr_pair_list_free(&state->value->vp_group);
403 
404  if (unlang_foreach_pair_copy(state->value, vp, vp->da) < 0) {
405  REDEBUG("Failed copying children of %s", state->value->da->name);
406  *p_result = RLM_MODULE_FAIL;
408  }
409 
410  } else {
411  fr_value_box_clear_value(&state->value->data);
412  if (fr_value_box_cast(state->value, &state->value->data, state->value->vp_type, state->value->da, &vp->data) < 0) {
413  RDEBUG("Failed casting 'foreach' iteration variable '%s' from %pP", state->value->da->name, vp);
414  goto next;
415  }
416 
417 #ifndef NDEBUG
418  RDEBUG2("# looping with: %s = %pV", state->value->da->name, &vp->data);
419 #endif
420  }
421 
422  repeatable_set(frame);
423 
424  /*
425  * Push the child, and yield for a later return.
426  */
427  return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
428 }
429 
430 /*
431  * Loop over an attribute
432  */
435 {
436  fr_pair_t *vp;
437 
438  /*
439  * No matching attributes, we can't do anything.
440  */
441  vp = tmpl_dcursor_init(NULL, NULL, &state->cc, &state->cursor, request, state->vpt);
442  if (!vp) {
443  *p_result = RLM_MODULE_NOOP;
445  }
446 
447  /*
448  * Before we loop over the variables, ensure that the user can't pull the rug out from
449  * under us.
450  */
451  do {
452  if (vp->vp_edit) {
453  REDEBUG("Cannot do nested 'foreach' loops over the same attribute %pP", vp);
454  *p_result = RLM_MODULE_FAIL;
456  }
457 
458  vp->vp_edit = true;
459  } while ((vp = fr_dcursor_next(&state->cursor)) != NULL);
460  tmpl_dcursor_clear(&state->cc);
461 
462  vp = tmpl_dcursor_init(NULL, NULL, &state->cc, &state->cursor, request, state->vpt);
463  fr_assert(vp != NULL);
464 
465  /*
466  * Update the key with the current path or index.
467  */
468  unlang_foreach_attr_key_update(request, state);
469 
470  if (vp->vp_type == FR_TYPE_GROUP) {
471  fr_assert(state->value->vp_type == FR_TYPE_GROUP);
472 
473  if (fr_pair_list_copy(state->value, &state->value->vp_group, &vp->vp_group) < 0) {
474  REDEBUG("Failed copying members of %s", state->value->da->name);
475  *p_result = RLM_MODULE_FAIL;
477  }
478 
479  } else if (fr_type_is_structural(vp->vp_type)) {
480  if (state->value->vp_type == vp->vp_type) {
481  if (unlang_foreach_pair_copy(state->value, vp, vp->da) < 0) {
482  REDEBUG("Failed copying children of %s", state->value->da->name);
483  *p_result = RLM_MODULE_FAIL;
485  }
486  } else {
487  REDEBUG("Failed initializing loop variable %s - expected %s type, but got input (%pP)", state->value->da->name, fr_type_to_str(state->value->vp_type), vp);
488  *p_result = RLM_MODULE_FAIL;
490  }
491 
492  } else {
493  fr_value_box_clear_value(&state->value->data);
494  while (vp && (fr_value_box_cast(state->value, &state->value->data, state->value->vp_type, state->value->da, &vp->data) < 0)) {
495  RDEBUG("Failed casting 'foreach' iteration variable '%s' from %pP", state->value->da->name, vp);
496  vp = fr_dcursor_next(&state->cursor);
497  }
498 
499  /*
500  * Couldn't cast anything, the loop can't be run.
501  */
502  if (!vp) {
503  *p_result = RLM_MODULE_NOOP;
505  }
506  }
507 
509 
510  repeatable_set(frame);
511 
512  /*
513  * Push the child, and go process it.
514  */
515  return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
516 }
517 
518 
520 {
521  unlang_stack_t *stack = request->stack;
525 
526  int i, depth = 0;
527  fr_pair_list_t vps;
528  fr_pair_t *vp;
529 
530  fr_pair_list_init(&vps);
531 
532  /*
533  * Ensure any breaks terminate here...
534  */
535  break_point_set(frame);
536 
537  MEM(frame->state = state = talloc_zero(request->stack, unlang_frame_state_foreach_t));
538  talloc_set_destructor(state, _free_unlang_frame_state_foreach);
539 
540  state->request = request;
541 #ifndef NDEBUG
542  state->indent = request->log.indent.unlang;
543 #endif
544 
545  /*
546  * We have a key variable, let's use that.
547  */
548  if (gext->value) {
549  state->vpt = gext->vpt;
550 
551  /*
552  * Create the local variable and populate its value.
553  */
554  if (fr_pair_append_by_da(request->local_ctx, &state->value, &request->local_pairs, gext->value) < 0) {
555  REDEBUG("Failed creating %s", gext->value->name);
556  *p_result = RLM_MODULE_FAIL;
558  }
559  fr_assert(state->value != NULL);
560 
561  if (gext->key) {
562  if (fr_pair_append_by_da(request->local_ctx, &state->key, &request->local_pairs, gext->key) < 0) {
563  REDEBUG("Failed creating %s", gext->key->name);
564  *p_result = RLM_MODULE_FAIL;
566  }
567  fr_assert(state->key != NULL);
568  }
569 
570  if (tmpl_is_attr(gext->vpt)) {
571  MEM(state->buffer = talloc_array(state, char, BUFFER_SIZE));
572  return unlang_foreach_attr_init(p_result, request, frame, state);
573  }
574 
575  fr_assert(tmpl_is_xlat(gext->vpt));
576 
577  return unlang_foreach_xlat_init(p_result, request, frame, state);
578  }
579 
580  /*
581  * Figure out foreach depth by walking back up the stack
582  */
583  if (stack->depth > 0) for (i = (stack->depth - 1); i >= 0; i--) {
584  unlang_t const *our_instruction;
585  our_instruction = stack->frame[i].instruction;
586  if (!our_instruction || (our_instruction->type != UNLANG_TYPE_FOREACH)) continue;
587  depth++;
588  }
589 
590  if (depth >= (int)NUM_ELEMENTS(xlat_foreach_names)) {
591  REDEBUG("foreach Nesting too deep!");
592  *p_result = RLM_MODULE_FAIL;
594  }
595 
596  fr_pair_list_init(&state->vps);
597 
598  /*
599  * Copy the VPs from the original request, this ensures deterministic
600  * behaviour if someone decides to add or remove VPs in the set we're
601  * iterating over.
602  */
603  if (tmpl_copy_pairs(frame->state, &vps, request, gext->vpt) < 0) { /* nothing to loop over */
604  *p_result = RLM_MODULE_NOOP;
606  }
607 
609 
610  fr_pair_list_append(&state->vps, &vps);
611  fr_pair_dcursor_init(&state->cursor, &state->vps);
612 
613  /*
614  * Skip any non-leaf attributes at the start of the cursor
615  * Adds sanity to foreach &request.[*]
616  */
617  vp = fr_dcursor_current(&state->cursor);
618  while (vp) {
619  switch (vp->vp_type) {
620  case FR_TYPE_LEAF:
621  break;
622  default:
623  vp = fr_dcursor_next(&state->cursor);
624  continue;
625  }
626  break;
627  }
628 
629  /*
630  * If no non-leaf attributes found clean up
631  */
632  if (!vp) {
633  fr_dcursor_free_list(&state->cursor);
634  *p_result = RLM_MODULE_NOOP;
636  }
637 
638  state->depth = depth;
639 
640  /*
641  * Add a (hopefully) faster lookup to get the state.
642  */
643  request_data_add(request, FOREACH_REQUEST_DATA, state->depth, state, false, false, false);
644 
646 
647  repeatable_set(frame);
648 
649  /*
650  * Push the child, and go process it.
651  */
652  return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
653 }
654 
656 {
657  RDEBUG2("%s", unlang_ops[frame->instruction->type].name);
658 
659  *p_result = frame->result;
660 
661  /*
662  * Stop at the next break point, or if we hit
663  * the a top frame.
664  */
665  return unwind_to_break(request->stack);
666 }
667 
668 /** Implements the Foreach-Variable-X
669  *
670  * @ingroup xlat_functions
671  */
673  xlat_ctx_t const *xctx,
674  request_t *request, UNUSED fr_value_box_list_t *in)
675 {
676  fr_pair_t *vp;
677  int const *inst = xctx->inst;
678  fr_value_box_t *vb;
680 
682  if (!state) return XLAT_ACTION_FAIL;
683 
684  vp = fr_dcursor_current(&state->cursor);
685  fr_assert(vp != NULL);
686 
687  MEM(vb = fr_value_box_alloc_null(ctx));
688  fr_value_box_copy(vb, vb, &vp->data);
689  fr_dcursor_append(out, vb);
690  return XLAT_ACTION_DONE;
691 }
692 
693 void unlang_foreach_init(TALLOC_CTX *ctx)
694 {
695  size_t i;
696 
697  for (i = 0; i < NUM_ELEMENTS(xlat_foreach_names); i++) {
698  xlat_t *x;
699 
702  fr_assert(x);
704  x->uctx = &xlat_foreach_inst[i];
705  }
706 
708  &(unlang_op_t){
709  .name = "foreach",
710  .interpret = unlang_foreach,
711  .debug_braces = true
712  });
713 
715  &(unlang_op_t){
716  .name = "break",
717  .interpret = unlang_break,
718  });
719 }
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_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition: action.h:37
#define RCSID(id)
Definition: build.h:481
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:406
#define fr_dcursor_init(_cursor, _head)
Initialise a cursor.
Definition: dcursor.h:732
next
Definition: dcursor.h:178
static void fr_dcursor_free_list(fr_dcursor_t *cursor)
Free the current item and all items after it.
Definition: dcursor.h:663
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:288
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition: dcursor.h:337
static fr_slen_t in
Definition: dict.h:821
static int unlang_foreach_pair_copy(fr_pair_t *to, fr_pair_t *from, fr_dict_attr_t const *from_parent)
Definition: foreach.c:108
uint32_t index
for xlat results
Definition: foreach.c:60
static char const *const xlat_foreach_names[]
Definition: foreach.c:35
static void unlang_foreach_attr_key_update(UNUSED request_t *request, unlang_frame_state_foreach_t *state)
Definition: foreach.c:337
static unlang_action_t unlang_foreach_attr_next(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition: foreach.c:347
char * buffer
for key values
Definition: foreach.c:61
static int xlat_foreach_inst[]
Definition: foreach.c:46
fr_dcursor_t cursor
Used to track our place in the list.
Definition: foreach.c:55
tmpl_t const * vpt
pointer to the vpt
Definition: foreach.c:58
void unlang_foreach_init(TALLOC_CTX *ctx)
Definition: foreach.c:693
fr_pair_t * key
local variable which contains the key
Definition: foreach.c:56
static unlang_action_t unlang_foreach_attr_init(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame, unlang_frame_state_foreach_t *state)
Definition: foreach.c:433
static unlang_action_t unlang_foreach_xlat_next(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition: foreach.c:242
bool success
for xlat expansion
Definition: foreach.c:63
fr_value_box_list_t list
value box list for looping over xlats
Definition: foreach.c:64
#define BUFFER_SIZE
Definition: foreach.c:48
fr_pair_t * value
local variable which contains the value
Definition: foreach.c:57
int depth
Level of nesting of this foreach loop.
Definition: foreach.c:71
static unlang_action_t unlang_foreach(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition: foreach.c:519
#define FOREACH_REQUEST_DATA
Definition: foreach.c:148
static unlang_action_t unlang_foreach_next_old(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition: foreach.c:180
static unlang_action_t unlang_break(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition: foreach.c:655
tmpl_dcursor_ctx_t cc
tmpl cursor state
Definition: foreach.c:66
int indent
for catching indentation issues
Definition: foreach.c:73
request_t * request
The current request.
Definition: foreach.c:54
static unlang_action_t unlang_foreach_xlat_expanded(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition: foreach.c:273
static unlang_action_t unlang_foreach_xlat_init(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame, unlang_frame_state_foreach_t *state)
Definition: foreach.c:315
fr_pair_list_t vps
List containing the attribute(s) we're iterating over.
Definition: foreach.c:69
static int unlang_foreach_xlat_key_update(request_t *request, unlang_frame_state_foreach_t *state)
Definition: foreach.c:223
static int _free_unlang_frame_state_foreach(unlang_frame_state_foreach_t *state)
Ensure request data is pulled out of the request if the frame is popped.
Definition: foreach.c:153
State of a foreach loop.
Definition: foreach.c:53
static unlang_foreach_t * unlang_group_to_foreach(unlang_group_t *g)
Cast a group structure to the foreach keyword extension.
Definition: foreach_priv.h:42
fr_dict_attr_t const * value
value variable in the foreach loop
Definition: foreach_priv.h:36
fr_dict_attr_t const * key
key variable for the foreach loop
Definition: foreach_priv.h:35
static xlat_action_t unlang_foreach_xlat_func(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
Implements the Foreach-Variable-X.
Definition: foreach.c:672
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
void unlang_register(int type, unlang_op_t *op)
Register an operation with the interpreter.
Definition: base.c:63
unlang_op_t unlang_ops[UNLANG_TYPE_MAX]
Different operations the interpreter can execute.
Definition: base.c:31
static char * stack[MAX_STACK]
Definition: radmin.c:158
@ FR_TYPE_VOID
User data.
Definition: merged_model.c:127
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
unsigned int uint32_t
Definition: merged_model.c:33
static uint8_t depth(fr_minmax_heap_index_t i)
Definition: minmax_heap.c:83
int fr_pair_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and append)
Definition: pair.c:1466
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition: pair.c:2319
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition: pair.c:1345
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
fr_pair_t * fr_pair_afrom_child_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Create a new valuepair.
Definition: pair.c:371
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition: pair.c:489
static bool done
Definition: radclient.c:80
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
#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_FAIL
Module failed, don't reply.
Definition: rcode.h:42
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition: rcode.h:48
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
void * request_data_reference(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request without removing it.
Definition: request_data.c:339
#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
Declarations for the "return" keyword, used to implement other keywords.
#define FR_SBUFF_IN(_start, _len_or_end)
#define tmpl_is_xlat(vpt)
Definition: tmpl.h:215
#define tmpl_is_attr(vpt)
Definition: tmpl.h:213
#define tmpl_xlat(_tmpl)
Definition: tmpl.h:941
int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt))
Copy pairs matching a tmpl_t in the current request_t.
Definition: tmpl_eval.c:798
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
ssize_t tmpl_dcursor_print(fr_sbuff_t *out, tmpl_dcursor_ctx_t const *cc)
Definition: tmpl_dcursor.c:781
void tmpl_dcursor_clear(tmpl_dcursor_ctx_t *cc)
Clear any temporary state allocations.
Definition: tmpl_dcursor.c:495
#define tmpl_dcursor_init(_err, _ctx, _cc, _cursor, _request, _vpt)
Definition: tmpl_dcursor.h:100
Maintains state between cursor calls.
Definition: tmpl_dcursor.h:62
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
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
#define UNLANG_NEXT_SIBLING
Definition: unlang_priv.h:93
void * state
Stack frame specialisations.
Definition: unlang_priv.h:296
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
Definition: unlang_priv.h:531
@ UNLANG_TYPE_BREAK
Break statement (within a UNLANG_TYPE_FOREACH).
Definition: unlang_priv.h:60
@ UNLANG_TYPE_FOREACH
Foreach section.
Definition: unlang_priv.h:59
unlang_t const * instruction
The unlang node we're evaluating.
Definition: unlang_priv.h:281
static void break_point_set(unlang_stack_frame_t *frame)
Definition: unlang_priv.h:347
rlm_rcode_t result
The result from executing the instruction.
Definition: unlang_priv.h:300
char const * name
Name of the operation.
Definition: unlang_priv.h:205
static bool is_stack_unwinding_to_break(unlang_stack_t *stack)
Definition: unlang_priv.h:380
static void repeatable_set(unlang_stack_frame_t *frame)
Definition: unlang_priv.h:345
static unlang_action_t unwind_to_break(unlang_stack_t *stack)
Definition: unlang_priv.h:363
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
Generic representation of a grouping.
Definition: unlang_priv.h:145
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
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
Definition: pair_inline.c:125
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition: pair.h:261
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
Definition: pair_inline.c:113
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
Definition: pair_inline.c:182
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.h:591
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition: types.h:433
#define fr_type_is_structural(_x)
Definition: types.h:371
#define fr_type_is_leaf(_x)
Definition: types.h:372
#define FR_TYPE_LEAF
Definition: types.h:297
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_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition: value.c:3740
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition: value.c:3681
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:3927
#define fr_value_box(_box, _var, _tainted)
Automagically fill in a box, determining the value type from the type of the C variable.
Definition: value.h:871
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition: value.h:632
static size_t char ** out
Definition: value.h:997
void const * inst
xlat instance data.
Definition: xlat_ctx.h:50
An xlat calling ctx.
Definition: xlat_ctx.h:49
void xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags)
Specify flags that alter the xlat's behaviour.
Definition: xlat_func.c:402
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:218
@ XLAT_FUNC_FLAG_INTERNAL
Definition: xlat_func.h:39
String expansion ("translation").
void * uctx
uctx to pass to instantiation functions.
Definition: xlat_priv.h:77