/** Copy VP(s) from the specified request. * * @param ctx to alloc new VALUE_PAIRs in. * @param out where to write the pointer to the copied VP. * Will be NULL if the attribute couldn't be resolved. * @param request current request. * @param name attribute name including qualifiers. * @return -4 if either the attribute or qualifier were invalid, and the same error codes as tmpl_find_vp for other * error conditions. */ int radius_copy_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, char const *name) { value_pair_tmpl_t vpt; *out = NULL; if (tmpl_from_attr_str(&vpt, name, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) { return -4; } return tmpl_copy_vps(ctx, out, request, &vpt); }
static unlang_action_t unlang_foreach(REQUEST *request, rlm_rcode_t *presult, int *priority) { VALUE_PAIR *vp; unlang_stack_t *stack = request->stack; unlang_stack_frame_t *frame = &stack->frame[stack->depth]; unlang_t *instruction = frame->instruction; unlang_frame_state_foreach_t *foreach = NULL; unlang_group_t *g; g = unlang_generic_to_group(instruction); if (!frame->repeat) { int i, foreach_depth = -1; VALUE_PAIR *vps; if (stack->depth >= UNLANG_STACK_MAX) { ERROR("Internal sanity check failed: module stack is too deep"); fr_exit(EXIT_FAILURE); } /* * Figure out how deep we are in nesting by looking at request_data * stored previously. * * FIXME: figure this out by walking up the modcall stack instead. */ for (i = 0; i < 8; i++) { if (!request_data_reference(request, (void *)xlat_fmt_get_vp, i)) { foreach_depth = i; break; } } if (foreach_depth < 0) { REDEBUG("foreach Nesting too deep!"); *presult = RLM_MODULE_FAIL; *priority = 0; return UNLANG_ACTION_CALCULATE_RESULT; } /* * Copy the VPs from the original request, this ensures deterministic * behaviour if someone decides to add or remove VPs in the set we're * iterating over. */ if (tmpl_copy_vps(stack, &vps, request, g->vpt) < 0) { /* nothing to loop over */ *presult = RLM_MODULE_NOOP; *priority = instruction->actions[RLM_MODULE_NOOP]; return UNLANG_ACTION_CALCULATE_RESULT; } MEM(frame->state = foreach = talloc_zero(stack, unlang_frame_state_foreach_t)); rad_assert(vps != NULL); foreach->depth = foreach_depth; foreach->vps = vps; fr_cursor_talloc_init(&foreach->cursor, &foreach->vps, VALUE_PAIR); #ifndef NDEBUG foreach->indent = request->log.unlang_indent; #endif vp = fr_cursor_head(&foreach->cursor); } else { foreach = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t); vp = fr_cursor_next(&foreach->cursor); /* * We've been asked to unwind to the * enclosing "foreach". We're here, so * we can stop unwinding. */ if (frame->unwind == UNLANG_TYPE_BREAK) { frame->unwind = UNLANG_TYPE_NULL; vp = NULL; } /* * Unwind all the way. */ if (frame->unwind == UNLANG_TYPE_RETURN) { vp = NULL; } if (!vp) { /* * Free the copied vps and the request data * If we don't remove the request data, something could call * the xlat outside of a foreach loop and trigger a segv. */ fr_pair_list_free(&foreach->vps); request_data_get(request, (void *)xlat_fmt_get_vp, foreach->depth); *presult = frame->result; if (*presult != RLM_MODULE_UNKNOWN) *priority = instruction->actions[*presult]; #ifndef NDEBUG rad_assert(foreach->indent == request->log.unlang_indent); #endif return UNLANG_ACTION_CALCULATE_RESULT; } } #ifndef NDEBUG RDEBUG2(""); RDEBUG2("# looping with: Foreach-Variable-%d = %pV", foreach->depth, &vp->data); #endif rad_assert(vp); /* * Add the vp to the request, so that * xlat.c, xlat_foreach() can find it. */ foreach->variable = vp; request_data_add(request, (void *)xlat_fmt_get_vp, foreach->depth, &foreach->variable, false, false, false); /* * Push the child, and yield for a later return. */ unlang_push(stack, g->children, frame->result, UNLANG_NEXT_SIBLING, UNLANG_SUB_FRAME); frame->repeat = true; return UNLANG_ACTION_PUSHED_CHILD; }