Exemplo n.º 1
0
/** Convert module specific attribute id to value_pair_tmpl_t.
 *
 * @param[in] ctx for talloc
 * @param[in] name string to convert.
 * @param[in] type Type of quoting around value.
 * @return pointer to new VPT.
 */
value_pair_tmpl_t *radius_str2tmpl(TALLOC_CTX *ctx, char const *name, FR_TOKEN type)
{
	value_pair_tmpl_t *vpt;

	vpt = talloc_zero(ctx, value_pair_tmpl_t);
	vpt->name = talloc_strdup(vpt, name);

	switch (type)
	{
		case T_BARE_WORD:
			if (!isdigit((int) *name)) {
				request_refs_t ref;
				pair_lists_t list;
				const char *p = name;

				ref = radius_request_name(&p, REQUEST_CURRENT);
				list = radius_list_name(&p, PAIR_LIST_REQUEST);

				if ((p != name) && !*p) {
					vpt->type = VPT_TYPE_LIST;

				} else {
					const DICT_ATTR *da;
					da = dict_attrbyname(p);
					if (!da) {
						vpt->type = VPT_TYPE_LITERAL;
						break;
					}
					vpt->da = da;
					vpt->type = VPT_TYPE_ATTR;
				}

				vpt->request = ref;
				vpt->list = list;
				break;
			}
			/* FALL-THROUGH */

		case T_SINGLE_QUOTED_STRING:
			vpt->type = VPT_TYPE_LITERAL;
			break;
		case T_DOUBLE_QUOTED_STRING:
			vpt->type = VPT_TYPE_XLAT;
			break;
		case T_BACK_QUOTED_STRING:
			vpt->type = VPT_TYPE_EXEC;
			break;
		case T_OP_REG_EQ: /* hack */
			vpt->type = VPT_TYPE_REGEX;
			break;
		default:
			rad_assert(0);
			return NULL;
	}

	return vpt;
}
Exemplo n.º 2
0
/** Parse qualifiers to convert attrname into a value_pair_tmpl_t.
 *
 * VPTs are used in various places where we need to pre-parse configuration 
 * sections into attribute mappings.
 *
 * Note: name field is just a copy of the input pointer, if you know that
 * string might be freed before you're done with the vpt use radius_attr2tmpl
 * instead.
 * 
 * @param[in] name attribute name including qualifiers.
 * @param[out] vpt to modify.
 * @param[in] request_def The default request to insert unqualified 
 *	attributes into.
 * @param[in] list_def The default list to insert unqualified attributes into.
 * @return -1 on error or 0 on success.
 */
int radius_parse_attr(const char *name, value_pair_tmpl_t *vpt,
		      request_refs_t request_def,
		      pair_lists_t list_def)
{
	char buffer[128];
	const char *p;
	size_t len;

	vpt->name = name;
	p = name;
	
	vpt->request = radius_request_name(&p, request_def);
	len = p - name;
	if (vpt->request == REQUEST_UNKNOWN) {
		strlcpy(buffer, name, len < sizeof(buffer) ?
			len + 1 : sizeof(buffer));
		
		radlog(L_ERR, "Invalid request qualifier \"%s\"", buffer);
		
		return -1;
	}
	name += len;
	
	vpt->list = radius_list_name(&p, list_def);
	if (vpt->list == PAIR_LIST_UNKNOWN) {
		len = p - name;
		strlcpy(buffer, name, len < sizeof(buffer) ?
			len + 1 : sizeof(buffer));
				
		radlog(L_ERR, "Invalid list qualifier \"%s\"", buffer);
		
		return -1;
	}
	
	if (*p == '\0') {
		vpt->type = VPT_TYPE_LIST;
		
		return 0;
	}
	
	vpt->da = dict_attrbyname(p);
	if (!vpt->da) {
		radlog(L_ERR, "Attribute \"%s\" unknown", p);
	
		return -1;
	}
	
	vpt->type = VPT_TYPE_ATTR;
	
	return 0;
}
Exemplo n.º 3
0
/** Convert a valuepair string to VALUE_PAIR and insert it into a list
 *
 * Takes a valuepair string with list and request qualifiers, converts it into a VALUE_PAIR
 * and inserts it into the appropriate list.
 *
 * @param request Current request.
 * @param raw string to parse.
 * @param request_def to use if attribute isn't qualified.
 * @param list_def to use if attribute isn't qualified.
 * @return 0 on success, -1 on error.
 */
