Пример #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 */
}
Пример #2
0
/** Find an existing module instance
 *
 * @param[in] modules		section in the main config.
 * @param[in] asked_name 	The name of the module we're attempting to find.
 *				May include '-' which indicates that it's ok for
 *				the module not to be loaded.
 * @return
 *	- Module instance matching name.
 *	- NULL if not such module exists.
 */
module_instance_t *module_find(CONF_SECTION *modules, char const *asked_name)
{
	char const *inst_name;
	void *inst;

	if (!modules) return NULL;

	/*
	 *	Look for the real name.  Ignore the first character,
	 *	which tells the server "it's OK for this module to not
	 *	exist."
	 */
	inst_name = asked_name;
	if (inst_name[0] == '-') inst_name++;

	inst = cf_data_value(cf_data_find(modules, module_instance_t, inst_name));
	if (!inst) return NULL;

	return talloc_get_type_abort(inst, module_instance_t);
}
Пример #3
0
/** Wrapper around dl_instance
 *
 * @param[in] ctx	to allocate data in (instance of proto_radius).
 * @param[out] out	Where to write a dl_instance_t containing the module handle and instance.
 * @param[in] parent	Base structure address.
 * @param[in] ci	#CONF_PAIR specifying the name of the type module.
 * @param[in] rule	unused.
 * @return
 *	- 0 on success.
 *	- -1 on failure.
 */
static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent,
			   CONF_ITEM *ci, UNUSED CONF_PARSER const *rule)
{
	char const	*name = cf_pair_value(cf_item_to_pair(ci));
	dl_instance_t	*parent_inst;
	CONF_SECTION	*cs = cf_item_to_section(cf_parent(ci));
	CONF_SECTION	*transport_cs;

	transport_cs = cf_section_find(cs, name, NULL);

	/*
	 *	Allocate an empty section if one doesn't exist
	 *	this is so defaults get parsed.
	 */
	if (!transport_cs) transport_cs = cf_section_alloc(cs, cs, name, NULL);

	parent_inst = cf_data_value(cf_data_find(cs, dl_instance_t, "rlm_radius"));
	rad_assert(parent_inst);

	return dl_instance(ctx, out, transport_cs, parent_inst, name, DL_TYPE_SUBMODULE);
}
Пример #4
0
/** Initialise a module specific connection pool
 *
 * @see fr_pool_init
 *
 * @param[in] module		section.
 * @param[in] opaque		data pointer to pass to callbacks.
 * @param[in] c			Callback to create new connections.
 * @param[in] a			Callback to check the status of connections.
 * @param[in] log_prefix	override, if NULL will be set automatically from the module CONF_SECTION.
 * @param[in] trigger_prefix	if NULL will be set automatically from the module CONF_SECTION.
 * @param[in] trigger_args	to make available in any triggers executed by the connection pool.
 * @return
 *	- New connection pool.
 *	- NULL on error.
 */
fr_pool_t *module_connection_pool_init(CONF_SECTION *module,
				       void *opaque,
				       fr_pool_connection_create_t c,
				       fr_pool_connection_alive_t a,
				       char const *log_prefix,
				       char const *trigger_prefix,
				       VALUE_PAIR *trigger_args)
{
	CONF_SECTION *cs, *mycs;
	char log_prefix_buff[128];
	char trigger_prefix_buff[128];

	fr_pool_t *pool;
	char const *cs_name1, *cs_name2;

	int ret;

#define parent_name(_x) cf_section_name(cf_item_to_section(cf_parent(_x)))

	cs_name1 = cf_section_name1(module);
	cs_name2 = cf_section_name2(module);
	if (!cs_name2) cs_name2 = cs_name1;

	if (!trigger_prefix) {
		snprintf(trigger_prefix_buff, sizeof(trigger_prefix_buff), "modules.%s.pool", cs_name1);
		trigger_prefix = trigger_prefix_buff;
	}

	if (!log_prefix) {
		snprintf(log_prefix_buff, sizeof(log_prefix_buff), "rlm_%s (%s)", cs_name1, cs_name2);
		log_prefix = log_prefix_buff;
	}

	/*
	 *	Get sibling's pool config section
	 */
	ret = module_sibling_section_find(&cs, module, "pool");
	switch (ret) {
	case -1:
		return NULL;

	case 1:
		DEBUG4("%s: Using pool section from \"%s\"", log_prefix, parent_name(cs));
		break;

	case 0:
		DEBUG4("%s: Using local pool section", log_prefix);
		break;
	}

	/*
	 *	Get our pool config section
	 */
	mycs = cf_section_find(module, "pool", NULL);
	if (!mycs) {
		DEBUG4("%s: Adding pool section to config item \"%s\" to store pool references", log_prefix,
		       cf_section_name(module));

		mycs = cf_section_alloc(module, module, "pool", NULL);
	}

	/*
	 *	Sibling didn't have a pool config section
	 *	Use our own local pool.
	 */
	if (!cs) {
		DEBUG4("%s: \"%s.pool\" section not found, using \"%s.pool\"", log_prefix,
		       parent_name(cs), parent_name(mycs));
		cs = mycs;
	}

	/*
	 *	If fr_pool_init has already been called
	 *	for this config section, reuse the previous instance.
	 *
	 *	This allows modules to pass in the config sections
	 *	they would like to use the connection pool from.
	 */
	pool = cf_data_value(cf_data_find(cs, fr_pool_t, NULL));
	if (!pool) {
		DEBUG4("%s: No pool reference found for config item \"%s.pool\"", log_prefix, parent_name(cs));
		pool = fr_pool_init(cs, cs, opaque, c, a, log_prefix);
		if (!pool) return NULL;

		fr_pool_enable_triggers(pool, trigger_prefix, trigger_args);

		if (fr_pool_start(pool) < 0) {
			ERROR("%s: Starting initial connections failed", log_prefix);
			return NULL;
		}

		DEBUG4("%s: Adding pool reference %p to config item \"%s.pool\"", log_prefix, pool, parent_name(cs));
		cf_data_add(cs, pool, NULL, false);
		return pool;
	}
	fr_pool_ref(pool);

	DEBUG4("%s: Found pool reference %p in config item \"%s.pool\"", log_prefix, pool, parent_name(cs));

	/*
	 *	We're reusing pool data add it to our local config
	 *	section. This allows other modules to transitively
	 *	re-use a pool through this module.
	 */
	if (mycs != cs) {
		DEBUG4("%s: Copying pool reference %p from config item \"%s.pool\" to config item \"%s.pool\"",
		       log_prefix, pool, parent_name(cs), parent_name(mycs));
		cf_data_add(mycs, pool, NULL, false);
	}

	return pool;
}
Пример #5
0
/** Allocate a #CONF_SECTION
 *
 * @param[in] ctx	to allocate
 * @param[in] parent	#CONF_SECTION to hang this #CONF_SECTION off of.
 *			If parent is not NULL, the new section will be added as a child.
 * @param[in] name1	Primary name.
 * @param[in] name2	Secondary name.
 * @param[in] filename	Caller file name for debugging.  May be overridden later.
 * @param[in] lineno	Caller line number for debugging.  May be overridden later.
 * @return
 *	- NULL on error.
 *	- A new #CONF_SECTION parented by parent.
 */
