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: 681d4443f8e13f900c5e8d7efa124cd0c8cfbb70 $
19 *
20 * @file unlang/foreach.c
21 * @brief Unlang "foreach" keyword evaluation.
22 *
23 * @copyright 2006-2019 The FreeRADIUS server project
24 */
25RCSID("$Id: 681d4443f8e13f900c5e8d7efa124cd0c8cfbb70 $")
26
27#include <freeradius-devel/server/tmpl_dcursor.h>
28#include <freeradius-devel/unlang/xlat_func.h>
29
30#include "foreach_priv.h"
31#include "return_priv.h"
32#include "xlat_priv.h"
33
34#define BUFFER_SIZE (256)
35
36/** State of a foreach loop
37 *
38 */
39typedef struct {
40 request_t *request; //!< The current request.
41 fr_dcursor_t cursor; //!< Used to track our place in the list
42 fr_pair_t *key; //!< local variable which contains the key
43 fr_pair_t *value; //!< local variable which contains the value
44 tmpl_t const *vpt; //!< pointer to the vpt
45
46 uint32_t index; //!< for xlat results
47 char *buffer; //!< for key values
48
49 bool success; //!< for xlat expansion
50 fr_value_box_list_t list; //!< value box list for looping over xlats
51
52 tmpl_dcursor_ctx_t cc; //!< tmpl cursor state
53
54#ifndef NDEBUG
55 int indent; //!< for catching indentation issues
56#endif
58
59/*
60 * Brute-force things instead of doing it the "right" way.
61 *
62 * We would ideally like to have the local variable be a ref to the current vp from the cursor. However,
63 * that isn't (yet) supported. We do have #FR_TYPE_PAIR_CURSOR, but there is no way to save the cursor,
64 * or address it. See also xlat_expr.c for notes on using '$$' to refer to a cursor. Maybe we need a
65 * new magic "list", which is called "cursor", or "self"? That way we can also address parent cursors?
66 *
67 * In order to support that, we would have to update a lot of things:
68 *
69 * - the foreach code has not just create a local attribute, but mark up that attribute as it's really a cursor".
70 * - maybe we also need to put the cursor into its own stack frame? Or have it as a common field
71 * in every frame?
72 * - the tmpl code has to be updated so that when you reference a "cursor attribute", it finds the cursor,
73 * and edits the pair associated with the cursor
74 * - update tmpl_eval_pair(), because that's what's used in the xlat code. That gets us all
75 * references to the _source_ VP.
76 * - we also have to update the edit.c code, which calls tmpl_dcursor_init() to get pairs from
77 * a tmpl_t of type ATTR.
78 * - for LHS assignment, the edit code has to be updated: apply_edits_to_leaf() and apply_edits_to_list()
79 * which calls fr_edit_list_apply_pair_assignment() to do the actual work. But we could likely just
80 * check current->lhs.vp, and dereference that to get the underlying thing.
81 *
82 * What we ACTUALLY do instead is in the compiler when we call define_local_variable(), we clone the "da"
83 * hierarchy via fr_dict_attr_acopy_local(). That function which should go away when we add refs.
84 *
85 * Then this horrific function copies the pairs by number, which re-parents them to the correct
86 * destination da. It's brute-force and expensive, but it's easy. And for now, it's less work than
87 * re-doing substantial parts of the server core and utility libraries.
88 */
89static int unlang_foreach_pair_copy(fr_pair_t *to, fr_pair_t *from, fr_dict_attr_t const *from_parent)
90{
91 fr_assert(fr_type_is_structural(to->vp_type));
92 fr_assert(fr_type_is_structural(from->vp_type));
93
94 fr_pair_list_foreach(&from->vp_group, vp) {
95 fr_pair_t *child;
96
97 /*
98 * We only copy children of the parent TLV, but we can copy internal attributes, as they
99 * can exist anywhere.
100 */
101 if (vp->da->parent != from_parent) {
102 if (vp->da->flags.internal) {
103 child = fr_pair_copy(to, vp);
104 if (child) fr_pair_append(&to->vp_group, child);
105 }
106 continue;
107 }
108
109 child = fr_pair_afrom_child_num(to, to->da, vp->da->attr);
110 if (!child) continue;
111
112 fr_pair_append(&to->vp_group, child);
113
114 if (fr_type_is_leaf(child->vp_type)) {
115 if (fr_value_box_copy(child, &child->data, &vp->data) < 0) return -1;
116 continue;
117 }
118
120
121 if (unlang_foreach_pair_copy(child, vp, vp->da) < 0) return -1;
122 }
123
124 return 0;
125}
126
127/** Ensure request data is pulled out of the request if the frame is popped
128 *
129 */
131{
132 request_t *request = state->request;
133 fr_pair_t *vp;
134
135 fr_assert(state->value);
136
137 if (tmpl_is_xlat(state->vpt)) return 0;
138
139 tmpl_dcursor_clear(&state->cc);
140
141 /*
142 * Now that we're done, the leaf entries can be changed again.
143 */
144 vp = tmpl_dcursor_init(NULL, NULL, &state->cc, &state->cursor, request, state->vpt);
145 if (!vp) {
146 tmpl_dcursor_clear(&state->cc);
147 return 0;
148 }
149 do {
150 vp->vp_edit = false;
151 } while ((vp = fr_dcursor_next(&state->cursor)) != NULL);
152 tmpl_dcursor_clear(&state->cc);
153
154 return 0;
155}
156
158{
159 fr_value_box_t box;
160
161 if (!state->key) return 0;
162
163 fr_value_box_clear_value(&state->key->data);
164
165 fr_value_box(&box, state->index, false);
166
167 if (fr_value_box_cast(state->key, &state->key->data, state->key->vp_type, state->key->da, &box) < 0) {
168 RDEBUG("Failed casting 'foreach' key variable '%s' from %u", state->key->da->name, state->index);
169 return -1;
170 }
171
172 return 0;
173}
174
175
177{
178 unlang_frame_state_foreach_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
179 fr_value_box_t *box;
180
181next:
182 state->index++;
183
184 box = fr_dcursor_next(&state->cursor);
185 if (!box) {
186 *p_result = frame->result;
188 }
189
190 if (unlang_foreach_xlat_key_update(request, state) < 0) goto next;
191
192 fr_value_box_clear_value(&state->value->data);
193 if (fr_value_box_cast(state->value, &state->value->data, state->value->vp_type, state->value->da, box) < 0) {
194 RDEBUG("Failed casting 'foreach' iteration variable '%s' from %pV", state->value->da->name, box);
195 goto next;
196 }
197
198 repeatable_set(frame);
199
200 /*
201 * Push the child, and yield for a later return.
202 */
203 return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
204}
205
206
208{
209 unlang_frame_state_foreach_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
210 fr_value_box_t *box;
211
212 if (!state->success) {
213 RDEBUG("Failed expanding 'foreach' list");
214 *p_result = RLM_MODULE_FAIL;
216 }
217
218 box = fr_dcursor_init(&state->cursor, fr_value_box_list_dlist_head(&state->list));
219 if (!box) {
220 done:
221 *p_result = RLM_MODULE_NOOP;
223 }
224
225 fr_value_box_clear_value(&state->value->data);
226
227next:
228 if (fr_value_box_cast(state->value, &state->value->data, state->value->vp_type, state->value->da, box) < 0) {
229 RDEBUG("Failed casting 'foreach' iteration variable '%s' from %pV", state->value->da->name, box);
230 box = fr_dcursor_next(&state->cursor);
231 if (!box) goto done;
232
233 goto next;
234 }
235
237 repeatable_set(frame);
238
239 /*
240 * Push the child, and yield for a later return.
241 */
242 return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
243}
244
245
246/*
247 * Loop over an xlat expansion
248 */
251{
252 fr_value_box_list_init(&state->list);
253
254 if (unlang_xlat_push(state, &state->success, &state->list, request, tmpl_xlat(state->vpt), false) < 0) {
255 REDEBUG("Failed starting expansion of %s", state->vpt->name);
256 *p_result = RLM_MODULE_FAIL;
258 }
259
260 if (unlang_foreach_xlat_key_update(request, state) < 0) {
261 *p_result = RLM_MODULE_FAIL;
263 }
264
266 repeatable_set(frame);
267
269}
270
272{
273 if (!state->key) return;
274
275 switch (state->key->vp_type) {
276 case FR_TYPE_UINT32:
277 state->key->vp_uint32++;
278 break;
279
280 case FR_TYPE_STRING:
281 fr_value_box_clear_value(&state->key->data);
282 if (tmpl_dcursor_print(&FR_SBUFF_IN(state->buffer, BUFFER_SIZE), &state->cc) > 0) {
283 fr_value_box_strdup(state->key, &state->key->data, NULL, state->buffer, false);
284 }
285 break;
286
287 default:
288 fr_assert(0);
289 break;
290
291 }
292}
293
295{
296 unlang_frame_state_foreach_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
297 fr_pair_t *vp;
298
299 vp = fr_dcursor_current(&state->cursor);
300 fr_assert(vp != NULL);
301
302 /*
303 * If we modified the value, copy it back to the original pair. Note that the copy does NOT
304 * check the "immutable" flag. That flag is for the people using unlang, not for the
305 * interpreter.
306 */
307 if (fr_type_is_leaf(vp->vp_type)) {
308 if (vp->vp_type == state->value->vp_type) {
310 (void) fr_value_box_copy(vp, &vp->data, &state->value->data);
311 } else {
312 /*
313 * @todo - this shouldn't happen?
314 */
315 }
316 } else {
318
319 /*
320 * @todo - copy the pairs back?
321 */
322 }
323
324next:
325 vp = fr_dcursor_next(&state->cursor);
326 if (!vp) {
327 *p_result = frame->result;
328#ifndef NDEBUG
329 fr_assert(state->indent == request->log.indent.unlang);
330#endif
332 }
333
334 unlang_foreach_attr_key_update(request, state);
335
336 /*
337 * Copy the data.
338 */
339 if (vp->vp_type == FR_TYPE_GROUP) {
340 fr_assert(state->value->vp_type == FR_TYPE_GROUP);
341
342 fr_pair_list_free(&state->value->vp_group);
343
344 if (fr_pair_list_copy(state->value, &state->value->vp_group, &vp->vp_group) < 0) {
345 REDEBUG("Failed copying members of %s", state->value->da->name);
346 *p_result = RLM_MODULE_FAIL;
348 }
349
350 } else if (fr_type_is_structural(vp->vp_type)) {
351 if (state->value->vp_type != vp->vp_type) goto next;
352
353 fr_pair_list_free(&state->value->vp_group);
354
355 if (unlang_foreach_pair_copy(state->value, vp, vp->da) < 0) {
356 REDEBUG("Failed copying children of %s", state->value->da->name);
357 *p_result = RLM_MODULE_FAIL;
359 }
360
361 } else {
362 fr_value_box_clear_value(&state->value->data);
363 if (fr_value_box_cast(state->value, &state->value->data, state->value->vp_type, state->value->da, &vp->data) < 0) {
364 RDEBUG("Failed casting 'foreach' iteration variable '%s' from %pP", state->value->da->name, vp);
365 goto next;
366 }
367
368#ifndef NDEBUG
369 RDEBUG2("# looping with: %s = %pV", state->value->da->name, &vp->data);
370#endif
371 }
372
373 repeatable_set(frame);
374
375 /*
376 * Push the child, and yield for a later return.
377 */
378 return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
379}
380
381/*
382 * Loop over an attribute
383 */
386{
387 fr_pair_t *vp;
388
389 /*
390 * No matching attributes, we can't do anything.
391 */
392 vp = tmpl_dcursor_init(NULL, NULL, &state->cc, &state->cursor, request, state->vpt);
393 if (!vp) {
394 tmpl_dcursor_clear(&state->cc);
395 *p_result = RLM_MODULE_NOOP;
397 }
398
399 /*
400 * Before we loop over the variables, ensure that the user can't pull the rug out from
401 * under us.
402 */
403 do {
404 if (vp->vp_edit) {
405 REDEBUG("Cannot do nested 'foreach' loops over the same attribute %pP", vp);
406 fail:
407 tmpl_dcursor_clear(&state->cc);
408 *p_result = RLM_MODULE_FAIL;
410 }
411
412 vp->vp_edit = true;
413 } while ((vp = fr_dcursor_next(&state->cursor)) != NULL);
414 tmpl_dcursor_clear(&state->cc);
415
416 vp = tmpl_dcursor_init(NULL, NULL, &state->cc, &state->cursor, request, state->vpt);
417 fr_assert(vp != NULL);
418
419next:
420 /*
421 * Update the key with the current path. Attribute indexes start at zero.
422 */
423 if (state->key && (state->key->vp_type == FR_TYPE_STRING)) unlang_foreach_attr_key_update(request, state);
424
425 if (vp->vp_type == FR_TYPE_GROUP) {
426 fr_assert(state->value->vp_type == FR_TYPE_GROUP);
427
428 if (fr_pair_list_copy(state->value, &state->value->vp_group, &vp->vp_group) < 0) {
429 REDEBUG("Failed copying members of %s", state->value->da->name);
430 goto fail;
431 }
432
433 } else if (fr_type_is_structural(vp->vp_type)) {
434 if (state->value->vp_type != vp->vp_type) {
435 vp = fr_dcursor_next(&state->cursor);
436 if (vp) goto next;
437
438 *p_result = frame->result;
439 fr_assert(state->indent == request->log.indent.unlang);
441 }
442
443 if (unlang_foreach_pair_copy(state->value, vp, vp->da) < 0) {
444 REDEBUG("Failed copying children of %s", state->value->da->name);
445 goto fail;
446 }
447
448 } else {
449 fr_value_box_clear_value(&state->value->data);
450 while (vp && (fr_value_box_cast(state->value, &state->value->data, state->value->vp_type, state->value->da, &vp->data) < 0)) {
451 RDEBUG("Failed casting 'foreach' iteration variable '%s' from %pP", state->value->da->name, vp);
452 vp = fr_dcursor_next(&state->cursor);
453 }
454
455 /*
456 * Couldn't cast anything, the loop can't be run.
457 */
458 if (!vp) {
459 tmpl_dcursor_clear(&state->cc);
460 *p_result = RLM_MODULE_NOOP;
462 }
463 }
464
466
467 repeatable_set(frame);
468
469 /*
470 * Push the child, and go process it.
471 */
472 return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
473}
474
475
477{
481
482 MEM(frame->state = state = talloc_zero(request->stack, unlang_frame_state_foreach_t));
483 talloc_set_destructor(state, _free_unlang_frame_state_foreach);
484
485 state->request = request;
486#ifndef NDEBUG
487 state->indent = request->log.indent.unlang;
488#endif
489
490 /*
491 * Get the value.
492 */
493 fr_assert(gext->value);
494
495 state->vpt = gext->vpt;
496
497 fr_assert(fr_pair_find_by_da(&request->local_pairs, NULL, gext->value) == NULL);
498
499 /*
500 * Create the local variable and populate its value.
501 */
502 if (fr_pair_append_by_da(request->local_ctx, &state->value, &request->local_pairs, gext->value) < 0) {
503 REDEBUG("Failed creating %s", gext->value->name);
504 *p_result = RLM_MODULE_FAIL;
506 }
507 fr_assert(state->value != NULL);
508
509 if (gext->key) {
510 fr_assert(fr_pair_find_by_da(&request->local_pairs, NULL, gext->key) == NULL);
511
512 if (fr_pair_append_by_da(request->local_ctx, &state->key, &request->local_pairs, gext->key) < 0) {
513 REDEBUG("Failed creating %s", gext->key->name);
514 *p_result = RLM_MODULE_FAIL;
516 }
517 fr_assert(state->key != NULL);
518 }
519
520 if (tmpl_is_attr(gext->vpt)) {
521 MEM(state->buffer = talloc_array(state, char, BUFFER_SIZE));
522 return unlang_foreach_attr_init(p_result, request, frame, state);
523 }
524
525 fr_assert(tmpl_is_xlat(gext->vpt));
526
527 return unlang_foreach_xlat_init(p_result, request, frame, state);
528}
529
531{
533 unlang_stack_t *stack = request->stack;
534 unsigned int break_depth;
535
536 RDEBUG2("%s", unlang_ops[frame->instruction->type].name);
537
538 *p_result = frame->result;
539
540 /*
541 * Stop at the next break point, or if we hit
542 * the a top frame.
543 */
544 ua = unwind_to_op_flag(&break_depth, request->stack, UNLANG_OP_FLAG_BREAK_POINT);
545 repeatable_clear(&stack->frame[break_depth]);
546 return ua;
547}
548
550{
551 unlang_stack_t *stack = request->stack;
552
553 RDEBUG2("%s", unlang_ops[frame->instruction->type].name);
554
556}
557
559{
561 &(unlang_op_t){
562 .name = "foreach",
563 .interpret = unlang_foreach,
565 });
566
568 &(unlang_op_t){
569 .name = "break",
570 .interpret = unlang_break,
571 });
572
574 &(unlang_op_t){
575 .name = "continue",
576 .interpret = unlang_continue,
577 });
578}
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:485
#define UNUSED
Definition build.h:317
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:290
#define fr_dcursor_init(_cursor, _head)
Initialise a cursor.
Definition dcursor.h:736
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:339
#define MEM(x)
Definition debug.h:36
static int unlang_foreach_pair_copy(fr_pair_t *to, fr_pair_t *from, fr_dict_attr_t const *from_parent)
Definition foreach.c:89
uint32_t index
for xlat results
Definition foreach.c:46
static void unlang_foreach_attr_key_update(UNUSED request_t *request, unlang_frame_state_foreach_t *state)
Definition foreach.c:271
static unlang_action_t unlang_foreach_attr_next(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition foreach.c:294
char * buffer
for key values
Definition foreach.c:47
fr_dcursor_t cursor
Used to track our place in the list.
Definition foreach.c:41
tmpl_t const * vpt
pointer to the vpt
Definition foreach.c:44
static unlang_action_t unlang_continue(UNUSED rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition foreach.c:549
fr_pair_t * key
local variable which contains the key
Definition foreach.c:42
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:384
static unlang_action_t unlang_foreach_xlat_next(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition foreach.c:176
bool success
for xlat expansion
Definition foreach.c:49
fr_value_box_list_t list
value box list for looping over xlats
Definition foreach.c:50
#define BUFFER_SIZE
Definition foreach.c:34
fr_pair_t * value
local variable which contains the value
Definition foreach.c:43
static unlang_action_t unlang_foreach(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition foreach.c:476
static unlang_action_t unlang_break(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition foreach.c:530
tmpl_dcursor_ctx_t cc
tmpl cursor state
Definition foreach.c:52
int indent
for catching indentation issues
Definition foreach.c:55
request_t * request
The current request.
Definition foreach.c:40
static unlang_action_t unlang_foreach_xlat_expanded(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition foreach.c:207
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:249
void unlang_foreach_init(void)
Definition foreach.c:558
static int unlang_foreach_xlat_key_update(request_t *request, unlang_frame_state_foreach_t *state)
Definition foreach.c:157
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:130
State of a foreach loop.
Definition foreach.c:39
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
unlang_action_t unlang_interpret_push_children(UNUSED 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:239
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:159
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_GROUP
A grouping of other attributes.
unsigned int uint32_t
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:1472
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:2329
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:697
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:1351
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:493
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:375
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:81
#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
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:210
#define tmpl_is_attr(vpt)
Definition tmpl.h:208
#define tmpl_xlat(_tmpl)
Definition tmpl.h:930
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:283
static unlang_action_t unwind_to_op_flag(unsigned int *depth_p, unlang_stack_t *stack, unlang_op_flag_t flag)
Mark the entire stack as cancelled.
#define UNLANG_NEXT_SIBLING
Definition unlang_priv.h:98
static void repeatable_clear(unlang_stack_frame_t *frame)
void * state
Stack frame specialisations.
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
@ UNLANG_TYPE_CONTINUE
Break statement (within a UNLANG_TYPE_FOREACH).
Definition unlang_priv.h:62
@ UNLANG_TYPE_BREAK
Break statement (within a UNLANG_TYPE_FOREACH or UNLANG_TYPE_CASE).
Definition unlang_priv.h:61
@ UNLANG_TYPE_FOREACH
Foreach section.
Definition unlang_priv.h:60
unlang_t const * instruction
The unlang node we're evaluating.
rlm_rcode_t result
The result from executing the instruction.
char const * name
Name of the operation.
@ UNLANG_OP_FLAG_CONTINUE_POINT
Continue point.
@ UNLANG_OP_FLAG_DEBUG_BRACES
Print debug braces.
@ UNLANG_OP_FLAG_BREAK_POINT
Break point.
static void repeatable_set(unlang_stack_frame_t *frame)
unlang_process_t process
function to call for interpreting this stack frame
unlang_type_t type
The specialisation of this node.
Generic representation of a grouping.
An unlang operation.
Our interpreter stack, as distinct from the C stack.
An unlang stack associated with a request.
#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.
#define fr_type_is_structural(_x)
Definition types.h:388
#define fr_type_is_leaf(_x)
Definition types.h:389
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:3574
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:3962
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:3899
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:4158
#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:894
String expansion ("translation").