int radius_str2vp(REQUEST *request, char const *raw, request_refs_t request_def, pair_lists_t list_def)
{
	char const *p;
	size_t len;
	request_refs_t req;
	pair_lists_t list;

	VALUE_PAIR *vp = NULL;
	VALUE_PAIR **vps;

	p = raw;

	req = radius_request_name(&p, request_def);
	len = p - raw;
	if (req == REQUEST_UNKNOWN) {
		REDEBUG("Invalid request qualifier \"%.*s\"", (int) len, raw);

		return -1;
	}
	raw += len;

	list = radius_list_name(&p, list_def);
	if (list == PAIR_LIST_UNKNOWN) {
		len = p - raw;

		REDEBUG("Invalid list qualifier \"%.*s\"", (int) len, raw);

		return -1;
	}
	raw += len;

	if (radius_request(&request, req) < 0) {
		return -1;
	}

	vps = radius_list(request, list);
	if (!vps) {
		return -1;
	}

	if (userparse(request, raw, &vp) == T_OP_INVALID) {
		return -1;
	}

	pairmove(request, vps, &vp);

	return 0;
}
Exemplo n.º 4
0
/** Parse qualifiers to convert attrname into a value_pair_tmpl_t.
 *
 * VPTs are used in various places where we need to pre-parse configuration
 * sections into attribute mappings.
 *
 * Note: name field is just a copy of the input pointer, if you know that
 * string might be freed before you're done with the vpt use radius_attr2tmpl
 * instead.
 *
 * @param[in] name attribute name including qualifiers.
 * @param[out] vpt to modify.
 * @param[in] request_def The default request to insert unqualified
 *	attributes into.
 * @param[in] list_def The default list to insert unqualified attributes into.
 * @return -1 on error or 0 on success.
 */
int radius_parse_attr(char const *name, value_pair_tmpl_t *vpt,
		      request_refs_t request_def,
		      pair_lists_t list_def)
{
	DICT_ATTR const *da;
	char const *p;
	size_t len;

	memset(vpt, 0, sizeof(*vpt));
	vpt->name = name;
	p = name;

	vpt->request = radius_request_name(&p, request_def);
	len = p - name;
	if (vpt->request == REQUEST_UNKNOWN) {
		ERROR("Invalid request qualifier \"%.*s\"", (int) len, name);
		return -1;
	}
	name += len;

	vpt->list = radius_list_name(&p, list_def);
	if (vpt->list == PAIR_LIST_UNKNOWN) {
		len = p - name;
		ERROR("Invalid list qualifier \"%.*s\"", (int) len, name);
		return -1;
	}

	if (*p == '\0') {
		vpt->type = VPT_TYPE_LIST;
		return 0;
	}

	da = dict_attrbyname(p);
	if (!da) {
		da = dict_attrunknownbyname(p, false);
		if (!da) {
			ERROR("Unknown attribute \"%s\"", p);
			return -1;
		}
	}
	vpt->da = da;

	vpt->type = VPT_TYPE_ATTR;
	return 0;
}
Exemplo n.º 5
0
/** Return a VP from the specified request.
 *
 * @param request current request.
 * @param name attribute name including qualifiers.
 * @param vp_p where to write the pointer to the resolved VP. 
 *	Will be NULL if the attribute couldn't be resolved.
 * @return False if either the attribute or qualifier were invalid, else true
 */
