* @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 action for the interpreter to perform.
+ * @return an #unlang_action_t.
*/
-typedef unlang_action_t (*unlang_function_t)(REQUEST *request, void *uctx);
+typedef unlang_action_t (*unlang_function_t)(REQUEST *request, rlm_rcode_t *presult, int *priority, void *uctx);
/** An unlang operation
*
///< in debug mode.
} unlang_op_t;
-void unlang_push_function(REQUEST *request, unlang_function_t func, unlang_function_t repeat, void *uctx);
+void unlang_push_function(REQUEST *request,
+ unlang_function_t func, unlang_function_t repeat, void *uctx);
bool unlang_section(CONF_SECTION *cs);
unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
unlang_t *instruction = frame->instruction;
unlang_action_t ua;
+ char const *caller;
- if (!frame->repeat) {
- ua = state->func(request, state->uctx);
- } else {
- ua = state->repeat(request, state->uctx);
- }
+ *priority = instruction->actions[*presult];
/*
- * The success/failure of these functions
- * should not affect the rcode in any way.
- *
- * Only the module/xlat which pushed the
- * function can interpret its result,
- * which will be written to uf->uctx.
+ * Don't let the callback mess with the current
+ * module permanently.
*/
- *presult = RLM_MODULE_OK;
- *priority = instruction->actions[*presult];
+ caller = request->module;
+ request->module = NULL;
+ if (!frame->repeat) {
+ ua = state->func(request, presult, priority, state->uctx);
+ } else {
+ ua = state->repeat(request, presult, priority, state->uctx);
+ }
+ request->module = caller;
return ua;
}
* - RLM_MODULE_HANDLED if we're done with this round.
* - RLM_MODULE_REJECT if the user should be rejected.
*/
-static rlm_rcode_t mod_authenticate_result(REQUEST *request, void *instance, UNUSED void *thread, void *uctx)
+static rlm_rcode_t mod_authenticate_result(REQUEST *request, void *instance, UNUSED void *thread,
+ eap_session_t *eap_session, rlm_rcode_t result)
{
rlm_eap_t *inst = talloc_get_type_abort(instance, rlm_eap_t);
- eap_auth_rctx_t *rctx = talloc_get_type_abort(uctx, eap_auth_rctx_t);
- eap_session_t *eap_session = rctx->eap_session;
rlm_eap_method_t *method = &inst->methods[eap_session->type];
rlm_rcode_t rcode;
- rad_assert(rctx->rcode != RLM_MODULE_UNKNOWN);
-
- request->module = rctx->caller; /* Restore original module name */
RDEBUG2("Submodule %s returned", method->submodule->name);
/*
* The submodule failed. Die.
*/
- if (rctx->rcode == RLM_MODULE_INVALID) {
+ if (result == RLM_MODULE_INVALID) {
eap_fail(eap_session);
eap_session_destroy(&eap_session);
eap_session_freeze(&eap_session);
finish:
- talloc_free(rctx); /* Free rctx */
return rcode;
}
-/** Destroy an EAP session if the request currently processing it is destroyed
- *
- * We do this so we don't leak EAP sessions.
- *
- */
-static void mod_authenticate_signal(UNUSED REQUEST *request, UNUSED void *instance, UNUSED void *thread,
- void *uctx, fr_state_signal_t action)
-{
- eap_auth_rctx_t *rctx = talloc_get_type_abort(uctx, eap_auth_rctx_t);
- eap_session_t *eap_session = rctx->eap_session;
-
- if (action != FR_SIGNAL_DONE) return;
-
- eap_session_destroy(&eap_session);
- talloc_free(rctx); /* Would be cleaned up anyway but doesn't hurt */
-}
-
-/** Call an eap submodule using the unlang stack
+/** Call mod_authenticate_result asynchronously from the unlang interpreter
*
* @param[in] request The current request.
- * @param[in] uctx Describing the module to call.
- * @return
- * - UNLANG_ACTION_CALCULATE_RESULT.
- * - UNLANG_ACTION_YIELD.
+ * @param[in] instance of rlm_eap.
+ * @param[in] thread UNUSED.
+ * @param[in] uctx the eap_session_t.
+ * @return The result of this round of authentication.
*/
-static unlang_action_t eap_call_submodule(UNUSED REQUEST *request, void *uctx)
+static rlm_rcode_t mod_authenticate_result_async(REQUEST *request, void *instance, void *thread, void *uctx)
{
- eap_auth_rctx_t *rctx = talloc_get_type_abort(uctx, eap_auth_rctx_t);
- rlm_eap_t *inst = rctx->inst;
- eap_session_t *eap_session = rctx->eap_session;
- rlm_eap_method_t *method = &inst->methods[eap_session->type];
-
- request->module = rctx->caller;
- RDEBUG2("Calling submodule %s", method->submodule->name);
-
- request->module = method->submodule->name;
- rctx->rcode = eap_session->process(method->submodule_inst->data, eap_session);
- request->module = NULL;
+ eap_session_t *eap_session = talloc_get_type_abort(uctx, eap_session_t);
+ rlm_rcode_t result = unlang_stack_result(request);
- return UNLANG_ACTION_CALCULATE_RESULT;
+ return mod_authenticate_result(request, instance, thread, eap_session, result);
}
/** Select the correct callback based on a response
* - RLM_MODULE_YIELD Yield control back to the interpreter so it can
* call the submodule.
*/
-static rlm_rcode_t eap_method_select(rlm_eap_t *inst, eap_session_t *eap_session)
+static rlm_rcode_t eap_method_select(rlm_eap_t *inst, void *thread, eap_session_t *eap_session)
{
- eap_type_data_t *type = &eap_session->this_round->response->type;
- REQUEST *request = eap_session->request;
+ eap_type_data_t *type = &eap_session->this_round->response->type;
+ REQUEST *request = eap_session->request;
- eap_type_t next = inst->default_method;
- VALUE_PAIR *vp;
+ rlm_eap_method_t const *method;
+
+ eap_type_t next = inst->default_method;
+ VALUE_PAIR *vp;
- eap_auth_rctx_t *rctx;
+ rlm_rcode_t rcode;
/*
* Session must have been thawed...
eap_session->type = type->num;
module_call:
- MEM(rctx = talloc(request, eap_auth_rctx_t));
- rctx->caller = request->module;
- rctx->inst = inst;
- rctx->eap_session = eap_session;
- rctx->rcode = RLM_MODULE_UNKNOWN;
+ method = &inst->methods[eap_session->type];
+
+ unlang_module_yield(request, mod_authenticate_result_async, NULL, eap_session);
/*
* mod_authenticate_result will be called after
* eap_call_submodule finishes.
*/
- unlang_module_yield(request, mod_authenticate_result, mod_authenticate_signal, rctx);
- unlang_push_function(request, eap_call_submodule, NULL, rctx);
+ RDEBUG2("Calling submodule %s", method->submodule->name);
+// caller = request->module;
+// request->module = method->submodule->name;
+ rcode = eap_session->process(method->submodule_inst->data, eap_session);
+// request->module = caller;
+
+ /*
+ * If the submodule yielded, then setup a resumption
+ * frame for when it finishes.
+ */
+ if (rcode == RLM_MODULE_YIELD) return RLM_MODULE_YIELD;
- return RLM_MODULE_YIELD;
+ /*
+ * If the submodule didn't yield call the result
+ * function directly using the C stack.
+ */
+ return mod_authenticate_result(request, inst, thread, eap_session, rcode);
}
-static rlm_rcode_t mod_authenticate(void *instance, UNUSED void *thread, REQUEST *request)
+static rlm_rcode_t mod_authenticate(void *instance, void *thread, REQUEST *request)
{
rlm_eap_t *inst = talloc_get_type_abort(instance, rlm_eap_t);
eap_session_t *eap_session;
* or with simple types like Identity and NAK,
* process it ourselves.
*/
- if (eap_method_select(inst, eap_session) != RLM_MODULE_YIELD) {
- RDEBUG2("Cleaning up EAP session");
- eap_fail(eap_session);
- eap_session_destroy(&eap_session);
- return RLM_MODULE_INVALID;
- }
-
- return RLM_MODULE_YIELD;
+ return eap_method_select(inst, thread, eap_session);
}
/*
* Do authentication, by letting EAP-TLS do most of the work.
*/
static rlm_rcode_t CC_HINT(nonnull) mod_process(void *instance, eap_session_t *eap_session);
-static rlm_rcode_t mod_process(void *type_arg, eap_session_t *eap_session)
+
+static unlang_action_t eap_tls_virtual_server_result(REQUEST *request, rlm_rcode_t *presult,
+ UNUSED int *priority, void *uctx)
+{
+ eap_session_t *eap_session = talloc_get_type_abort(uctx, eap_session_t);
+
+ switch (*presult) {
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ if (eap_tls_success(eap_session) < 0) *presult = RLM_MODULE_FAIL;
+ break;
+
+ default:
+ REDEBUG2("Certificate rejected by the virtual server");
+ eap_tls_fail(eap_session);
+ *presult = RLM_MODULE_REJECT;
+ break;
+ }
+
+ return UNLANG_ACTION_CALCULATE_RESULT;
+}
+
+static rlm_rcode_t eap_tls_virtual_server(rlm_eap_tls_t *inst, eap_session_t *eap_session)
+{
+ REQUEST *request = eap_session->request;
+ CONF_SECTION *server_cs;
+ CONF_SECTION *section;
+ VALUE_PAIR *vp;
+
+ /* set the virtual server to use */
+ vp = fr_pair_find_by_num(request->control, 0, FR_VIRTUAL_SERVER, TAG_ANY);
+ if (vp) {
+ server_cs = virtual_server_find(vp->vp_strvalue);
+ if (!server_cs) {
+ REDEBUG2("Virtual server \"%s\" not found", vp->vp_strvalue);
+ error:
+ eap_tls_fail(eap_session);
+ return RLM_MODULE_INVALID;
+ }
+ } else {
+ server_cs = virtual_server_find(inst->virtual_server);
+ rad_assert(server_cs);
+ }
+
+ section = cf_section_find(server_cs, "recv", "Access-Request");
+ if (!section) {
+ REDEBUG2("Failed finding 'recv Access-Request { ... }' section of virtual server %s",
+ cf_section_name2(server_cs));
+ goto error;
+ }
+
+ if (!unlang_section(section)) {
+ REDEBUG("Failed to find pre-compiled unlang for section %s %s { ... }",
+ cf_section_name1(server_cs), cf_section_name2(server_cs));
+ goto error;
+ }
+
+ RDEBUG2("Validating certificate");
+
+ /*
+ * Catch the interpreter on the way back up the stack
+ */
+ unlang_push_function(request, NULL, eap_tls_virtual_server_result, eap_session);
+
+ /*
+ * Push unlang instructions for the virtual server section
+ */
+ unlang_push_section(request, section, RLM_MODULE_NOOP, UNLANG_SUB_FRAME);
+
+ return RLM_MODULE_YIELD;
+}
+
+static rlm_rcode_t mod_process(void *instance, eap_session_t *eap_session)
{
eap_tls_status_t status;
eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
tls_session_t *tls_session = eap_tls_session->tls_session;
REQUEST *request = eap_session->request;
- rlm_eap_tls_t *inst;
-
- inst = type_arg;
+ rlm_eap_tls_t *inst = talloc_get_type_abort(instance, rlm_eap_tls_t);
status = eap_tls_process(eap_session);
if ((status == EAP_TLS_INVALID) || (status == EAP_TLS_FAIL)) {
* it accepts the certificates, too.
*/
case EAP_TLS_ESTABLISHED:
- if (inst->virtual_server) {
- VALUE_PAIR *vp;
- REQUEST *fake;
-
- /* create a fake request */
- fake = request_alloc_fake(request);
- rad_assert(!fake->packet->vps);
-
- fake->packet->vps = fr_pair_list_copy(fake->packet, request->packet->vps);
-
- /* set the virtual server to use */
- if ((vp = fr_pair_find_by_num(request->control, 0, FR_VIRTUAL_SERVER, TAG_ANY)) != NULL) {
- fake->server_cs = virtual_server_find(vp->vp_strvalue);
- if (!fake->server_cs) {
- REDEBUG2("Virtual server \"%s\" not found", vp->vp_strvalue);
- talloc_free(fake);
- eap_tls_fail(eap_session);
- return RLM_MODULE_INVALID;
- }
- } else {
- fake->server_cs = virtual_server_find(inst->virtual_server);
- rad_assert(fake->server_cs);
- }
-
- RDEBUG2("Validating certificate");
- rad_virtual_server(fake);
-
- /* copy the reply vps back to our reply */
- fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps, &fake->reply->vps, 0, 0,
- TAG_ANY);
-
- /* reject if virtual server didn't return accept */
- if (fake->reply->code != FR_CODE_ACCESS_ACCEPT) {
- RDEBUG2("Certificate rejected by the virtual server");
- talloc_free(fake);
- eap_tls_fail(eap_session);
- return RLM_MODULE_REJECT;
- }
-
- talloc_free(fake);
- /* success */
- }
- break;
+ if (inst->virtual_server) return eap_tls_virtual_server(inst, eap_session);
+ if (eap_tls_success(eap_session) < 0) return RLM_MODULE_FAIL;
+
+ return RLM_MODULE_OK;
/*
* The TLS code is still working on the TLS
return RLM_MODULE_REJECT;
}
-
- if (eap_tls_success(eap_session) < 0) return RLM_MODULE_FAIL;
-
- return RLM_MODULE_OK;
}
/*
* Send an initial eap-tls request to the peer, using the libeap functions.
*/
-static rlm_rcode_t mod_session_init(void *type_arg, eap_session_t *eap_session)
+static rlm_rcode_t mod_session_init(void *uctx, eap_session_t *eap_session)
{
eap_tls_session_t *eap_tls_session;
- rlm_eap_tls_t *inst = talloc_get_type_abort(type_arg, rlm_eap_tls_t);
+ rlm_eap_tls_t *inst = talloc_get_type_abort(uctx, rlm_eap_tls_t);
VALUE_PAIR *vp;
bool client_cert;
eap_session->process = mod_process;
- return RLM_MODULE_OK;
+ return RLM_MODULE_HANDLED;
}
/*