Esempio n. 1
0
/** 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 */
}
Esempio n. 2
0
/** 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 */
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
/** 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);
}