The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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 */
25RCSID("$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
35static 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
46static 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 */
53typedef 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 */
108static 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
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
247next:
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
293next:
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
373next:
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
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) {
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);
690 return XLAT_ACTION_DONE;
691}
692
693void 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:483
#define UNUSED
Definition build.h:315
#define NUM_ELEMENTS(_t)
Definition build.h:337
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:288
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
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_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:337
#define MEM(x)
Definition debug.h:36
static fr_slen_t in
Definition dict.h:824
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.
fr_dict_attr_t const * value
value variable in the foreach loop
fr_dict_attr_t const * key
key variable for the foreach loop
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.
@ FR_TYPE_GROUP
A grouping of other attributes.
unsigned int uint32_t
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_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:489
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
#define fr_assert(_expr)
Definition rad_assert.h:38
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_reference(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request without removing it.
void * request_data_get(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request.
#define request_data_add(_request, _unique_ptr, _unique_int, _opaque, _free_on_replace, _free_on_parent, _persist)
Add opaque data to a request_t.
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
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)
void tmpl_dcursor_clear(tmpl_dcursor_ctx_t *cc)
Clear any temporary state allocations.
#define tmpl_dcursor_init(_err, _ctx, _cc, _cursor, _request, _vpt)
Maintains state between cursor calls.
int unlang_xlat_push(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
Definition xlat.c:286
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
#define UNLANG_NEXT_SIBLING
Definition unlang_priv.h:93
void * state
Stack frame specialisations.
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
@ 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.
static void break_point_set(unlang_stack_frame_t *frame)
rlm_rcode_t result
The result from executing the instruction.
char const * name
Name of the operation.
static bool is_stack_unwinding_to_break(unlang_stack_t *stack)
static void repeatable_set(unlang_stack_frame_t *frame)
static unlang_action_t unwind_to_break(unlang_stack_t *stack)
unlang_process_t process
function to call for interpreting this stack frame
unlang_type_t type
The specialisation of this node.
Generic representation of a grouping.
An unlang operation.
A node in a graph of unlang_op_t (s) that we execute.
Our interpreter stack, as distinct from the C stack.
An unlang stack associated with a request.
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
#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.
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.
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition pair.h:591
#define fr_type_is_structural(_x)
Definition types.h:371
#define fr_type_is_leaf(_x)
Definition types.h:372
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_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