CONF_SECTION *_cf_section_alloc(TALLOC_CTX *ctx, CONF_SECTION *parent,
				char const *name1, char const *name2,
				char const *filename, int lineno)
{
	CONF_SECTION *cs;
	char buffer[1024];

	if (!name1) return NULL;

	if (name2 && parent) {
		char const *p;

		p = strchr(name2, '$');
		if (p && (p[1] != '{')) p = NULL;

		if (p) {
			name2 = cf_expand_variables(parent->item.filename,
						    &parent->item.lineno,
						    parent,
						    buffer, sizeof(buffer), name2, NULL);
			if (!name2) {
				ERROR("Failed expanding section name");
				return NULL;
			}
		}
	}

	cs = talloc_zero(ctx, CONF_SECTION);
	if (!cs) return NULL;

	cs->item.type = CONF_ITEM_SECTION;
	cs->item.parent = cf_section_to_item(parent);
	fr_cursor_init(&cs->item.cursor, &cs->item.child);

	MEM(cs->name1 = talloc_typed_strdup(cs, name1));
	if (name2) {
		MEM(cs->name2 = talloc_typed_strdup(cs, name2));
		cs->name2_quote = T_BARE_WORD;
	}
	talloc_set_destructor(cs, _cf_section_free);

	if (filename) cf_filename_set(cs, filename);
	if (lineno) cf_lineno_set(cs, lineno);

	if (parent) {
		CONF_DATA const *cd;
		CONF_PARSER *rule;

		cs->depth = parent->depth + 1;
		cf_item_add(parent, &(cs->item));

		cd = cf_data_find(CF_TO_ITEM(parent), CONF_PARSER, cf_section_name1(parent));
		if (cd) {
			rule = cf_data_value(cd);

			/*
			 *	The parent has an ON_READ rule.  Check
			 *	if that rule has a child which matches
			 *	this section.
			 */
			if ((FR_BASE_TYPE(rule->type) == FR_TYPE_SUBSECTION) &&
			    ((rule->type & FR_TYPE_ON_READ) != 0) &&
			    rule->subcs) {
				CONF_PARSER const *rule_p;

				for (rule_p = rule->subcs; rule_p->name; rule_p++) {
					if ((FR_BASE_TYPE(rule_p->type) == FR_TYPE_SUBSECTION) &&
					    ((rule_p->type & FR_TYPE_ON_READ) != 0) &&
					    (strcmp(rule_p->name, name1) == 0)) {
						(void) _cf_section_rule_push(cs, rule_p, cd->item.filename, cd->item.lineno);
						(void) rule_p->func(ctx, NULL, NULL, cf_section_to_item(cs), rule_p);
						return cs;
					}
				}
			}
		}

		/*
		 *	Call any ON_READ callback.  And push this rule
		 *	to the child section, so that the child can
		 *	pick it up.
		 */
		cd = cf_data_find(CF_TO_ITEM(parent), CONF_PARSER, name1);
		if (cd) {
			rule = cf_data_value(cd);
			if (rule->func &&
			    (FR_BASE_TYPE(rule->type) == FR_TYPE_SUBSECTION) &&
			    ((rule->type & FR_TYPE_ON_READ) != 0)) {
				(void) cf_section_rules_push(cs, rule);

				(void) rule->func(ctx, NULL, NULL, cf_section_to_item(cs), rule);
			}
		}
	}

	return cs;
}