int radius_get_vp(REQUEST *request, const char *name, VALUE_PAIR **vp_p)
{
	VALUE_PAIR **vps;
	pair_lists_t list;
	
	const DICT_ATTR *da;
	
	*vp_p = NULL;
	
	if (!radius_ref_request(&request, &name)) {
		RDEBUG("WARNING: Attribute name refers to outer request"
		       " but not in a tunnel.");
		return TRUE;	/* Discuss, we don't actually know if
				   the attrname was valid... */
	}
	
	list = radius_list_name(&name, PAIR_LIST_REQUEST);
	if (list == PAIR_LIST_UNKNOWN) {
		RDEBUG("ERROR: Invalid list qualifier");
		return FALSE;
	}
	
	da = dict_attrbyname(name);
	if (!da) {
		RDEBUG("ERROR: Attribute \"%s\" unknown", name);
		return FALSE;
	}

	vps = radius_list(request, list);
	rad_assert(vps);
	
	/*
	 *	May not may not be found, but it *is* a known name.
	 */
	*vp_p = pairfind(*vps, da->attr, da->vendor);
	return TRUE;
}
Exemplo n.º 6
0
/*
 *	Allow single attribute values to be retrieved from the cache.
 */
static ssize_t cache_xlat(void *instance, REQUEST *request,
			  char const *fmt, char *out, size_t freespace)
{
	rlm_cache_entry_t 	*c;
	rlm_cache_t		*inst = instance;
	rlm_cache_handle_t	*handle;

	VALUE_PAIR		*vp, *vps;
	pair_lists_t		list;
	DICT_ATTR const		*target;
	char const		*p = fmt;
	size_t			len;
	int			ret = 0;

	list = radius_list_name(&p, PAIR_LIST_REQUEST);

	target = dict_attrbyname(p);
	if (!target) {
		REDEBUG("Unknown attribute \"%s\"", p);
		return -1;
	}

	if (cache_acquire(&handle, inst, request) < 0) return -1;

	switch (cache_find(&c, inst, request, handle, fmt)) {
	case RLM_MODULE_OK:		/* found */
		break;

	case RLM_MODULE_NOTFOUND:	/* not found */
		*out = '\0';
		return 0;

	default:
		return -1;
	}

	switch (list) {
	case PAIR_LIST_REQUEST:
		vps = c->packet;
		break;

	case PAIR_LIST_REPLY:
		vps = c->reply;
		break;

	case PAIR_LIST_CONTROL:
		vps = c->control;
		break;

	case PAIR_LIST_UNKNOWN:
		REDEBUG("Unknown list qualifier in \"%s\"", fmt);
		ret = -1;
		goto finish;

	default:
		REDEBUG("Unsupported list \"%s\"", fr_int2str(pair_lists, list, "<UNKNOWN>"));
		ret = -1;
		goto finish;
	}

	vp = pairfind(vps, target->attr, target->vendor, TAG_ANY);
	if (!vp) {
		RDEBUG("No instance of this attribute has been cached");
		*out = '\0';
		goto finish;
	}

	len = vp_prints_value(out, freespace, vp, 0);
	if (is_truncated(len, freespace)) {
		REDEBUG("Insufficient buffer space to write cached value");
		ret = -1;
		goto finish;
	}

finish:
	cache_free(inst, &c);
	cache_release(inst, request, &handle);

	return ret;
}
Exemplo n.º 7
0
static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
				       char const **error)
{
	ssize_t slen;
	char *p, *q, *brace;
	char const *attrname;
	xlat_exp_t *node;

	rad_assert(fmt[0] == '%');
	rad_assert(fmt[1] == '{');

	/*
	 *	%{%{...}:-bar}
	 */
	if ((fmt[2] == '%') && (fmt[3] == '{')) {
		return xlat_tokenize_alternation(ctx, fmt, head, error);
	}

	XLAT_DEBUG("EXPANSION: %s", fmt);
	node = talloc_zero(ctx, xlat_exp_t);
	attrname = node->fmt = fmt + 2;
	node->len = 0;

#ifdef HAVE_REGEX_H
	/*
	 *	Handle regex's specially.
	 */
	if (isdigit((int) fmt[2]) && (fmt[3] == '}')) {
		if (fmt[2] == '9') {
			talloc_free(node);
			*error = "Invalid regex reference";
			return -2;
		}

		XLAT_DEBUG("REGEX: %s", fmt);
		fmt[3] = '\0';
		node->num = fmt[2] - '0'; /* ASCII */

		node->type = XLAT_REGEX;
		*head = node;
		return 4;
	}
#endif /* HAVE_REGEX_H */

	/*
	 *	%{Attr-Name}
	 *	%{Attr-Name[#]}
	 *	%{Tunnel-Password:1}
	 *	%{Tunnel-Password:1[#]}
	 *	%{request:Attr-Name}
	 *	%{request:Tunnel-Password:1}
	 *	%{request:Tunnel-Password:1[#]}
	 *	%{mod:foo}
	 */
	q = brace = NULL;
	for (p = fmt + 2; *p != '\0'; p++) {
		if (*p == ':') break;

		if (isspace((int) *p)) break;

		if (*p == '[') break;

		if (*p == '}') break;
	}

	if (*p != ':') p = NULL;

	/*
	 *	Might be a module name reference.
	 */
	if (p) {
		*p = '\0';

		/*
		 *	%{mod:foo}
		 */
		node->xlat = xlat_find(node->fmt);
		if (node->xlat) {
			node->type = XLAT_MODULE;

			XLAT_DEBUG("MOD: %s --> %s", node->fmt, p);
			slen = xlat_tokenize_literal(node, p + 1, &node->child, true, error);
			if (slen <= 0) {
				talloc_free(node);
				return slen - (p - fmt);
			}
			p += slen + 1;

			*head = node;
			rad_assert(node->next == NULL);
			return p - fmt;
		}

		/*
		 *	Modules can have '}' in their RHS, so we
		 *	didn't check for that until now.
		 *
		 *	As of now, node->fmt MUST be a reference to an
		 *	attribute, however complicated.  So it MUST have a closing brace.
		 */
		brace = strchr(p + 1, '}');
		if (!brace) goto no_brace;
		*brace = '\0';

		/*
		 *	%{User-Name}
		 *	%{User-Name[1]}
		 *	%{Tunnel-Password:1}
		 *	%{request:Tunnel-Password:1}
		 *
		 *	<sigh>  The syntax is fairly poor.
		 */
		XLAT_DEBUG("Looking for list in '%s'", attrname);

		/*
		 *	Not a module.  Has to be an attribute
		 *	reference.
		 *
		 *	As of v3, we've removed %{request: ..>} as
		 *	internally registered xlats.
		 */
		*p = ':';
		node->ref = radius_request_name(&attrname, REQUEST_CURRENT);
		rad_assert(node->ref != REQUEST_UNKNOWN);

		node->list = radius_list_name(&attrname, PAIR_LIST_REQUEST);
		if (node->list == PAIR_LIST_UNKNOWN) {
			talloc_free(node);
			*error = "Unknown module";
			return -2;
		}

		/*
		 *	Check for a trailing tag.
		 */
		p = strchr(attrname, ':');
		if (p) *p = '\0';

	} else {
		brace = strchr(attrname, '}');
		if (!brace) {
		no_brace:
			talloc_free(node);
			*error = "No matching closing brace";
			return -1;	/* second character of format string */
		}
		*brace = '\0';

		node->ref = REQUEST_CURRENT;
		node->list = PAIR_LIST_REQUEST;
	}

	*brace = '\0';

	XLAT_DEBUG("Looking for attribute name in %s", attrname);

	/*
	 *	Allow for an array reference.  They come AFTER the
	 *	tag, if the tag exists.  Otherwise, they come after
	 *	the attribute name.
	 */
	if (p) {
		q = strchr(p + 1, '[');
	} else {
		q = strchr(attrname, '[');
	}
	if (q) *(q++) = '\0';

	if (!*attrname) {
		talloc_free(node);
		*error = "Empty expression is invalid";
		return -(attrname - fmt);
	}

	/*
	 *	It's either an attribute name, or a Tunnel-Password:TAG
	 *	with the ':' already set to NULL.
	 */
	node->da = dict_attrbyname(attrname);
	if (!node->da) {
		/*
		 *	Foreach.  Maybe other stuff, too.
		 */
		node->xlat = xlat_find(attrname);
		if (node->xlat) {
			node->type = XLAT_VIRTUAL;
			node->fmt = attrname;

			XLAT_DEBUG("VIRTUAL: %s", node->fmt);
			*head = node;
			rad_assert(node->next == NULL);
			brace++;
			return brace - fmt;
		}

		talloc_free(node);
		*error = "Unknown attribute";
		return -(attrname - fmt);
	}

	/*
	 *	Parse the tag.
	 */
	if (p) {
		unsigned long tag;
		char *end;

		if (!node->da->flags.has_tag) {
			talloc_free(node);
			*error = "Attribute cannot have a tag";
			return - (p - fmt);
		}

		tag = strtoul(p + 1, &end, 10);
		p++;

		if (tag == ULONG_MAX) {
			talloc_free(node);
			*error = "Invalid tag value";
			return - (p - fmt);
		}

		node->tag = tag;
		p = end;

		if (*p) {
			talloc_free(node);
			*error = "Unexpected text after tag";
			return - (p - fmt);
		}

	} else {
		node->tag = TAG_ANY;
		/* leave p alone */
	}

	/*
	 *	Check for array reference
	 */
	if (q) {
		unsigned long num;
		char *end;

		p = q;
		if (*p== '#') {
			node->num = 65536;
			p++;

		} else if (*p == '*') {
			node->num = 65537;
			p++;

		} else if (isdigit((int) *p)) {
			num = strtoul(p, &end, 10);
			if ((num == ULONG_MAX) || (num > 65535)) {
				talloc_free(node);
				*error = "Invalid number";
				return - (p - fmt);
			}
			p = end;
			DEBUG("END %s", p);
			node->num = num;

		} else {
			talloc_free(node);
			*error = "Invalid array reference";
			return - (p - fmt);
		}

		if (*p != ']') {
			talloc_free(node);
			*error = "Expected ']'";
			return - (p - fmt);
		}

		p++;
		if (*p) {
			talloc_free(node);
			*error = "Unexpected text after array reference";
			return - (p - fmt);
		}
	}

	rad_assert(!p || (p == brace));

	node->type = XLAT_ATTRIBUTE;
	p = brace + 1;

	*head = node;
	rad_assert(node->next == NULL);
	return p - fmt;
}
Exemplo n.º 8
0
/*
 *	Do any per-module initialization that is separate to each
 *	configured instance of the module.  e.g. set up connections
 *	to external databases, read configuration files, set up
 *	dictionary entries, etc.
 *
 *	If configuration information is given in the config section
 *	that must be referenced in later calls, store a handle to it
 *	in *instance otherwise put a null pointer there.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	char const *p;
	rlm_exec_t	*inst = instance;

	inst->xlat_name = cf_section_name2(conf);
	if (!inst->xlat_name) {
		inst->xlat_name = cf_section_name1(conf);
		inst->bare = 1;
	}

	xlat_register(inst->xlat_name, exec_xlat, rlm_exec_shell_escape, inst);

	if (inst->input) {
		p = inst->input;
		inst->input_list = radius_list_name(&p, PAIR_LIST_UNKNOWN);
		if ((inst->input_list == PAIR_LIST_UNKNOWN) || (*p != '\0')) {
			cf_log_err_cs(conf, "Invalid input list '%s'", inst->input);
			return -1;
		}
	}

	if (inst->output) {
		p = inst->output;
		inst->output_list = radius_list_name(&p, PAIR_LIST_UNKNOWN);
		if ((inst->output_list == PAIR_LIST_UNKNOWN) || (*p != '\0')) {
			cf_log_err_cs(conf, "Invalid output list '%s'", inst->output);
			return -1;
		}
	}

	/*
	 *	Sanity check the config.  If we're told to NOT wait,
	 *	then the output pairs must not be defined.
	 */
	if (!inst->wait &&
	    (inst->output != NULL)) {
		cf_log_err_cs(conf, "Cannot read output pairs if wait = no");
		return -1;
	}

	/*
	 *	Get the packet type on which to execute
	 */
	if (!inst->packet_type) {
		inst->packet_code = 0;
	} else {
		DICT_VALUE	*dval;

		dval = dict_valbyname(PW_PACKET_TYPE, 0, inst->packet_type);
		if (!dval) {
			cf_log_err_cs(conf, "Unknown packet type %s: See list of VALUEs for Packet-Type in "
				      "share/dictionary", inst->packet_type);
			return -1;
		}
		inst->packet_code = dval->value;
	}

	/*
	 *	Get the time to wait before killing the child
	 */
	if (!inst->timeout) {
		inst->timeout = EXEC_TIMEOUT;
	}
	if (inst->timeout < 1) {
		cf_log_err_cs(conf, "Timeout '%d' is too small (minimum: 1)", inst->timeout);
		return -1;
	}
	/*
	 *	Blocking a request longer than 30 seconds isn't going to help anyone.
	 */
	if (inst->timeout > 30) {
		cf_log_err_cs(conf, "Timeout '%d' is too large (maximum: 30)", inst->timeout);
		return -1;
	}

	return 0;
}
Exemplo n.º 9
0
/** Parse qualifiers to convert attrname into a value_pair_tmpl_t.
 *
 * VPTs are used in various places where we need to pre-parse configuration
 * sections into attribute mappings.
 *
 * Note: name field is just a copy of the input pointer, if you know that
 * string might be freed before you're done with the vpt use radius_attr2tmpl
 * instead.
 *
 * The special return code of -2 is used only by radius_str2tmpl, which allow
 * bare words which might (or might not) be an attribute reference.
 *
 * @param[out] vpt to modify.
 * @param[in] name attribute name including qualifiers.
 * @param[in] request_def The default request to insert unqualified attributes into.
 * @param[in] list_def The default list to insert unqualified attributes into.
 * @return -2 on partial parse followed by error, -1 on other error, or 0 on success
 */
