attr_packet_type) < 0) return UNLANG_ACTION_FAIL;
vp->vp_uint32 = FR_RADIUS_CODE_ACCESS_REQUEST;
- if (unlang_function_push(/* transparent */ unlang_interpret_result(request),
- request,
- NULL,
- eap_virtual_server_resume,
- NULL, 0,
- UNLANG_SUB_FRAME,
- eap_session) < 0) return UNLANG_ACTION_FAIL;
+ if (unlang_function_push_with_result(/* transparent */ unlang_interpret_result(request),
+ request,
+ NULL,
+ eap_virtual_server_resume,
+ NULL, 0,
+ UNLANG_SUB_FRAME,
+ eap_session) < 0) return UNLANG_ACTION_FAIL;
if (unlang_call_push(NULL, request, server_cs, UNLANG_SUB_FRAME) < 0) return UNLANG_ACTION_FAIL;
* - eap_tls_session->state = EAP_TLS_ESTABLISHED if the handshake
* completed successfully, and there's no more data to send.
*/
-static unlang_action_t eap_tls_handshake_resume(UNUSED unlang_result_t *p_result,
- request_t *request, void *uctx)
+static unlang_action_t eap_tls_handshake_resume(request_t *request, void *uctx)
{
eap_session_t *eap_session = talloc_get_type_abort(uctx, eap_session_t);
eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
/*
* Will run after the handshake round completes
*/
- if (unlang_function_push(/* discard, sets eap_tls_session->state */ NULL,
- request,
+ if (unlang_function_push(request,
NULL,
eap_tls_handshake_resume,
- NULL, 0, UNLANG_SUB_FRAME, eap_session) < 0) return UNLANG_ACTION_FAIL;
+ NULL,
+ 0, UNLANG_SUB_FRAME,
+ eap_session) < 0) return UNLANG_ACTION_FAIL;
if (fr_tls_session_async_handshake_push(request, tls_session) < 0) return UNLANG_ACTION_FAIL;
*
* @note This function sets no rcode, the result of query is available in query->ret.
*/
-static unlang_action_t ldap_trunk_query_results(UNUSED unlang_result_t *p_result, request_t *request, void *uctx)
+static unlang_action_t ldap_trunk_query_results(request_t *request, void *uctx)
{
fr_ldap_query_t *query = talloc_get_type_abort(uctx, fr_ldap_query_t);
return UNLANG_ACTION_FAIL;
}
- action = unlang_function_push(/* discard, result is written to query->ret */NULL,
- request,
+ action = unlang_function_push(request,
NULL,
ldap_trunk_query_results,
ldap_trunk_query_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME, query);
+ UNLANG_SUB_FRAME,
+ query);
if (action == UNLANG_ACTION_FAIL) goto error;
return UNLANG_ACTION_FAIL;
}
- action = unlang_function_push(/* discard, result is written to query->ret */ NULL,
- request,
+ action = unlang_function_push(request,
NULL,
ldap_trunk_query_results,
ldap_trunk_query_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME, query);
+ UNLANG_SUB_FRAME,
+ query);
if (action == UNLANG_ACTION_FAIL) goto error;
return UNLANG_ACTION_FAIL;
}
- action = unlang_function_push(/* discard, result is written to query->ret */ NULL,
- request,
+ action = unlang_function_push(request,
NULL,
ldap_trunk_query_results,
ldap_trunk_query_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME, query);
+ UNLANG_SUB_FRAME,
+ query);
if (action == UNLANG_ACTION_FAIL) goto error;
RETURN_UNLANG_FAIL;
}
- return unlang_function_push(p_result,
- request,
- ldap_async_auth_bind_start,
- ldap_async_auth_bind_results,
- ldap_async_auth_bind_cancel,
- ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME,
- bind_auth_ctx);
+ return unlang_function_push_with_result(p_result,
+ request,
+ ldap_async_auth_bind_start,
+ ldap_async_auth_bind_results,
+ ldap_async_auth_bind_cancel,
+ ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME,
+ bind_auth_ctx);
}
RETURN_UNLANG_FAIL;
}
- return unlang_function_push(p_result,
- request,
- ldap_edir_get_password_start,
- ldap_edir_get_password_resume,
- ldap_edir_get_password_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME, edir_ctx);
+ return unlang_function_push_with_result(p_result,
+ request,
+ ldap_edir_get_password_start,
+ ldap_edir_get_password_resume,
+ ldap_edir_get_password_cancel, ~FR_SIGNAL_CANCEL,
+ UNLANG_SUB_FRAME, edir_ctx);
}
char const *fr_ldap_edir_errstr(int code)
RETURN_UNLANG_FAIL;
}
- return unlang_function_push(p_result,
- request,
- ldap_async_sasl_bind_auth_start,
- ldap_async_sasl_bind_auth_results,
- ldap_async_sasl_bind_auth_cancel,
- ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME,
- bind_auth_ctx);
+ return unlang_function_push_with_result(p_result,
+ request,
+ ldap_async_sasl_bind_auth_start,
+ ldap_async_sasl_bind_auth_results,
+ ldap_async_sasl_bind_auth_cancel,
+ ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME,
+ bind_auth_ctx);
}
fr_time_delta_t timeout; //!< How long the trigger has to run.
} fr_trigger_t;
-static unlang_action_t trigger_done(unlang_result_t *p_result,
- request_t *request, void *rctx)
+static unlang_action_t trigger_done(request_t *request, void *rctx)
{
fr_trigger_t *trigger = talloc_get_type_abort(rctx, fr_trigger_t);
if (trigger->exec.status == 0) {
RDEBUG2("Trigger \"%s\" done", trigger->command);
- RETURN_UNLANG_OK;
+ return UNLANG_ACTION_CALCULATE_RESULT;
}
RERROR("Trigger \"%s\" failed", trigger->command);
- RETURN_UNLANG_FAIL;
+ return UNLANG_ACTION_CALCULATE_RESULT;
}
-static unlang_action_t trigger_resume(UNUSED unlang_result_t *p_result,
- request_t *request, void *rctx)
+static unlang_action_t trigger_resume(request_t *request, void *rctx)
{
fr_trigger_t *trigger = talloc_get_type_abort(rctx, fr_trigger_t);
return UNLANG_ACTION_YIELD;
}
-static unlang_action_t trigger_run(unlang_result_t *p_result, request_t *request, void *uctx)
+static unlang_action_t trigger_run(request_t *request, void *uctx)
{
fr_trigger_t *trigger = talloc_get_type_abort(uctx, fr_trigger_t);
if (unlang_xlat_push(request, NULL, &trigger->args, request,
trigger->xlat, UNLANG_SUB_FRAME) < 0) {
- RETURN_UNLANG_FAIL;
+ return UNLANG_ACTION_CALCULATE_RESULT;
}
return UNLANG_ACTION_PUSHED_CHILD;
return -1;
}
- if (unlang_function_push(/* discarded */ NULL,
- request,
- trigger_run, trigger_resume,
+ if (unlang_function_push(request,
+ trigger_run,
+ trigger_resume,
NULL, 0,
- UNLANG_TOP_FRAME, trigger) < 0) goto error;
+ UNLANG_TOP_FRAME,
+ trigger) < 0) goto error;
if (!intp) {
/*
if (unlang_interpret_stack_depth(request) > 1) {
unlang_action_t action;
- action = unlang_function_push(unlang_interpret_result(request), /* transparent */
- request,
- NULL, /* don't call it immediately */
- server_remove_log_destination, /* but when we pop the frame */
- server_signal_remove_log_destination, ~(FR_SIGNAL_CANCEL),
- top_frame, vs);
+ action = unlang_function_push_with_result(unlang_interpret_result(request), /* transparent */
+ request,
+ NULL, /* don't call it immediately */
+ server_remove_log_destination, /* but when we pop the frame */
+ server_signal_remove_log_destination, ~(FR_SIGNAL_CANCEL),
+ top_frame,
+ vs);
if (action != UNLANG_ACTION_PUSHED_CHILD) return action;
top_frame = UNLANG_SUB_FRAME; /* switch to SUB_FRAME after the first instruction */
/*
* tls/virtual_server.c
*/
-unlang_action_t fr_tls_call_push(request_t *child, unlang_function_t resume,
+unlang_action_t fr_tls_call_push(request_t *child, unlang_function_no_result_t resume,
fr_tls_conf_t *conf, fr_tls_session_t *tls_session, bool cache_required);
#ifdef __cplusplus
/** Process the result of `load session { ... }`
*/
-static unlang_action_t tls_cache_load_result(UNUSED unlang_result_t *p_result, request_t *request, void *uctx)
+static unlang_action_t tls_cache_load_result(request_t *request, void *uctx)
{
fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
fr_tls_cache_t *tls_cache = tls_session->cache;
/** Process the result of `store session { ... }`
*/
-static unlang_action_t tls_cache_store_result(UNUSED unlang_result_t *p_result,
- request_t *request, void *uctx)
+static unlang_action_t tls_cache_store_result(request_t *request, void *uctx)
{
fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
fr_tls_cache_t *tls_cache = tls_session->cache;
/** Process the result of `clear session { ... }`
*/
-static unlang_action_t tls_cache_clear_result(UNUSED unlang_result_t *p_result,
- request_t *request, void *uctx)
+static unlang_action_t tls_cache_clear_result(request_t *request, void *uctx)
{
fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
fr_tls_cache_t *tls_cache = tls_session->cache;
*
* As this is just a logging session, it's result doesn't affect the parent.
*/
-static unlang_action_t tls_establish_session_result(UNUSED unlang_result_t *p_result,
- UNUSED request_t *request, UNUSED void *uctx)
+static unlang_action_t tls_establish_session_result(UNUSED request_t *request, UNUSED void *uctx)
{
return UNLANG_ACTION_CALCULATE_RESULT;
}
/** Finish off a handshake round, possibly adding attributes to the request
*
*/
-static unlang_action_t tls_session_async_handshake_done_round(UNUSED unlang_result_t *p_result,
- request_t *request, void *uctx)
+static unlang_action_t tls_session_async_handshake_done_round(request_t *request, void *uctx)
{
fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
int ret;
*
* This function may be called multiple times, once after every asynchronous request.
*
- * @param[in,out] p_result UNUSED.
* @param[in] request The current request.
* @param[in] uctx #fr_tls_session_t to continue.
* @return
* - UNLANG_ACTION_CALCULATE_RESULT - We're done with this round.
* - UNLANG_ACTION_PUSHED_CHILD - Need to perform more asynchronous actions.
*/
-static unlang_action_t tls_session_async_handshake_cont(unlang_result_t *p_result,
- request_t *request, void *uctx)
+static unlang_action_t tls_session_async_handshake_cont(request_t *request, void *uctx)
{
fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
int err;
*/
if (fr_tls_log_io_error(request,
err, "SSL_read (%s)", __FUNCTION__) < 0) goto error;
- return tls_session_async_handshake_done_round(p_result, request, uctx);
+ return tls_session_async_handshake_done_round(request, uctx);
}
}
* #tls_session_async_handshake_read is split out because we may need to call
* it multiple times, once after every async action.
*
- * @param[in,out] p_result UNUSED.
* @param[in] request The current request.
* @param[in] uctx #fr_tls_session_t to continue.
* @return
* - UNLANG_ACTION_CALCULATE_RESULT - We're done with this round.
* - UNLANG_ACTION_PUSHED_CHILD - Need to perform more asynchronous actions.
*/
-static unlang_action_t tls_session_async_handshake(unlang_result_t *p_result,
- request_t *request, void *uctx)
+static unlang_action_t tls_session_async_handshake(request_t *request, void *uctx)
{
fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
int ret;
record_init(&tls_session->dirty_in);
}
- return tls_session_async_handshake_cont(p_result, request, uctx); /* Must unbind request, possibly asynchronously */
+ return tls_session_async_handshake_cont(request, uctx); /* Must unbind request, possibly asynchronously */
}
/** Push a handshake call onto the stack
*/
unlang_action_t fr_tls_session_async_handshake_push(request_t *request, fr_tls_session_t *tls_session)
{
- return unlang_function_push(/* discard, result is written to tls_session->result */ NULL,
- request,
+ return unlang_function_push(request,
tls_session_async_handshake,
NULL,
tls_session_async_handshake_signal,
return tls_session;
}
-static unlang_action_t tls_new_session_result(UNUSED unlang_result_t *p_result, request_t *request, UNUSED void *uctx)
+static unlang_action_t tls_new_session_result(request_t *request, UNUSED void *uctx)
{
request_t *parent = request->parent;
if (unlang_subrequest_child_push(NULL, child, child->parent, true, UNLANG_SUB_FRAME) < 0) {
return UNLANG_ACTION_FAIL;
}
- if (unlang_function_push(/* discard, eap_tls_session->state holds result */ NULL,
- child,
+ if (unlang_function_push(child,
NULL,
tls_new_session_result,
NULL, 0,
/** Process the result of `verify certificate { ... }`
*
*/
-static unlang_action_t tls_verify_client_cert_result(UNUSED unlang_result_t *p_result,
- request_t *request, void *uctx)
+static unlang_action_t tls_verify_client_cert_result(request_t *request, void *uctx)
{
fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
fr_pair_t *vp, *next;
* - 0 on success.
* - -1 on failure.
*/
-unlang_action_t fr_tls_call_push(request_t *child, unlang_function_t resume,
+unlang_action_t fr_tls_call_push(request_t *child, unlang_function_no_result_t resume,
fr_tls_conf_t *conf, fr_tls_session_t *tls_session,
#ifdef NDEBUG
UNUSED
* Setup a function to execute after the
* subrequest completes.
*/
- if (unlang_function_push(/* discard, the failure of these callbacks does not affect the handshake */NULL,
- child,
+ if (unlang_function_push(child,
NULL,
resume,
NULL,
void **data; //!< Final destination structure for value boxes.
} call_env_rctx_t;
-static unlang_action_t call_env_expand_repeat(unlang_result_t *p_result, request_t *request, void *uctx);
+static unlang_action_t call_env_expand_repeat(request_t *request, void *uctx);
/** Start the expansion of a call environment tmpl.
*
*/
-static unlang_action_t call_env_expand_start(UNUSED unlang_result_t *p_result, request_t *request, void *uctx)
+static unlang_action_t call_env_expand_start(request_t *request, void *uctx)
{
call_env_rctx_t *call_env_rctx = talloc_get_type_abort(uctx, call_env_rctx_t);
TALLOC_CTX *ctx;
*
* If there are more tmpls to expand, push the next expansion.
*/
-static unlang_action_t call_env_expand_repeat(UNUSED unlang_result_t *p_result,
- request_t *request, void *uctx)
+static unlang_action_t call_env_expand_repeat(request_t *request, void *uctx)
{
void *out = NULL, *tmpl_out = NULL;
call_env_rctx_t *call_env_rctx = talloc_get_type_abort(uctx, call_env_rctx_t);
return UNLANG_ACTION_CALCULATE_RESULT;
}
- return unlang_function_push(/* discard, result is provided in env_result */ NULL,
- request,
+ return unlang_function_push(request,
call_env_expand_start,
call_env_expand_repeat,
- NULL, 0,
- UNLANG_SUB_FRAME,
+ NULL,
+ 0, UNLANG_SUB_FRAME,
call_env_rctx);
}
call_env_rctx->call_env = call_env;
fr_value_box_list_init(&call_env_rctx->tmpl_expanded);
- return unlang_function_push(/* discard, result is provided in env_result */NULL,
- request,
+ return unlang_function_push(request,
call_env_expand_start,
call_env_expand_repeat,
NULL,
*/
RCSID("$Id$")
+#include "action.h"
#include "unlang_priv.h"
#include "function.h"
+#define FUNC(_state) *((void **)&state->func)
+#define REPEAT(_state) *((void **)&state->repeat)
+
/*
* Some functions differ mainly in their parsing
*/
typedef struct {
- unlang_function_t func; //!< To call when going down the stack.
+ union {
+ unlang_function_no_result_t nres; //!< To call when going down the stack.
+ unlang_function_with_result_t wres; //!< To call when going down the stack.
+ } func;
char const *func_name; //!< Debug name for the function.
- unlang_function_t repeat; //!< To call when going back up the stack.
+
+ union {
+ unlang_function_no_result_t nres; //!< To call when going back up the stack.
+ unlang_function_with_result_t wres; //!< To call when going back up the stack.
+ } repeat;
+ unlang_function_type_t type; //!< Record whether we need to call the
char const *repeat_name; //!< Debug name for the repeat function.
+
unlang_function_signal_t signal; //!< Signal function to call.
fr_signal_t sigmask; //!< Signals to block.
char const *signal_name; //!< Debug name for the signal function.
state->signal(request, action, state->uctx);
}
-static unlang_action_t unlang_function_call_repeat(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
+
+/*
+ * Don't let the callback mess with the current
+ * module permanently.
+ */
+#define STORE_CALLER \
+ char const *caller; \
+ caller = request->module; \
+ request->module = NULL
+
+#define RESTORE_CALLER \
+ request->module = caller;
+
+/** Call a generic function that produces a result
+ *
+ * @param[out] p_result The frame result.
+ * @param[in] request The current request.
+ * @param[in] frame The current frame.
+ */
+static unlang_action_t call_with_result(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
unlang_action_t ua;
unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
- char const *caller;
-
- /*
- * Don't let the callback mess with the current
- * module permanently.
- */
- caller = request->module;
- request->module = NULL;
- RDEBUG4("Calling repeat function %p (%s)", state->repeat, state->repeat_name);
- /*
- * FIXME: The full scratch rcode/priority should be passed in
- * and then passed to this function.
- */
- ua = state->repeat(p_result, request, state->uctx);
- request->module = caller;
+ STORE_CALLER;
+
+again:
+ RDEBUG4("Calling function %p (%s)", state->func.wres, state->func_name);
+ ua = state->func.wres(p_result, request, state->uctx);
+ state->func.wres = state->repeat.wres;
+ state->repeat.wres = NULL;
+ state->repeat_name = NULL;
+ if (state->func.wres) {
+ switch (ua) {
+ case UNLANG_ACTION_STOP_PROCESSING:
+ break;
+
+ case UNLANG_ACTION_CALCULATE_RESULT:
+ goto again;
+
+ default:
+ frame_repeat(frame, call_with_result);
+ }
+ }
+ RESTORE_CALLER;
return ua;
}
-/** Call a generic function
+/** Call a generic function that produces no result
+ *
+ * These functions report results by modifying the rctx passed into the function.
+ * They are not allowed to return UNLANG_ACTION_FAIL. In non-debug builds this
+ * is rewritten to UNLANG_ACTION_CALCULATE_RESULT, and in debug builds it triggers
+ * an assert.
*
* @param[out] p_result The frame result.
* @param[in] request The current request.
* @param[in] frame The current frame.
*/
-static unlang_action_t unlang_function_call(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
+static unlang_action_t call_no_result(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
unlang_action_t ua;
unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
- char const *caller;
-
- /*
- * Don't let the callback mess with the current
- * module permanently.
- */
- caller = request->module;
- request->module = NULL;
-
- RDEBUG4("Calling function %p (%s)", state->func, state->func_name);
- ua = state->func(p_result, request, state->uctx);
- switch (ua) {
- case UNLANG_ACTION_STOP_PROCESSING:
- break;
-
- /*
- * Similar functionality to the modcall code.
- * If we have a repeat function set and the
- * initial function is done, call the repeat
- * function using the C stack.
- */
- case UNLANG_ACTION_CALCULATE_RESULT:
- if (state->repeat) unlang_function_call_repeat(p_result, request, frame);
- break;
- /*
- * Function pushed more children or yielded
- * setup our repeat function for when we
- * eventually start heading back up the stack.
- */
- default:
- if (state->repeat) frame_repeat(frame, unlang_function_call_repeat);
+ STORE_CALLER;
+
+again:
+ RDEBUG4("Calling function %p (%s)", state->func.nres, state->func_name);
+ ua = state->func.nres(request, state->uctx);
+ state->func.nres = state->repeat.nres;
+ state->func_name = state->repeat_name;
+ state->repeat.nres = NULL;
+ state->repeat_name = NULL;
+ if (state->func.nres) {
+ switch (ua) {
+ case UNLANG_ACTION_STOP_PROCESSING:
+ break;
+
+ case UNLANG_ACTION_CALCULATE_RESULT:
+ goto again;
+
+ default:
+ frame_repeat(frame, call_no_result);
+ }
}
- request->module = caller;
+ if (ua == UNLANG_ACTION_FAIL) {
+ fr_assert_msg(0, "Function %s (%p) is not allowed to indicate failure via UNLANG_ACTION_FAIL",
+ state->func_name, state->func.nres);
+ ua = UNLANG_ACTION_CALCULATE_RESULT;
+ }
+ RESTORE_CALLER;
return ua;
}
}
state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
- state->repeat = NULL;
+ REPEAT(state) = NULL;
state->signal = NULL;
repeatable_clear(frame);
* @param[in] request The current request.
* @param[in] repeat the repeat function to set.
* @param[in] repeat_name Name of the repeat function call (for debugging).
+ * @param[in] type Type of repeat function (with or without result).
* @return
* - 0 on success.
* - -1 on failure.
*/
-int _unlang_function_repeat_set(request_t *request, unlang_function_t repeat, char const *repeat_name)
+int _unlang_function_repeat_set(request_t *request, void *repeat, char const *repeat_name, unlang_function_type_t type)
{
unlang_stack_t *stack = request->stack;
unlang_stack_frame_t *frame = &stack->frame[stack->depth];
state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
+ if (unlikely(state->type != type)) {
+ fr_assert_msg(0, "Function type mismatch \"%s\"", repeat_name);
+ return -1;
+ }
+
/*
* If we're inside unlang_function_call,
* it'll pickup state->repeat and do the right thing
* once the current function returns.
*/
- state->repeat = repeat;
+ REPEAT(state) = repeat;
state->repeat_name = repeat_name;
repeatable_set(frame);
return 0;
}
-/** Push a generic function onto the unlang stack
+static inline CC_HINT(always_inline)
+unlang_action_t unlang_function_push_common(unlang_result_t *p_result,
+ request_t *request,
+ void *func,
+ char const *func_name,
+ void *repeat,
+ char const *repeat_name,
+ unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
+ unlang_function_type_t type,
+ bool top_frame,
+ void *uctx)
+{
+ unlang_stack_t *stack = request->stack;
+ unlang_stack_frame_t *frame;
+ unlang_frame_state_func_t *state;
+
+ /*
+ * Push module's function
+ */
+ if (unlang_interpret_push(p_result, request, &function_instruction,
+ FRAME_CONF(RLM_MODULE_NOOP, top_frame), UNLANG_NEXT_STOP) < 0) {
+ RETURN_UNLANG_FAIL;
+ }
+
+ frame = &stack->frame[stack->depth];
+
+ /*
+ * Initialize state
+ */
+ state = frame->state;
+ state->signal = signal;
+ state->sigmask = sigmask;
+ state->signal_name = signal_name;
+ state->type = type;
+ state->uctx = uctx;
+
+ /*
+ * Just skip to the repeat state directly
+ */
+ if (!func && repeat) {
+ FUNC(state) = repeat;
+ state->func_name = repeat_name;
+ repeatable_set(frame); /* execute on the way back up */
+ /*
+ * If we have both a function and a repeat,
+ * then record them both, and execute
+ * 'func' first. This will set the repeat
+ * function to call 'repeat' on the way
+ * back up the stack.
+ */
+ } else {
+ FUNC(state) = func;
+ state->func_name = func_name;
+ REPEAT(state) = repeat;
+ state->repeat_name = repeat_name;
+ }
+
+ return UNLANG_ACTION_PUSHED_CHILD;
+}
+
+/** Push a generic function onto the unlang stack with a result
*
* @private
*
* - UNLANG_ACTION_PUSHED_CHILD on success.
* - UNLANG_ACTION_FAIL on failure.
*/
-unlang_action_t _unlang_function_push(unlang_result_t *p_result,
- request_t *request,
- unlang_function_t func, char const *func_name,
- unlang_function_t repeat, char const *repeat_name,
- unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
- bool top_frame, void *uctx)
+unlang_action_t _unlang_function_push_with_result(unlang_result_t *p_result,
+ request_t *request,
+ unlang_function_with_result_t func, char const *func_name,
+ unlang_function_with_result_t repeat, char const *repeat_name,
+ unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
+ bool top_frame, void *uctx)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame;
- unlang_frame_state_func_t *state;
+ unlang_action_t ua;
+ unlang_stack_frame_t *frame;
- /*
- * Push module's function
- */
- if (unlang_interpret_push(p_result, request, &function_instruction,
- FRAME_CONF(RLM_MODULE_NOOP, top_frame), UNLANG_NEXT_STOP) < 0) {
- RETURN_UNLANG_FAIL;
- }
+ ua = unlang_function_push_common(p_result,
+ request,
+ func, func_name,
+ repeat, repeat_name,
+ signal, sigmask, signal_name,
+ UNLANG_FUNCTION_TYPE_WITH_RESULT, top_frame, uctx);
- frame = &stack->frame[stack->depth];
+ if (unlikely(ua == UNLANG_ACTION_FAIL)) return UNLANG_ACTION_FAIL;
- /*
- * Tell the interpreter to call unlang_function_call
- * again when going back up the stack.
- */
- if (repeat) repeatable_set(frame);
+ frame = frame_current(request);
+ frame->process = call_with_result;
- /*
- * Initialize state
- */
- state = frame->state;
- state->func = func;
- state->func_name = func_name;
- state->repeat = repeat;
- state->repeat_name = repeat_name;
- state->signal = signal;
- state->sigmask = sigmask;
- state->signal_name = signal_name;
- state->uctx = uctx;
+ return ua;
+}
- /*
- * Just skip to the repeat state directly
- */
- if (!func && repeat) frame->process = unlang_function_call_repeat;
+/** Push a generic function onto the unlang stack
+ *
+ * @private
+ *
+ * These can be pushed by any other type of unlang op to allow a submodule or function
+ * deeper in the C call stack to establish a new resumption point.
+ *
+ * @param[in] request The current request.
+ * @param[in] func to call going up the stack.
+ * @param[in] func_name Name of the function call (for debugging).
+ * @param[in] repeat function to call going back down the stack (may be NULL).
+ * This may be the same as func.
+ * @param[in] repeat_name Name of the repeat function call (for debugging).
+ * @param[in] signal function to call if the request is signalled.
+ * @param[in] sigmask Signals to block.
+ * @param[in] signal_name Name of the signal function call (for debugging).
+ * @param[in] top_frame Return out of the unlang interpreter when popping this frame.
+ * @param[in] uctx to pass to func(s).
+ * @return
+ * - UNLANG_ACTION_PUSHED_CHILD on success.
+ * - UNLANG_ACTION_FAIL on failure.
+ */
+unlang_action_t _unlang_function_push_no_result(request_t *request,
+ unlang_function_no_result_t func, char const *func_name,
+ unlang_function_no_result_t repeat, char const *repeat_name,
+ unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
+ bool top_frame, void *uctx)
+{
+ unlang_action_t ua;
- return UNLANG_ACTION_PUSHED_CHILD;
+ ua = unlang_function_push_common(NULL,
+ request,
+ func, func_name,
+ repeat, repeat_name,
+ signal, sigmask, signal_name,
+ UNLANG_FUNCTION_TYPE_NO_RESULT, top_frame, uctx);
+
+ if (unlikely(ua == UNLANG_ACTION_FAIL)) return UNLANG_ACTION_FAIL;
+
+ /* frame->process = call_no_result - This is the default, we don't need to set it again */
+
+ return ua;
}
/** Custom frame state dumper
unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
RDEBUG2("frame state");
- if (state->func) RDEBUG2("function %p (%s)", state->func, state->func_name);
- if (state->repeat) RDEBUG2("repeat %p (%s)", state->repeat, state->repeat_name);
+ if (FUNC(state)) RDEBUG2("function %p (%s)", FUNC(state), state->func_name);
+ if (REPEAT(state)) RDEBUG2("repeat %p (%s)", REPEAT(state), state->repeat_name);
if (state->signal) RDEBUG2("signal %p (%s)", state->signal, state->signal_name);
}
void unlang_function_init(void)
{
unlang_register(UNLANG_TYPE_FUNCTION,
- &(unlang_op_t){
+ &(unlang_op_t){
.name = "function",
- .interpret = unlang_function_call,
+ .interpret = call_no_result,
.signal = unlang_function_signal,
.dump = unlang_function_dump,
.flag = UNLANG_OP_FLAG_RETURN_POINT,
- .frame_state_size = sizeof(unlang_frame_state_func_t),
+ .frame_state_size = sizeof(unlang_frame_state_func_t),
.frame_state_type = "unlang_frame_state_func_t",
- });
+ });
}
#include <freeradius-devel/server/request.h>
#include <freeradius-devel/server/signal.h>
+
+typedef enum {
+ UNLANG_FUNCTION_TYPE_WITH_RESULT, //!< Function with a result.
+ UNLANG_FUNCTION_TYPE_NO_RESULT, //!< Function without a result.
+} unlang_function_type_t;
+
/** A generic function pushed by a module or xlat to functions deeper in the C call stack to create resumption points
*
* @param[in] p_result The module return code and priority.
* All input (args) and output will be done using this structure.
* @return an #unlang_action_t.
*/
-typedef unlang_action_t (*unlang_function_t)(unlang_result_t *p_result, request_t *request, void *uctx);
+typedef unlang_action_t (*unlang_function_with_result_t)(unlang_result_t *p_result, request_t *request, void *uctx);
+
+/** A generic function pushed by a module or xlat to functions deeper in the C call stack to create resumption points
+ *
+ * @note Returning UNLANG_ACTION_FAIL has an identical effect to returning UNLANG_ACTION_CALCULATE_RESULT
+ * and will not be visible to the caller.
+ *
+ * @param[in] request The current request.
+ * @param[in,out] uctx Provided by whatever pushed the function. Is opaque to the
+ * interpreter, but should be usable by the function.
+ * All input (args) and output will be done using this structure.
+ * @return an #unlang_action_t.
+ */
+typedef unlang_action_t (*unlang_function_no_result_t)(request_t *request, void *uctx);
/** Function to call if the request was signalled
*
* - -1 on failure.
*/
#define unlang_function_repeat_set(_request, _repeat) \
- _unlang_function_repeat_set(_request, _repeat, STRINGIFY(_repeat))
-int _unlang_function_repeat_set(request_t *request, unlang_function_t repeat, char const *name)
+ _Generic((&(_repeat)), \
+ unlang_function_with_result_t: _unlang_function_repeat_set(_request,\
+ (void *)(_repeat), \
+ STRINGIFY(_repeat), \
+ UNLANG_FUNCTION_TYPE_WITH_RESULT), \
+ unlang_function_no_result_t: _unlang_function_repeat_set(_request,\
+ (void *)(_repeat), \
+ STRINGIFY(_repeat), \
+ UNLANG_FUNCTION_TYPE_NO_RESULT) \
+ )
+int _unlang_function_repeat_set(request_t *request, void *repeat, char const *name, unlang_function_type_t type)
CC_HINT(warn_unused_result);
-/** Push a generic function onto the unlang stack
+/** Push a generic function onto the unlang stack that produces a result
*
* These can be pushed by any other type of unlang op to allow a submodule or function
* deeper in the C call stack to establish a new resumption point.
* doing it wrong. Use unlang_module_yield() instead, and change the process function for the
* module.
*
- * @note By default the rcodes from functions will be discarded. This can be altered on a per-function
- * basis by the func or repeat functions setting result_p->priority to a non-zero value.
- * Results can also be collected by passing in a non-NULL _result_p pointer.
- * You can also pass the result of unlang_interpret_result(request) to make the function frame
- * transparent, and evaluate the rcodes with the priorities of the current frame.
- *
* @param[in] _result_p Where to write the result.
* @param[in] _request The current request.
* @param[in] _func to call going up the stack.
* - UNLANG_ACTION_PUSHED_CHILD on success.
* - UNLANG_ACTION_FAIL on failure.
*/
-#define unlang_function_push(_result_p, _request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx) \
- _unlang_function_push(_result_p, _request, \
- _func, STRINGIFY(_func), \
- _repeat, STRINGIFY(_repeat), \
- _signal, _sigmask, STRINGIFY(_signal), \
- _top_frame, _uctx)
-unlang_action_t _unlang_function_push(unlang_result_t *p_result, request_t *request,
- unlang_function_t func, char const *func_name,
- unlang_function_t repeat, char const *repeat_name,
- unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
- bool top_frame, void *uctx)
- CC_HINT(warn_unused_result);
+#define unlang_function_push_with_result(_result_p, _request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx) \
+ _unlang_function_push_with_result(_result_p, _request, \
+ _func, STRINGIFY(_func), \
+ _repeat, STRINGIFY(_repeat), \
+ _signal, _sigmask, STRINGIFY(_signal), \
+ _top_frame, _uctx)
+
+unlang_action_t _unlang_function_push_with_result(unlang_result_t *p_result,
+ request_t *request,
+ unlang_function_with_result_t func, char const *func_name,
+ unlang_function_with_result_t repeat, char const *repeat_name,
+ unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
+ bool top_frame, void *uctx) CC_HINT(warn_unused_result);
+
+/** Push a generic function onto the unlang stack
+ *
+ * These can be pushed by any other type of unlang op to allow a submodule or function
+ * deeper in the C call stack to establish a new resumption point.
+ *
+ * @note If you're pushing a function onto the stack to resume execution in a module, you're probably
+ * doing it wrong. Use unlang_module_yield() instead, and change the process function for the
+ * module.
+ *
+ * @param[in] _request The current request.
+ * @param[in] _func to call going up the stack.
+ * @param[in] _repeat function to call going back down the stack (may be NULL).
+ * This may be the same as func.
+ * @param[in] _signal function to call if the request is signalled.
+ * @param[in] _sigmask Signals to block.
+ * @param[in] _top_frame Return out of the unlang interpreter when popping this frame.
+ * @param[in] _uctx to pass to func(s).
+ * @return
+ * - UNLANG_ACTION_PUSHED_CHILD on success.
+ * - UNLANG_ACTION_FAIL on failure.
+ */
+#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx) \
+ _unlang_function_push_no_result(_request, \
+ _func, STRINGIFY(_func), \
+ _repeat, STRINGIFY(_repeat), \
+ _signal, _sigmask, STRINGIFY(_signal), \
+ _top_frame, _uctx)
+unlang_action_t _unlang_function_push_no_result(request_t *request,
+ unlang_function_no_result_t func, char const *func_name,
+ unlang_function_no_result_t repeat, char const *repeat_name,
+ unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
+ bool top_frame, void *uctx) CC_HINT(warn_unused_result);
#ifdef __cplusplus
}
#endif
{
unlang_op_t *op = NULL;
- op = &unlang_ops[frame->instruction->type];
-
- instruction_dump(request, frame->instruction);
+ if (frame->instruction) {
+ op = &unlang_ops[frame->instruction->type];
+ instruction_dump(request, frame->instruction);
+ }
RINDENT();
if (frame->state) RDEBUG2("state %s (%p)", talloc_get_name(frame->state), frame->state);
RDEBUG2("yielded %s", is_yielded(frame) ? "yes" : "no");
RDEBUG2("unwind %s", is_unwinding(frame) ? "yes" : "no");
- RDEBUG2("control %s%s%s",
- is_break_point(frame) ? "b" : "-",
- is_return_point(frame) ? "r" : "-",
- is_continue_point(frame) ? "c" : "-"
- );
+ if (frame->instruction) {
+ RDEBUG2("control %s%s%s",
+ is_break_point(frame) ? "b" : "-",
+ is_return_point(frame) ? "r" : "-",
+ is_continue_point(frame) ? "c" : "-"
+ );
+ }
/*
* Call the custom frame dump function
request_t *parent = request->parent;
fr_packet_t *reply = request->reply;
- /*
- * Bubble this rcode up to become the result of the subrequest
- */
p_result->priority = MOD_PRIORITY_MAX;
if (RDEBUG_ENABLED2) {
* Setup a function in thie child to process the
* result of the subrequest.
*/
- if (unlang_function_push(/* sets priority */ NULL,
- child,
- NULL,
- /*
- * Run in the child after the virtual sever executes.
- * This sets the rcode for the subrequest, which is
- * written to eap_session->submodule_result.
- */
- process_reply,
- NULL, 0,
- UNLANG_SUB_FRAME, eap_session) != UNLANG_ACTION_PUSHED_CHILD) goto finish;
+ if (unlang_function_push_with_result(NULL,
+ child,
+ NULL,
+ /*
+ * Run in the child after the virtual sever executes.
+ * This sets the rcode for the subrequest, which is
+ * written to eap_session->submodule_result.
+ */
+ process_reply,
+ NULL, 0,
+ UNLANG_SUB_FRAME, eap_session) != UNLANG_ACTION_PUSHED_CHILD) goto finish;
/*
* Run inner tunnel in the context of the child
*/
if (*group_ctx->dn) {
if (unlang_function_repeat_set(request, ldap_cacheable_userobj_resolve) < 0) RETURN_UNLANG_FAIL;
- if (unlang_function_push(/* both start and resume provide an rcode */p_result, request,
- ldap_group_dn2name_start,
- ldap_group_dn2name_resume,
- ldap_group_userobj_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME, group_ctx) < 0) RETURN_UNLANG_FAIL;
+ if (unlang_function_push_with_result(/* both start and resume provide an rcode */p_result, request,
+ ldap_group_dn2name_start,
+ ldap_group_dn2name_resume,
+ ldap_group_userobj_cancel, ~FR_SIGNAL_CANCEL,
+ UNLANG_SUB_FRAME,
+ group_ctx) < 0) RETURN_UNLANG_FAIL;
return UNLANG_ACTION_PUSHED_CHILD;
}
*/
if (*group_ctx->group_name) {
if (unlang_function_repeat_set(request, ldap_cacheable_userobj_resolve) < 0) RETURN_UNLANG_FAIL;
- if (unlang_function_push(/* both start and resume provide an rcode */p_result, request,
- ldap_group_name2dn_start,
- ldap_group_name2dn_resume,
- ldap_group_userobj_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME, group_ctx) < 0) RETURN_UNLANG_FAIL;
+ if (unlang_function_push_with_result(/* both start and resume provide an rcode */p_result, request,
+ ldap_group_name2dn_start,
+ ldap_group_name2dn_resume,
+ ldap_group_userobj_cancel, ~FR_SIGNAL_CANCEL,
+ UNLANG_SUB_FRAME,
+ group_ctx) < 0) RETURN_UNLANG_FAIL;
return UNLANG_ACTION_PUSHED_CHILD;
}
*/
if ((name_p != group_ctx->group_name) || (dn_p != group_ctx->group_dn)) {
group_ctx->attrs[0] = inst->group.obj_name_attr;
- if (unlang_function_push(p_result, request,
- ldap_cacheable_userobj_resolve,
- NULL,
- ldap_group_userobj_cancel,
- ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME,
- group_ctx) < 0) {
+ if (unlang_function_push_with_result(p_result, request,
+ ldap_cacheable_userobj_resolve,
+ NULL,
+ ldap_group_userobj_cancel,
+ ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME,
+ group_ctx) < 0) {
talloc_free(group_ctx);
RETURN_UNLANG_FAIL;
}
group_ctx->base_dn = &autz_ctx->call_env->group_base;
fr_value_box_list_init(&group_ctx->expanded_filter);
- if (unlang_function_push(p_result,
- request,
- ldap_cacheable_groupobj_start,
- ldap_cacheable_groupobj_resume,
- ldap_group_groupobj_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME,
- group_ctx) < 0) {
+ if (unlang_function_push_with_result(p_result,
+ request,
+ ldap_cacheable_groupobj_start,
+ ldap_cacheable_groupobj_resume,
+ ldap_group_groupobj_cancel, ~FR_SIGNAL_CANCEL,
+ UNLANG_SUB_FRAME,
+ group_ctx) < 0) {
error:
talloc_free(group_ctx);
RETURN_UNLANG_FAIL;
group_ctx->base_dn = &xlat_ctx->env_data->group_base;
}
- if (unlang_function_push(p_result,
- request,
- ldap_cacheable_groupobj_start,
- ldap_check_groupobj_resume,
- ldap_group_groupobj_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME,
- group_ctx) < 0) {
+ if (unlang_function_push_with_result(p_result,
+ request,
+ ldap_cacheable_groupobj_start,
+ ldap_check_groupobj_resume,
+ ldap_group_groupobj_cancel, ~FR_SIGNAL_CANCEL,
+ UNLANG_SUB_FRAME,
+ group_ctx) < 0) {
error:
talloc_free(group_ctx);
RETURN_UNLANG_FAIL;
/** Initiate resolving a group DN to its name
*
*/
-static unlang_action_t ldap_dn2name_start (unlang_result_t *p_result, request_t *request, void *uctx)
+static unlang_action_t ldap_dn2name_start(unlang_result_t *p_result, request_t *request, void *uctx)
{
ldap_group_userobj_dyn_ctx_t *group_ctx = talloc_get_type_abort(uctx, ldap_group_userobj_dyn_ctx_t);
- ldap_group_xlat_ctx_t *xlat_ctx = group_ctx->xlat_ctx;
+ ldap_group_xlat_ctx_t *xlat_ctx = group_ctx->xlat_ctx;
rlm_ldap_t const *inst = xlat_ctx->inst;
if (!inst->group.obj_name_attr) {
/** Process the results of evaluating a user object when checking group membership
*
*/
-static unlang_action_t ldap_check_userobj_resume(UNUSED unlang_result_t *p_result,
- request_t *request, void *uctx)
+static unlang_action_t ldap_check_userobj_resume(unlang_result_t *p_result, request_t *request, void *uctx)
{
ldap_group_userobj_dyn_ctx_t *group_ctx = talloc_get_type_abort(uctx, ldap_group_userobj_dyn_ctx_t);
ldap_group_xlat_ctx_t *xlat_ctx = talloc_get_type_abort(group_ctx->xlat_ctx, ldap_group_xlat_ctx_t);
fr_value_box_t *group = xlat_ctx->group;
char *value_name = NULL;
+ /*
+ * Something we pushed failed early
+ */
+ switch (p_result->rcode) {
+ case RLM_MODULE_USER_SECTION_REJECT:
+ return UNLANG_ACTION_CALCULATE_RESULT;
+
+ default:
+ break;
+ }
+
/*
* If group_ctx->values is not populated, this is the first call
* - extract the returned values if any.
if (unlang_function_repeat_set(request, ldap_check_userobj_resume) < 0) RETURN_UNLANG_FAIL;
- return unlang_function_push(/* discard, ldap_check_userobj_resume looks at the query result */ NULL,
- request,
- ldap_dn2name_start,
- NULL,
- ldap_dn2name_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME, group_ctx);
+ /* Need to push this for the custom cancellation function */
+ return unlang_function_push_with_result(p_result,
+ request,
+ ldap_dn2name_start,
+ NULL,
+ ldap_dn2name_cancel, ~FR_SIGNAL_CANCEL,
+ UNLANG_SUB_FRAME,
+ group_ctx);
}
if (((talloc_array_length(group_ctx->group_name) - 1) == value->bv_len) &&
if (unlang_function_repeat_set(request, ldap_check_userobj_resume) < 0) RETURN_UNLANG_FAIL;
- return unlang_function_push(/* discard, ldap_check_userobj_resume gets result from group_ctx */ NULL,
- request,
- ldap_dn2name_start,
- NULL,
- ldap_dn2name_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME, group_ctx);
+ /* Need to push this for the custom cancellation function */
+ return unlang_function_push_with_result(p_result,
+ request,
+ ldap_dn2name_start,
+ NULL,
+ ldap_dn2name_cancel, ~FR_SIGNAL_CANCEL,
+ UNLANG_SUB_FRAME, group_ctx);
}
fr_assert(0);
* can be checked.
* If not then a query is needed to retrieve the user object.
*/
- if (unlang_function_push(/* ldap_check_userobj_resume provides an rcode result */p_result,
- request,
- xlat_ctx->query ? NULL : ldap_check_userobj_start,
- ldap_check_userobj_resume,
- ldap_group_userobj_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME, group_ctx) < 0) {
+ if (unlang_function_push_with_result(p_result,
+ request,
+ xlat_ctx->query ? NULL : ldap_check_userobj_start,
+ ldap_check_userobj_resume,
+ ldap_group_userobj_cancel, ~FR_SIGNAL_CANCEL,
+ UNLANG_SUB_FRAME,
+ group_ctx) < 0) {
talloc_free(group_ctx);
RETURN_UNLANG_FAIL;
}
/** Process the results of a profile lookup
*
*/
-static unlang_action_t ldap_map_profile_resume(UNUSED unlang_result_t *p_result, request_t *request, void *uctx)
+static unlang_action_t ldap_map_profile_resume(request_t *request, void *uctx)
{
ldap_profile_ctx_t *profile_ctx = talloc_get_type_abort(uctx, ldap_profile_ctx_t);
fr_ldap_query_t *query = profile_ctx->query;
};
if (ret) *ret = LDAP_RESULT_ERROR;
- if (unlang_function_push(/* discard, ldap_map_profile_resume doesn't appear to return an rcode */ NULL,
- request,
+ if (unlang_function_push(request,
NULL,
ldap_map_profile_resume,
ldap_map_profile_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME, profile_ctx) < 0) {
+ UNLANG_SUB_FRAME,
+ profile_ctx) < 0) {
talloc_free(profile_ctx);
return UNLANG_ACTION_FAIL;
}
xlat_ctx->basedn = &xlat_ctx->env_data->user_base;
return rlm_ldap_find_user_async(xlat_ctx,
- /* discard, only used by xlats */NULL,
+ /* discard, this function is only used by xlats */NULL,
xlat_ctx->inst, request,
xlat_ctx->basedn, xlat_ctx->filter,
xlat_ctx->ttrunk, xlat_ctx->attrs, &xlat_ctx->query);
#define REPEAT_LDAP_MEMBEROF_XLAT_RESULTS \
if (unlang_function_repeat_set(request, ldap_group_xlat_results) < 0) do { \
- result.rcode = RLM_MODULE_FAIL; \
- goto finish; \
+ RETURN_UNLANG_FAIL; \
} while (0)
/** Run the state machine for the LDAP membership xlat
*
* This is called after each async lookup is completed
+ *
+ * Will stop early, and set p_result to unlang_result
*/
static unlang_action_t ldap_group_xlat_results(unlang_result_t *p_result, request_t *request, void *uctx)
{
ldap_group_xlat_ctx_t *xlat_ctx = talloc_get_type_abort(uctx, ldap_group_xlat_ctx_t);
rlm_ldap_t const *inst = xlat_ctx->inst;
- unlang_result_t result = { .rcode = RLM_MODULE_NOTFOUND };
+
+ /*
+ * Check to see if rlm_ldap_check_groupobj_dynamic or rlm_ldap_check_userobj_dynamic failed
+ */
+ if (p_result->rcode == RLM_MODULE_FAIL) return UNLANG_ACTION_CALCULATE_RESULT;
switch (xlat_ctx->status) {
case GROUP_XLAT_FIND_USER:
if (inst->group.obj_membership_filter) {
REPEAT_LDAP_MEMBEROF_XLAT_RESULTS;
- if (rlm_ldap_check_groupobj_dynamic(&result, request, xlat_ctx) == UNLANG_ACTION_PUSHED_CHILD) {
+ if (rlm_ldap_check_groupobj_dynamic(p_result, request, xlat_ctx) == UNLANG_ACTION_PUSHED_CHILD) {
xlat_ctx->status = GROUP_XLAT_MEMB_FILTER;
return UNLANG_ACTION_PUSHED_CHILD;
}
FALL_THROUGH;
case GROUP_XLAT_MEMB_FILTER:
- if (xlat_ctx->found) {
- result.rcode = RLM_MODULE_OK;
- goto finish;
- }
+ if (xlat_ctx->found) RETURN_UNLANG_OK;
if (inst->group.userobj_membership_attr) {
REPEAT_LDAP_MEMBEROF_XLAT_RESULTS;
- if (rlm_ldap_check_userobj_dynamic(&result, request, xlat_ctx) == UNLANG_ACTION_PUSHED_CHILD) {
+ if (rlm_ldap_check_userobj_dynamic(p_result, request, xlat_ctx) == UNLANG_ACTION_PUSHED_CHILD) {
xlat_ctx->status = GROUP_XLAT_MEMB_ATTR;
return UNLANG_ACTION_PUSHED_CHILD;
}
FALL_THROUGH;
case GROUP_XLAT_MEMB_ATTR:
- if (xlat_ctx->found) result.rcode = RLM_MODULE_OK;
+ if (xlat_ctx->found) RETURN_UNLANG_OK;
break;
}
-finish:
- RETURN_UNLANG_RCODE(result.rcode);
+ RETURN_UNLANG_NOTFOUND;
}
/** Process the results of evaluating LDAP group membership
UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
{
ldap_group_xlat_ctx_t *xlat_ctx = talloc_get_type_abort(xctx->rctx, ldap_group_xlat_ctx_t);
- fr_value_box_t *vb;
+ fr_value_box_t *vb;
MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_BOOL, attr_expr_bool_enum));
vb->vb_bool = xlat_ctx->found;
if (unlang_xlat_yield(request, ldap_group_xlat_resume, NULL, 0, xlat_ctx) != XLAT_ACTION_YIELD) goto error;
- if (unlang_function_push(/* discard, ldap_group_xlat_resume just looks at xlat_ctx to see if things succeeded */ NULL,
- request,
- xlat_ctx->dn ? NULL : ldap_group_xlat_user_find,
- ldap_group_xlat_results,
- ldap_group_xlat_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME,
- xlat_ctx) < 0) goto error;
+ if (unlang_function_push_with_result(NULL,
+ request,
+ xlat_ctx->dn ? NULL : ldap_group_xlat_user_find,
+ ldap_group_xlat_results,
+ ldap_group_xlat_cancel, ~FR_SIGNAL_CANCEL,
+ UNLANG_SUB_FRAME,
+ xlat_ctx) < 0) goto error;
return XLAT_ACTION_PUSH_UNLANG;
}
fr_ldap_thread_trunk_t *ttrunk;
fr_ldap_query_t *query;
ldap_group_xlat_status_t status;
+ unlang_result_t result;
bool found;
} ldap_group_xlat_ctx_t;
};
if (filter) user_ctx->filter = filter->vb_strvalue;
- if (unlang_function_push(/* ldap_find_user_async_result sets an rcode based on the search result */ p_result,
- request,
- NULL,
- ldap_find_user_async_result,
- ldap_find_user_async_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME, user_ctx) < 0) {
+ if (unlang_function_push_with_result(/* ldap_find_user_async_result sets an rcode based on the search result */ p_result,
+ request,
+ NULL,
+ ldap_find_user_async_result,
+ ldap_find_user_async_cancel, ~FR_SIGNAL_CANCEL,
+ UNLANG_SUB_FRAME, user_ctx) < 0) {
talloc_free(user_ctx);
return UNLANG_ACTION_FAIL;
}
unlang_xlat_yield(request, sql_xlat_select_resume, NULL, 0, query_ctx);
- if (unlang_function_push(/* discard, sql_xlat_select_resume just uses query_ctx->rcode */ NULL,
- request,
- inst->select,
- NULL,
- NULL, 0,
- UNLANG_SUB_FRAME, query_ctx) == UNLANG_ACTION_FAIL) return XLAT_ACTION_FAIL;
+ if (unlang_function_push_with_result(/* discard, sql_xlat_select_resume just uses query_ctx->rcode */ NULL,
+ request,
+ inst->select,
+ NULL,
+ NULL, 0,
+ UNLANG_SUB_FRAME, query_ctx) == UNLANG_ACTION_FAIL) return XLAT_ACTION_FAIL;
return XLAT_ACTION_PUSH_UNLANG;
}
thread->trunk, arg->vb_strvalue, SQL_QUERY_SELECT));
unlang_xlat_yield(request, sql_xlat_select_resume, NULL, 0, query_ctx);
- if (unlang_function_push(/* discard, sql_xlat_select_resume just uses query_ctx->rcode */NULL,
- request,
- inst->select,
- NULL,
- NULL, 0,
- UNLANG_SUB_FRAME, query_ctx) != UNLANG_ACTION_PUSHED_CHILD) return XLAT_ACTION_FAIL;
+ if (unlang_function_push_with_result(/* discard, sql_xlat_select_resume just uses query_ctx->rcode */NULL,
+ request,
+ inst->select,
+ NULL,
+ NULL, 0,
+ UNLANG_SUB_FRAME, query_ctx) != UNLANG_ACTION_PUSHED_CHILD) return XLAT_ACTION_FAIL;
return XLAT_ACTION_PUSH_UNLANG;
}
thread->trunk, query_head->vb_strvalue, SQL_QUERY_SELECT);
if (unlang_map_yield(request, mod_map_resume, NULL, 0, query_ctx) != UNLANG_ACTION_YIELD) RETURN_UNLANG_FAIL;
- return unlang_function_push(/* discard, mod_map_resume just uses query_ctx->rcode */ NULL,
- request,
- inst->select,
- NULL,
- NULL,
- 0, UNLANG_SUB_FRAME,
- query_ctx);
+ return unlang_function_push_with_result(/* discard, mod_map_resume just uses query_ctx->rcode */ NULL,
+ request,
+ inst->select,
+ NULL,
+ NULL,
+ 0, UNLANG_SUB_FRAME,
+ query_ctx);
}
/** xlat escape function for drivers which do not provide their own
MEM(group_ctx->query_ctx = fr_sql_query_alloc(group_ctx, inst, request, trunk,
group_ctx->query->vb_strvalue, SQL_QUERY_SELECT));
- if (unlang_function_push(/* sql_get_grouplist_resume translates the query_ctx->rocde into a module rcode */p_result,
- request,
+ if (unlang_function_push_with_result(/* sql_get_grouplist_resume translates the query_ctx->rocde into a module rcode */p_result,
+ request,
NULL,
sql_get_grouplist_resume,
NULL,
0, UNLANG_SUB_FRAME,
group_ctx) < 0) return UNLANG_ACTION_FAIL;
- return unlang_function_push(/* discard, sql_get_grouplist_resume translates rcodes */NULL,
- request,
- inst->select,
- NULL,
- NULL, 0,
- UNLANG_SUB_FRAME, group_ctx->query_ctx);
+ return unlang_function_push_with_result(/* discard, sql_get_grouplist_resume translates rcodes */NULL,
+ request,
+ inst->select,
+ NULL,
+ NULL, 0,
+ UNLANG_SUB_FRAME, group_ctx->query_ctx);
}
typedef struct {
redundant_ctx->query_vb->vb_strvalue, SQL_QUERY_OTHER));
unlang_module_yield(request, mod_sql_redundant_query_resume, NULL, 0, redundant_ctx);
- return unlang_function_push(/* discard, mod_sql_redundant_query_resume uses query_ctx->rcode*/ NULL,
- request,
- inst->query,
- NULL,
- NULL,
- 0, UNLANG_SUB_FRAME,
- redundant_ctx->query_ctx);
+ return unlang_function_push_with_result(/* discard, mod_sql_redundant_query_resume uses query_ctx->rcode*/ NULL,
+ request,
+ inst->query,
+ NULL,
+ NULL,
+ 0, UNLANG_SUB_FRAME,
+ redundant_ctx->query_ctx);
}
/** Generic module call for failing between a bunch of queries.
int flags;
- unlang_function_t sql_query_resume; //!< Callback run after an SQL trunk query is run.
- unlang_function_t sql_select_query_resume; //!< Callback run after an SQL select trunk query is run.
+ unlang_function_with_result_t sql_query_resume; //!< Callback run after an SQL trunk query is run.
+ unlang_function_with_result_t sql_select_query_resume; //!< Callback run after an SQL select trunk query is run.
int (*sql_num_rows)(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config);
int (*sql_affected_rows)(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config);
- unlang_function_t sql_fetch_row;
+ unlang_function_with_result_t sql_fetch_row;
sql_rcode_t (*sql_fields)(char const **out[], fr_sql_query_t *query_ctx, rlm_sql_config_t const *config);
sql_rcode_t (*sql_free_result)(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config);
} rlm_sql_driver_t;
struct sql_inst {
- rlm_sql_config_t config; /* HACK */
+ rlm_sql_config_t config; /* HACK */
- fr_dict_attr_t const *sql_user; //!< Cached pointer to SQL-User-Name
+ fr_dict_attr_t const *sql_user; //!< Cached pointer to SQL-User-Name
//!< dictionary attribute.
- exfile_t *ef;
+ exfile_t *ef;
- module_instance_t *driver_submodule; //!< Driver's submodule.
- rlm_sql_driver_t const *driver; //!< Driver's exported interface.
+ module_instance_t *driver_submodule; //!< Driver's submodule.
+ rlm_sql_driver_t const *driver; //!< Driver's exported interface.
- xlat_escape_legacy_t sql_escape_func;
- fr_value_box_escape_t box_escape;
- void *sql_escape_arg; //!< Instance specific argument to be passed to escape function.
- unlang_function_t query;
- unlang_function_t select;
- unlang_function_t fetch_row;
- fr_sql_query_t *(*query_alloc)(TALLOC_CTX *ctx, rlm_sql_t const *inst, request_t *request, trunk_t *trunk, char const *query_str, fr_sql_query_type_t type);
-
- char const *name; //!< Module instance name.
- fr_dict_attr_t const *group_da; //!< Group dictionary attribute.
- fr_dict_attr_t const *query_number_da; //!< Query number attribute.
- module_instance_t const *mi; //!< Module instance data for thread lookups.
+ xlat_escape_legacy_t sql_escape_func;
+ fr_value_box_escape_t box_escape;
+ void *sql_escape_arg; //!< Instance specific argument to be passed to escape function.
+
+ unlang_function_with_result_t query;
+ unlang_function_with_result_t select;
+ unlang_function_with_result_t fetch_row;
+
+ fr_sql_query_t *(*query_alloc)(TALLOC_CTX *ctx, rlm_sql_t const *inst, request_t *request, trunk_t *trunk, char const *query_str, fr_sql_query_type_t type);
+
+ char const *name; //!< Module instance name.
+ fr_dict_attr_t const *group_da; //!< Group dictionary attribute.
+ fr_dict_attr_t const *query_number_da; //!< Query number attribute.
+ module_instance_t const *mi; //!< Module instance data for thread lookups.
};
unlang_action_t sql_get_map_list(unlang_result_t *p_result, request_t *request, fr_sql_map_ctx_t *map_ctx, trunk_t *trunk);
* state of the trunk request to reapable - so in that case don't
* yield (in sql_trunk_query_start)
*/
- if (unlang_function_push(/* allow the caller of rlm_sql_trunk_query to get at the rcode */p_result,
- request,
- query_ctx->treq->state == TRUNK_REQUEST_STATE_REAPABLE ?
- NULL : sql_trunk_query_start,
- query_ctx->type == SQL_QUERY_SELECT ?
- query_ctx->inst->driver->sql_select_query_resume :
- query_ctx->inst->driver->sql_query_resume,
- sql_trunk_query_cancel, ~FR_SIGNAL_CANCEL,
- UNLANG_SUB_FRAME, query_ctx) < 0) RETURN_UNLANG_FAIL;
+ if (unlang_function_push_with_result(/* allow the caller of rlm_sql_trunk_query to get at the rcode */p_result,
+ request,
+ query_ctx->treq->state == TRUNK_REQUEST_STATE_REAPABLE ?
+ NULL : sql_trunk_query_start,
+ query_ctx->type == SQL_QUERY_SELECT ?
+ query_ctx->inst->driver->sql_select_query_resume :
+ query_ctx->inst->driver->sql_query_resume,
+ sql_trunk_query_cancel, ~FR_SIGNAL_CANCEL,
+ UNLANG_SUB_FRAME, query_ctx) < 0) RETURN_UNLANG_FAIL;
p_result->rcode = RLM_MODULE_OK;
return UNLANG_ACTION_PUSHED_CHILD;
MEM(map_ctx->query_ctx = fr_sql_query_alloc(map_ctx->ctx, inst, request, trunk,
map_ctx->query->vb_strvalue, SQL_QUERY_SELECT));
- if (unlang_function_push(p_result,
- request,
- NULL,
- sql_get_map_list_resume,
- NULL, 0,
- UNLANG_SUB_FRAME,
- map_ctx) < 0) return UNLANG_ACTION_FAIL;
-
- return unlang_function_push(/* discard, sql_get_map_list_resume uses query_ctx->rcode */ NULL,
- request,
- inst->select,
- NULL,
- NULL, 0,
- UNLANG_SUB_FRAME,
- map_ctx->query_ctx);
+ if (unlang_function_push_with_result(p_result,
+ request,
+ NULL,
+ sql_get_map_list_resume,
+ NULL, 0,
+ UNLANG_SUB_FRAME,
+ map_ctx) < 0) return UNLANG_ACTION_FAIL;
+
+ return unlang_function_push_with_result(/* discard, sql_get_map_list_resume uses query_ctx->rcode */ NULL,
+ request,
+ inst->select,
+ NULL,
+ NULL, 0,
+ UNLANG_SUB_FRAME,
+ map_ctx->query_ctx);
}
/*
query_ctx->type = _type; \
query_ctx->status = SQL_QUERY_PREPARED; \
alloc_ctx->query = query; \
- return unlang_function_push(p_result, request, sql->_function, NULL, NULL, 0, UNLANG_SUB_FRAME, query_ctx); \
+ return unlang_function_push_with_result(p_result, request, sql->_function, NULL, NULL, 0, UNLANG_SUB_FRAME, query_ctx); \
} while (0)
/** Resume function called after each IP allocation query is expanded
if ((env->begin.type == FR_TYPE_STRING) && env->begin.vb_length) {
alloc_ctx->query_ctx->query_str = env->begin.vb_strvalue;
- return unlang_function_push(/* mod_alloc_resume looks at frame result */ p_result,
- request,
- sql->query,
- NULL,
- NULL, 0,
- UNLANG_SUB_FRAME,
- alloc_ctx->query_ctx);
+ return unlang_function_push_with_result(/* mod_alloc_resume looks at frame result */ p_result,
+ request,
+ sql->query,
+ NULL,
+ NULL, 0,
+ UNLANG_SUB_FRAME,
+ alloc_ctx->query_ctx);
}
return UNLANG_ACTION_PUSHED_CHILD;
common_ctx->query_ctx->query_str = common_ctx->env->update.vb_strvalue;
query_ctx->status = SQL_QUERY_PREPARED;
- return unlang_function_push(/* mod_common_update_resume uses frame rcode */p_result,
- request,
- sql->query,
- NULL,
- NULL, 0,
- UNLANG_SUB_FRAME,
- query_ctx);
+ return unlang_function_push_with_result(/* mod_common_update_resume uses frame rcode */p_result,
+ request,
+ sql->query,
+ NULL,
+ NULL, 0,
+ UNLANG_SUB_FRAME,
+ query_ctx);
}
/** Common function used by module methods which perform an optional "free" then "update"
talloc_free(common_ctx);
RETURN_UNLANG_FAIL;
}
- return unlang_function_push(/* mod_common_free_resume looks at frame result */ NULL,
- request,
- sql->query,
- NULL,
- NULL, 0,
- UNLANG_SUB_FRAME,
- common_ctx->query_ctx);
+ return unlang_function_push_with_result(/* mod_common_free_resume looks at frame result */ NULL,
+ request,
+ sql->query,
+ NULL,
+ NULL, 0,
+ UNLANG_SUB_FRAME,
+ common_ctx->query_ctx);
}
common_ctx->query_ctx->query_str = env->update.vb_strvalue;
talloc_free(common_ctx);
RETURN_UNLANG_FAIL;
}
- return unlang_function_push(/* mod_common_update_resume looks at frame result */ p_result,
- request,
- sql->query,
- NULL,
- NULL, 0,
- UNLANG_SUB_FRAME,
- common_ctx->query_ctx);
+ return unlang_function_push_with_result(/* mod_common_update_resume looks at frame result */ p_result,
+ request,
+ sql->query,
+ NULL,
+ NULL, 0,
+ UNLANG_SUB_FRAME,
+ common_ctx->query_ctx);
}
/** Call SQL module box_escape_func to escape tainted values