Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
	char *start;
	xlat_exp_t *node;
#ifdef HAVE_REGEX
	long num;
#endif

	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);
	node->fmt = start = talloc_typed_strdup(node, fmt + 2);
	node->len = 0;

#ifdef HAVE_REGEX
	/*
	 *	Handle regex's specially.
	 */
	p = start;
	num = strtol(p, &q, 10);
	if (p != q && (*q == '}')) {
		XLAT_DEBUG("REGEX <-- %s", fmt);
		*q = '\0';

		if ((num > REQUEST_MAX_REGEX) || (num < 0)) {
			talloc_free(node);
			*error = "Invalid regex reference.  Must be in range 0-" STRINGIFY(REQUEST_MAX_REGEX);
			return -2;					/* error */
		}
		node->regex_index = num;

		node->type = XLAT_REGEX;
		*head = node;

		node->len = (q - start);
		MEM(start = talloc_realloc_bstr(start, node->len));
		q++;	/* Skip closing brace */

		return 2 + (q - start);
	}
#endif /* HAVE_REGEX */

	/*
	 *	%{Attr-Name}
	 *	%{Attr-Name[#]}
	 *	%{Tunnel-Password:1}
	 *	%{Tunnel-Password:1[#]}
	 *	%{request:Attr-Name}
	 *	%{request:Tunnel-Password:1}
	 *	%{request:Tunnel-Password:1[#]}
	 *	%{mod:foo}
	 */

	/*
	 *	This is for efficiency, so we don't search for an xlat,
	 *	when what's being referenced is obviously an attribute.
	 */
	p = start;
	for (q = p; *q != '\0'; q++) {
		if (*q == ':') break;

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

		if (*q == '[') continue;

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

	/*
	 *	Check for empty expressions %{}
	 */
	if ((*q == '}') && (q == p)) {
		talloc_free(node);
		*error = "Empty expression is invalid";
		return (-(p - start)) - 2;				/* error */
	}

	/*
	 *	Might be a module name reference.
	 *
	 *	If it's not, it's an attribute or parse error.
	 */
	if (*q == ':') {
		*q = '\0';
		node->xlat = xlat_func_find(node->fmt);
		if (node->xlat) {
			/*
			 *	%{mod:foo}
			 */
			node->type = XLAT_FUNC;

			p = q + 1;
			XLAT_DEBUG("MOD <-- %s ... %s", node->fmt, p);

			slen = xlat_tokenize_literal(node, p, &node->child, true, error);
			if (slen < 0) {
				talloc_free(node);
				return (slen - (p - start)) - 2;	/* error */
			}
			p += slen;

			node->async_safe = (node->xlat->async_safe && node->child->async_safe);
			*head = node;
			rad_assert(node->next == NULL);

			node->len = p - start;
			MEM(start = talloc_realloc_bstr(start, node->len));

			return 2 + node->len;
		}
		*q = ':';	/* Avoids a talloc_strdup */
	}

	/*
	 *	The first token ends with:
	 *	- '[' - Which is an attribute index, so it must be an attribute.
	 *      - '}' - The end of the expansion, which means it was a bareword.
	 */
	slen = tmpl_afrom_attr_substr(node, &node->attr, p,
				      &(vp_tmpl_rules_t){ .allow_undefined = true, .allow_unknown = true });