/** Yield, spawning a child request, and resuming once the child request is complete * * @param[in] out Final rcode from when evaluation of the child request finishes. * @param[out] child - If not NULL, and points to a NULL pointer a pointer to the * child will be provided. * The caller can then manipulate the child, adding request data * and/or attributes. * The child pointer must be explicitly freed with * #unlang_subrequest_free once it is no longer needed. * - If not NULL, and points to a request, the request will be run * through the section passed as section_cs. The request must * have been allocated during a previous call to * unlang_module_yield_to_subrequest. * - If NULL the child will be automatically freed when the subrequest * completes. * @param[in] parent The current request. * @param[in] section_cs to execute. * @param[in] default_rcode The rcode the child starts executing its section with. * @param[in] resume function to call when the child has finished executing. * @param[in] signal function to call if a signal is received. * @param[in] rctx to pass to the resume() and signal() callbacks. * @return * - RLM_MODULE_YIELD. */ rlm_rcode_t unlang_module_yield_to_subrequest(rlm_rcode_t *out, REQUEST **child, REQUEST *parent, CONF_SECTION *section_cs, rlm_rcode_t default_rcode, fr_unlang_module_resume_t resume, fr_unlang_module_signal_t signal, void *rctx) { unlang_t *instruction = (unlang_t *)cf_data_value(cf_data_find(section_cs, unlang_group_t, NULL)); rad_assert(instruction); /* * Push the resumption point */ (void) unlang_module_yield(parent, resume, signal, rctx); if (!child || !*child) { CONF_SECTION *server_cs; fr_dict_t *dict; server_cs = virtual_server_by_child(section_cs); /* * We don't support executing orphaned sections. */ rad_assert(server_cs); /* * Work out the dictionary from the server section's cf_data */ dict = virtual_server_namespace(cf_section_name2(server_cs)); /* * If this asserts, fix the validation logic * don't just set a default value. * * *ALL* virtual servers should have a namespace. */ rad_assert(dict); /* * Push the subrequest frame. */ unlang_subrequest_push(out, child, parent, server_cs, instruction, dict, default_rcode, true); } else { unlang_subrequest_push_again(out, talloc_get_type_abort(*child, REQUEST), parent, instruction, default_rcode, true); } return RLM_MODULE_YIELD; /* This may allow us to do optimisations in future */ }
/** Push a pre-compiled xlat and resumption state onto the stack for evaluation * * In order to use the async unlang processor the calling module needs to establish * a resumption point, as the call to an xlat function may require yielding control * back to the interpreter. * * To simplify the calling conventions, this function is provided to first push a * resumption stack frame for the module, and then push an xlat stack frame. * * After pushing those frames the function updates the stack pointer to jump over * the resumption frame and execute the xlat interpreter. * * When the xlat interpreter finishes, and pops the xlat frame, the unlang interpreter * will then call the module resumption frame, allowing the module to continue exectuion. * * @param[in] ctx To allocate talloc value boxes and values in. * @param[out] out Where to write the result of the expansion. * @param[in] request The current request. * @param[in] exp XLAT expansion to evaluate. * @param[in] resume function to call when the XLAT expansion is complete. * @param[in] signal function to call if a signal is received. * @param[in] rctx to pass to the resume() and signal() callbacks. * @return * - RLM_MODULE_YIELD. */ rlm_rcode_t unlang_module_yield_to_xlat(TALLOC_CTX *ctx, fr_value_box_t **out, REQUEST *request, xlat_exp_t const *exp, fr_unlang_module_resume_t resume, fr_unlang_module_signal_t signal, void *rctx) { /* * Push the resumption point */ (void) unlang_module_yield(request, resume, signal, rctx); /* * Push the xlat function */ unlang_xlat_push(ctx, out, request, exp, true); return RLM_MODULE_YIELD; /* This may allow us to do optimisations in future */ }
static rlm_rcode_t CC_HINT(nonnull) mod_delay(void *instance, UNUSED void *thread, REQUEST *request) { rlm_delay_t const *inst = instance; struct timeval delay, resume_at, *yielded_at; if (inst->delay) { if (tmpl_aexpand(request, &delay, request, inst->delay, NULL, NULL) < 0) return RLM_MODULE_FAIL; } else { memset(&delay, 0, sizeof(delay)); } /* * Record the time that we yielded the request */ MEM(yielded_at = talloc(request, struct timeval)); if (gettimeofday(yielded_at, NULL) < 0) { REDEBUG("Failed getting current time: %s", fr_syserror(errno)); return RLM_MODULE_FAIL; } /* * Setup the delay for this request */ if (delay_add(request, &resume_at, yielded_at, &delay, inst->force_reschedule, inst->delay) != 0) { return RLM_MODULE_NOOP; } RDEBUG3("Current time %pV, resume time %pV", fr_box_timeval(*yielded_at), fr_box_timeval(resume_at)); if (unlang_event_module_timeout_add(request, _delay_done, yielded_at, &resume_at) < 0) { RPEDEBUG("Adding event failed"); return RLM_MODULE_FAIL; } return unlang_module_yield(request, mod_delay_return, mod_delay_cancel, yielded_at); }
/** Send packets outbound. * */ static rlm_rcode_t CC_HINT(nonnull) mod_process(void *instance, void *thread, REQUEST *request) { rlm_rcode_t rcode; rlm_radius_t *inst = instance; rlm_radius_thread_t *t = talloc_get_type_abort(thread, rlm_radius_thread_t); void *request_io_ctx; if (!request->packet->code) { RDEBUG("You MUST specify a packet code"); return RLM_MODULE_FAIL; } /* * Reserve Status-Server for ourselves, for link-specific * signaling. */ if (request->packet->code == FR_CODE_STATUS_SERVER) { REDEBUG("Cannot proxy Status-Server packets"); return RLM_MODULE_FAIL; } if ((request->packet->code >= FR_MAX_PACKET_CODE) || !inst->retry[request->packet->code].irt) { /* can't be zero */ REDEBUG("Invalid packet code %d", request->packet->code); return RLM_MODULE_FAIL; } if (!inst->allowed[request->packet->code]) { REDEBUG("Packet code %s is disallowed by the configuration", fr_packet_codes[request->packet->code]); return RLM_MODULE_FAIL; } if (request->client->dynamic && !request->client->active) { REDEBUG("Cannot proxy packets which define dynamic clients"); return RLM_MODULE_FAIL; } /* * The submodule needs to track it's own data associated * with the request. Allocate that here. Note that the * IO submodule has to set the destructor if it so wishes. */ request_io_ctx = talloc_zero_array(request, uint8_t, inst->io->request_inst_size); if (!request_io_ctx) { return RLM_MODULE_FAIL; } if (inst->io->request_inst_type) talloc_set_name_const(request_io_ctx, inst->io->request_inst_type); /* * Do any necessary RADIUS level fixups * - check Proxy-State * - do CHAP-Challenge fixups */ radius_fixups(inst, request); /* * Push the request and it's data to the IO submodule. * * This may return YIELD, for "please yield", or it may * return another code which indicates what happened to * the request...b */ rcode = inst->io->push(inst->io_instance, request, request_io_ctx, t->thread_io_ctx); if (rcode != RLM_MODULE_YIELD) { talloc_free(request_io_ctx); return rcode; } return unlang_module_yield(request, mod_radius_resume, mod_radius_signal, request_io_ctx); }