int radius_parse_attr(value_pair_tmpl_t *vpt, char const *name, request_refs_t request_def, pair_lists_t list_def)
{
	int error = -1;
	char const *p;
	size_t len;
	unsigned long num;
	char *q;
	DICT_ATTR const *da;

	memset(vpt, 0, sizeof(*vpt));
	vpt->name = name;
	p = name;

	if (*p == '&') {
		error = -2;
		p++;
	}

	vpt->vpt_request = radius_request_name(&p, request_def);
	len = p - name;
	if (vpt->vpt_request == REQUEST_UNKNOWN) {
		fr_strerror_printf("Invalid request qualifier \"%.*s\"", (int) len, name);
		return error;
	}
	name += len;

	vpt->vpt_list = radius_list_name(&p, list_def);
	if (vpt->vpt_list == PAIR_LIST_UNKNOWN) {
		len = p - name;
		fr_strerror_printf("Invalid list qualifier \"%.*s\"", (int) len, name);
		return error;
	}

	if (*p == '\0') {
		vpt->type = VPT_TYPE_LIST;
		return 0;
	}

	da = dict_attrbytagged_name(p);
	if (!da) {
		da = dict_attrunknownbyname(p, false);
		if (!da) {
			fr_strerror_printf("Unknown attribute \"%s\"", p);
			return error;
		}
	}
	vpt->vpt_da = da;
	vpt->type = VPT_TYPE_ATTR;
	vpt->vpt_tag = TAG_ANY;
	vpt->vpt_num = NUM_ANY;

	/*
	 *	After this point, we return -2 to indicate that parts
	 *	of the string were parsed as an attribute, but others
	 *	weren't.
	 */
	while (*p) {
		if (*p == ':') break;
		if (*p == '[') break;
		p++;
	}

	if (*p == ':') {
		if (!da->flags.has_tag) {
			fr_strerror_printf("Attribute '%s' cannot have a tag", da->name);
			return -2;
		}

		num = strtoul(p + 1, &q, 10);
		if (num > 0x1f) {
			fr_strerror_printf("Invalid tag value '%u' (should be between 0-31)", (unsigned int) num);
			return -2;
		}

		vpt->vpt_tag = num;
		p = q;
	}

	if (!*p) return 0;

	if (*p != '[') {
		fr_strerror_printf("Unexpected text after tag in '%s'", name);
		return -2;
	}

	num = strtoul(p + 1, &q, 10);
	if (num > 1000) {
		fr_strerror_printf("Invalid array reference '%u' (should be between 0-1000)", (unsigned int) num);
		return -2;
	}

	if ((*q != ']') || (q[1] != '\0')) {
		fr_strerror_printf("Unexpected text after array in '%s'", name);
		return -2;
	}

	vpt->vpt_num = num;

	return 0;
}
Exemplo n.º 10
0
/*
 *	Do any per-module initialization that is separate to each
 *	configured instance of the module.  e.g. set up connections
 *	to external databases, read configuration files, set up
 *	dictionary entries, etc.
 *
 *	If configuration information is given in the config section
 *	that must be referenced in later calls, store a handle to it
 *	in *instance otherwise put a null pointer there.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	char const *p;
	rlm_exec_t	*inst = instance;

	inst->xlat_name = cf_section_name2(conf);
	if (!inst->xlat_name) {
		inst->xlat_name = cf_section_name1(conf);
		inst->bare = 1;
	}

	xlat_register(inst->xlat_name, exec_xlat, rlm_exec_shell_escape, inst);
	
	/*
	 *	Check whether program actually exists
	 */
	
	if (inst->input) {
		p = inst->input;
		inst->input_list = radius_list_name(&p, PAIR_LIST_UNKNOWN);
		if ((inst->input_list == PAIR_LIST_UNKNOWN) || (*p != '\0')) {
			cf_log_err_cs(conf, "Invalid input list '%s'", inst->input);
			return -1;
		}
	}

	if (inst->output) {
		p = inst->output;
		inst->output_list = radius_list_name(&p, PAIR_LIST_UNKNOWN);
		if ((inst->output_list == PAIR_LIST_UNKNOWN) || (*p != '\0')) {
			cf_log_err_cs(conf, "Invalid output list '%s'", inst->output);
			return -1;
		}
	}

	/*
	 *	Sanity check the config.  If we're told to NOT wait,
	 *	then the output pairs must not be defined.
	 */
	if (!inst->wait &&
	    (inst->output != NULL)) {
		cf_log_err_cs(conf, "Cannot read output pairs if wait = no");
		return -1;
	}

	/*
	 *	Get the packet type on which to execute
	 */
	if (!inst->packet_type) {
		inst->packet_code = 0;
	} else {
		DICT_VALUE	*dval;

		dval = dict_valbyname(PW_PACKET_TYPE, 0, inst->packet_type);
		if (!dval) {
			cf_log_err_cs(conf, "Unknown packet type %s: See list of VALUEs for Packet-Type in "
				      "share/dictionary", inst->packet_type);
			return -1;
		}
		inst->packet_code = dval->value;
	}

	return 0;
}