1 /*
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 998751f9db377a0f6397b8c56e6abef4af69a620 $
19  *
20  * @file xlat.c
21  * @brief String expansion ("translation"). Implements %Attribute -> value
22  *
23  * @copyright 2000,2006  The FreeRADIUS server project
24  * @copyright 2000  Alan DeKok <aland@ox.org>
25  */
26 
27 RCSID("$Id: 998751f9db377a0f6397b8c56e6abef4af69a620 $")
28 
29 #include <freeradius-devel/radiusd.h>
30 #include <freeradius-devel/parser.h>
31 #include <freeradius-devel/rad_assert.h>
32 #include <freeradius-devel/base64.h>
33 
34 #include <ctype.h>
35 
36 typedef struct xlat_t {
37 	char			name[MAX_STRING_LEN];	//!< Name of the xlat expansion.
38 	int			length;			//!< Length of name.
39 	void			*instance;		//!< Module instance passed to xlat and escape functions.
40 	xlat_func_t		func;			//!< xlat function.
41 	xlat_escape_t	escape;			//!< Escape function to apply to dynamic input to func.
42 	bool			internal;		//!< If true, cannot be redefined.
43 } xlat_t;
44 
45 typedef enum {
46 	XLAT_LITERAL,		//!< Literal string
47 	XLAT_PERCENT,		//!< Literal string with %v
48 	XLAT_MODULE,		//!< xlat module
49 	XLAT_VIRTUAL,		//!< virtual attribute
50 	XLAT_ATTRIBUTE,		//!< xlat attribute
51 #ifdef HAVE_REGEX
52 	XLAT_REGEX,		//!< regex reference
53 #endif
54 	XLAT_ALTERNATE		//!< xlat conditional syntax :-
55 } xlat_state_t;
56 
57 struct xlat_exp {
58 	char const *fmt;	//!< The format string.
59 	size_t len;		//!< Length of the format string.
60 
61 	xlat_state_t type;	//!< type of this expansion.
62 	xlat_exp_t *next;	//!< Next in the list.
63 
64 	xlat_exp_t *child;	//!< Nested expansion.
65 	xlat_exp_t *alternate;	//!< Alternative expansion if this one expanded to a zero length string.
66 
67 	vp_tmpl_t attr;	//!< An attribute template.
68 	xlat_t const *xlat;	//!< The xlat expansion to expand format with.
69 };
70 
71 static rbtree_t *xlat_root = NULL;
72 
73 #ifdef WITH_UNLANG
74 static char const * const xlat_foreach_names[] = {"Foreach-Variable-0",
75 						  "Foreach-Variable-1",
76 						  "Foreach-Variable-2",
77 						  "Foreach-Variable-3",
78 						  "Foreach-Variable-4",
79 						  "Foreach-Variable-5",
80 						  "Foreach-Variable-6",
81 						  "Foreach-Variable-7",
82 						  "Foreach-Variable-8",
83 						  "Foreach-Variable-9",
84 						  NULL};
85 #endif
86 
87 
88 static int xlat_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };	/* up to 10 for foreach */
89 
90 /** Print length of its RHS.
91  *
92  */
xlat_strlen(UNUSED void * instance,UNUSED REQUEST * request,char const * fmt,char * out,size_t outlen)93 static ssize_t xlat_strlen(UNUSED void *instance, UNUSED REQUEST *request,
94 			   char const *fmt, char *out, size_t outlen)
95 {
96 	snprintf(out, outlen, "%u", (unsigned int) strlen(fmt));
97 	return strlen(out);
98 }
99 
100 /** Print the size of the attribute in bytes.
101  *
102  */
xlat_length(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)103 static ssize_t xlat_length(UNUSED void *instance, REQUEST *request,
104 			   char const *fmt, char *out, size_t outlen)
105 {
106 	VALUE_PAIR *vp;
107 	while (isspace((int) *fmt)) fmt++;
108 
109 	if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
110 		*out = '\0';
111 		return 0;
112 	}
113 
114 	snprintf(out, outlen, "%zu", vp->vp_length);
115 	return strlen(out);
116 }
117 
118 /** Print data as integer, not as VALUE.
119  *
120  */
xlat_integer(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)121 static ssize_t xlat_integer(UNUSED void *instance, REQUEST *request,
122 			    char const *fmt, char *out, size_t outlen)
123 {
124 	VALUE_PAIR 	*vp;
125 
126 	uint64_t 	int64 = 0;	/* Needs to be initialised to zero */
127 	uint32_t	int32 = 0;	/* Needs to be initialised to zero */
128 
129 	while (isspace((int) *fmt)) fmt++;
130 
131 	if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
132 		*out = '\0';
133 		return 0;
134 	}
135 
136 	switch (vp->da->type) {
137 	case PW_TYPE_OCTETS:
138 	case PW_TYPE_STRING:
139 		if (vp->vp_length > 8) {
140 			break;
141 		}
142 
143 		if (vp->vp_length > 4) {
144 			memcpy(&int64, vp->vp_octets, vp->vp_length);
145 			return snprintf(out, outlen, "%" PRIu64, htonll(int64));
146 		}
147 
148 		memcpy(&int32, vp->vp_octets, vp->vp_length);
149 		return snprintf(out, outlen, "%i", htonl(int32));
150 
151 	case PW_TYPE_INTEGER64:
152 		return snprintf(out, outlen, "%" PRIu64, vp->vp_integer64);
153 
154 	/*
155 	 *	IP addresses are treated specially, as parsing functions assume the value
156 	 *	is bigendian and will convert it for us.
157 	 */
158 	case PW_TYPE_IPV4_ADDR:
159 		return snprintf(out, outlen, "%u", htonl(vp->vp_ipaddr));
160 
161 	case PW_TYPE_IPV4_PREFIX:
162 		return snprintf(out, outlen, "%u", htonl((*(uint32_t *)(vp->vp_ipv4prefix + 2))));
163 
164 	case PW_TYPE_INTEGER:
165 		return snprintf(out, outlen, "%u", vp->vp_integer);
166 
167 	case PW_TYPE_DATE:
168 		return snprintf(out, outlen, "%u", vp->vp_date);
169 
170 	case PW_TYPE_BYTE:
171 		return snprintf(out, outlen, "%u", (unsigned int) vp->vp_byte);
172 
173 	case PW_TYPE_SHORT:
174 		return snprintf(out, outlen, "%u", (unsigned int) vp->vp_short);
175 
176 	/*
177 	 *	Ethernet is weird... It's network related, so we assume to it should be
178 	 *	bigendian.
179 	 */
180 	case PW_TYPE_ETHERNET:
181 		memcpy(&int64, vp->vp_ether, vp->vp_length);
182 		return snprintf(out, outlen, "%" PRIu64, htonll(int64));
183 
184 	case PW_TYPE_SIGNED:
185 		return snprintf(out, outlen, "%i", vp->vp_signed);
186 
187 	case PW_TYPE_IPV6_ADDR:
188 		return fr_prints_uint128(out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6addr));
189 
190 	case PW_TYPE_IPV6_PREFIX:
191 		return fr_prints_uint128(out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6prefix[2]));
192 
193 	default:
194 		break;
195 	}
196 
197 	REDEBUG("Type '%s' of length %zu cannot be converted to integer",
198 		fr_int2str(dict_attr_types, vp->da->type, "???"), vp->vp_length);
199 	*out = '\0';
200 
201 	return -1;
202 }
203 
204 /** Print data as hex, not as VALUE.
205  *
206  */
xlat_hex(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)207 static ssize_t xlat_hex(UNUSED void *instance, REQUEST *request,
208 			char const *fmt, char *out, size_t outlen)
209 {
210 	size_t i;
211 	VALUE_PAIR *vp;
212 	uint8_t const *p;
213 	ssize_t	ret;
214 	size_t	len;
215 	value_data_t dst;
216 	uint8_t const *buff = NULL;
217 
218 	while (isspace((int) *fmt)) fmt++;
219 
220 	if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
221 	error:
222 		*out = '\0';
223 		return -1;
224 	}
225 
226 	/*
227 	 *	The easy case.
228 	 */
229 	if (vp->da->type == PW_TYPE_OCTETS) {
230 		p = vp->vp_octets;
231 		len = vp->vp_length;
232 	/*
233 	 *	Cast the value_data_t of the VP to an octets string and
234 	 *	print that as hex.
235 	 */
236 	} else {
237 		ret = value_data_cast(request, &dst, PW_TYPE_OCTETS, NULL, vp->da->type,
238 				      NULL, &vp->data, vp->vp_length);
239 		if (ret < 0) {
240 			REDEBUG("%s", fr_strerror());
241 			goto error;
242 		}
243 		len = (size_t) ret;
244 		p = buff = dst.octets;
245 	}
246 
247 	rad_assert(p);
248 
249 	/*
250 	 *	Don't truncate the data.
251 	 */
252 	if (outlen < (len * 2)) {
253 		rad_const_free(buff);
254 		goto error;
255 	}
256 
257 	for (i = 0; i < len; i++) {
258 		snprintf(out + 2*i, 3, "%02x", p[i]);
259 	}
260 	rad_const_free(buff);
261 
262 	return len * 2;
263 }
264 
265 /** Return the tag of an attribute reference
266  *
267  */
xlat_tag(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)268 static ssize_t xlat_tag(UNUSED void *instance, REQUEST *request,
269 		        char const *fmt, char *out, size_t outlen)
270 {
271 	VALUE_PAIR *vp;
272 
273 	while (isspace((int) *fmt)) fmt++;
274 
275 	if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
276 		*out = '\0';
277 		return 0;
278 	}
279 
280 	if (!vp->da->flags.has_tag || !TAG_VALID(vp->tag)) {
281 		*out = '\0';
282 		return 0;
283 	}
284 
285 	return snprintf(out, outlen, "%u", vp->tag);
286 }
287 
288 /** Return the vendor of an attribute reference
289  *
290  */
xlat_vendor(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)291 static ssize_t xlat_vendor(UNUSED void *instance, REQUEST *request,
292 		           char const *fmt, char *out, size_t outlen)
293 {
294 	VALUE_PAIR *vp;
295 	DICT_VENDOR *vendor;
296 
297 	while (isspace((int) *fmt)) fmt++;
298 
299 	if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
300 		*out = '\0';
301 		return 0;
302 	}
303 
304 	vendor = dict_vendorbyvalue(vp->da->vendor);
305 	if (!vendor) {
306 		*out = '\0';
307 		return 0;
308 	}
309 	strlcpy(out, vendor->name, outlen);
310 
311 	return vendor->length;
312 }
313 
314 /** Return the vendor number of an attribute reference
315  *
316  */
xlat_vendor_num(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)317 static ssize_t xlat_vendor_num(UNUSED void *instance, REQUEST *request,
318 		               char const *fmt, char *out, size_t outlen)
319 {
320 	VALUE_PAIR *vp;
321 
322 	while (isspace((int) *fmt)) fmt++;
323 
324 	if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
325 		*out = '\0';
326 		return 0;
327 	}
328 
329 	return snprintf(out, outlen, "%u", vp->da->vendor);
330 }
331 
332 /** Return the attribute name of an attribute reference
333  *
334  */
xlat_attr(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)335 static ssize_t xlat_attr(UNUSED void *instance, REQUEST *request,
336 			 char const *fmt, char *out, size_t outlen)
337 {
338 	VALUE_PAIR *vp;
339 
340 	while (isspace((int) *fmt)) fmt++;
341 
342 	if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
343 		*out = '\0';
344 		return 0;
345 	}
346 	strlcpy(out, vp->da->name, outlen);
347 
348 	return strlen(vp->da->name);
349 }
350 
351 /** Return the attribute number of an attribute reference
352  *
353  */
xlat_attr_num(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)354 static ssize_t xlat_attr_num(UNUSED void *instance, REQUEST *request,
355 		             char const *fmt, char *out, size_t outlen)
356 {
357 	VALUE_PAIR *vp;
358 
359 	while (isspace((int) *fmt)) fmt++;
360 
361 	if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
362 		*out = '\0';
363 		return 0;
364 	}
365 
366 	return snprintf(out, outlen, "%u", vp->da->attr);
367 }
368 
369 /** Print out attribute info
370  *
371  * Prints out all instances of a current attribute, or all attributes in a list.
372  *
373  * At higher debugging levels, also prints out alternative decodings of the same
374  * value. This is helpful to determine types for unknown attributes of long
375  * passed vendors, or just crazy/broken NAS.
376  *
377  * This expands to a zero length string.
378  */
xlat_debug_attr(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,UNUSED size_t outlen)379 static ssize_t xlat_debug_attr(UNUSED void *instance, REQUEST *request, char const *fmt,
380 			       char *out, UNUSED size_t outlen)
381 {
382 	VALUE_PAIR *vp;
383 	vp_cursor_t cursor;
384 
385 	vp_tmpl_t vpt;
386 
387 	if (!RDEBUG_ENABLED2) {
388 		*out = '\0';
389 		return -1;
390 	}
391 
392 	while (isspace((int) *fmt)) fmt++;
393 
394 	if (tmpl_from_attr_str(&vpt, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
395 		RDEBUG("%s", fr_strerror());
396 		return -1;
397 	}
398 
399 	RIDEBUG("Attributes matching \"%s\"", fmt);
400 
401 	RINDENT();
402 	for (vp = tmpl_cursor_init(NULL, &cursor, request, &vpt);
403 	     vp;
404 	     vp = tmpl_cursor_next(&cursor, &vpt)) {
405 		FR_NAME_NUMBER const *type;
406 		char *value;
407 
408 		value = vp_aprints_value(vp, vp, '\'');
409 		if (vp->da->flags.has_tag) {
410 			RIDEBUG2("&%s:%s:%i %s %s",
411 				fr_int2str(pair_lists, vpt.tmpl_list, "<INVALID>"),
412 				vp->da->name,
413 				vp->tag,
414 				fr_int2str(fr_tokens, vp->op, "<INVALID>"),
415 				value);
416 		} else {
417 			RIDEBUG2("&%s:%s %s %s",
418 				fr_int2str(pair_lists, vpt.tmpl_list, "<INVALID>"),
419 				vp->da->name,
420 				fr_int2str(fr_tokens, vp->op, "<INVALID>"),
421 				value);
422 		}
423 		talloc_free(value);
424 
425 		if (!RDEBUG_ENABLED3) continue;
426 
427 		if (vp->da->vendor) {
428 			DICT_VENDOR *dv;
429 
430 			dv = dict_vendorbyvalue(vp->da->vendor);
431 			RIDEBUG2("Vendor : %i (%s)", vp->da->vendor, dv ? dv->name : "unknown");
432 		}
433 		RIDEBUG2("Type   : %s", fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"));
434 		RIDEBUG2("Length : %zu", vp->vp_length);
435 
436 		if (!RDEBUG_ENABLED4) continue;
437 
438 		type = dict_attr_types;
439 		while (type->name) {
440 			int pad;
441 
442 			value_data_t *dst = NULL;
443 
444 			ssize_t ret;
445 
446 			if ((PW_TYPE) type->number == vp->da->type) {
447 				goto next_type;
448 			}
449 
450 			switch (type->number) {
451 			case PW_TYPE_INVALID:		/* Not real type */
452 			case PW_TYPE_MAX:		/* Not real type */
453 			case PW_TYPE_EXTENDED:		/* Not safe/appropriate */
454 			case PW_TYPE_LONG_EXTENDED:	/* Not safe/appropriate */
455 			case PW_TYPE_TLV:		/* Not safe/appropriate */
456 			case PW_TYPE_EVS:		/* Not safe/appropriate */
457 			case PW_TYPE_VSA:		/* @fixme We need special behaviour for these */
458 			case PW_TYPE_COMBO_IP_ADDR:	/* Covered by IPv4 address IPv6 address */
459 			case PW_TYPE_COMBO_IP_PREFIX:	/* Covered by IPv4 address IPv6 address */
460 			case PW_TYPE_TIMEVAL:		/* Not a VALUE_PAIR type */
461 				goto next_type;
462 
463 			default:
464 				break;
465 			}
466 
467 			dst = talloc_zero(vp, value_data_t);
468 			ret = value_data_cast(dst, dst, type->number, NULL, vp->da->type, vp->da,
469 					      &vp->data, vp->vp_length);
470 			if (ret < 0) goto next_type;	/* We expect some to fail */
471 
472 			value = value_data_aprints(dst, type->number, NULL, dst, (size_t)ret, '\'');
473 			if (!value) goto next_type;
474 
475 			if ((pad = (11 - strlen(type->name))) < 0) {
476 				pad = 0;
477 			}
478 
479 			RINDENT();
480 			RDEBUG2("as %s%*s: %s", type->name, pad, " ", value);
481 			REXDENT();
482 			talloc_free(value);
483 
484 		next_type:
485 			talloc_free(dst);
486 			type++;
487 		}
488 	}
489 	REXDENT();
490 
491 	*out = '\0';
492 	return 0;
493 }
494 
495 /** Processes fmt as a map string and applies it to the current request
496  *
497  * e.g. "%{map:&User-Name := 'foo'}"
498  *
499  * Allows sets of modifications to be cached and then applied.
500  * Useful for processing generic attributes from LDAP.
501  */
xlat_map(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)502 static ssize_t xlat_map(UNUSED void *instance, REQUEST *request,
503 			char const *fmt, char *out, size_t outlen)
504 {
505 	vp_map_t *map = NULL;
506 	int ret;
507 
508 	if (map_afrom_attr_str(request, &map, fmt,
509 			       REQUEST_CURRENT, PAIR_LIST_REQUEST,
510 			       REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
511 		REDEBUG("Failed parsing \"%s\" as map: %s", fmt, fr_strerror());
512 		return -1;
513 	}
514 
515 	RINDENT();
516 	ret = map_to_request(request, map, map_to_vp, NULL);
517 	REXDENT();
518 	talloc_free(map);
519 	if (ret < 0) return strlcpy(out, "0", outlen);
520 
521 	return strlcpy(out, "1", outlen);
522 }
523 
524 /** Prints the current module processing the request
525  *
526  */
xlat_module(UNUSED void * instance,REQUEST * request,UNUSED char const * fmt,char * out,size_t outlen)527 static ssize_t xlat_module(UNUSED void *instance, REQUEST *request,
528 			   UNUSED char const *fmt, char *out, size_t outlen)
529 {
530 	strlcpy(out, request->module, outlen);
531 
532 	return strlen(out);
533 }
534 
535 #if defined(HAVE_REGEX) && defined(HAVE_PCRE)
xlat_regex(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)536 static ssize_t xlat_regex(UNUSED void *instance, REQUEST *request,
537 			  char const *fmt, char *out, size_t outlen)
538 {
539 	char *p;
540 	size_t len;
541 
542 	if (regex_request_to_sub_named(request, &p, request, fmt) < 0) {
543 		*out = '\0';
544 		return 0;
545 	}
546 
547 	len = talloc_array_length(p);
548 	if (len > outlen) {
549 		RDEBUG("Insufficient buffer space to write subcapture value, needed %zu bytes, have %zu bytes",
550 		       len, outlen);
551 		return -1;
552 	}
553 	strlcpy(out, p, outlen);
554 
555 	return len - 1; /* - \0 */
556 }
557 #endif
558 
559 #ifdef WITH_UNLANG
560 /** Implements the Foreach-Variable-X
561  *
562  * @see modcall()
563  */
xlat_foreach(void * instance,REQUEST * request,UNUSED char const * fmt,char * out,size_t outlen)564 static ssize_t xlat_foreach(void *instance, REQUEST *request,
565 			    UNUSED char const *fmt, char *out, size_t outlen)
566 {
567 	VALUE_PAIR	**pvp;
568 	size_t		len;
569 
570 	/*
571 	 *	See modcall, "FOREACH" for how this works.
572 	 */
573 	pvp = (VALUE_PAIR **) request_data_reference(request, (void *)radius_get_vp, *(int*) instance);
574 	if (!pvp || !*pvp) {
575 		*out = '\0';
576 		return 0;
577 	}
578 
579 	len = vp_prints_value(out, outlen, *pvp, 0);
580 	if (is_truncated(len, outlen)) {
581 		RDEBUG("Insufficient buffer space to write foreach value");
582 		return -1;
583 	}
584 
585 	return len;
586 }
587 #endif
588 
589 /** Print data as string, if possible.
590  *
591  * If attribute "Foo" is defined as "octets" it will normally
592  * be printed as 0x0a0a0a. The xlat "%{string:Foo}" will instead
593  * expand to "\n\n\n"
594  */
xlat_string(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)595 static ssize_t xlat_string(UNUSED void *instance, REQUEST *request,
596 			   char const *fmt, char *out, size_t outlen)
597 {
598 	size_t len;
599 	ssize_t ret;
600 	VALUE_PAIR *vp;
601 	uint8_t const *p;
602 
603 	while (isspace((int) *fmt)) fmt++;
604 
605 	if (outlen < 3) {
606 	nothing:
607 		*out = '\0';
608 		return 0;
609 	}
610 
611 	if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
612 
613 	ret = rad_vp2data(&p, vp);
614 	if (ret < 0) {
615 		return ret;
616 	}
617 
618 	switch (vp->da->type) {
619 	case PW_TYPE_OCTETS:
620 		len = fr_prints(out, outlen, (char const *) p, vp->vp_length, '"');
621 		break;
622 
623 		/*
624 		 *	Note that "%{string:...}" is NOT binary safe!
625 		 *	It is explicitly used to get rid of embedded zeros.
626 		 */
627 	case PW_TYPE_STRING:
628 		len = strlcpy(out, vp->vp_strvalue, outlen);
629 		break;
630 
631 	default:
632 		len = fr_prints(out, outlen, (char const *) p, ret, '\0');
633 		break;
634 	}
635 
636 	return len;
637 }
638 
639 /** xlat expand string attribute value
640  *
641  */
xlat_xlat(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)642 static ssize_t xlat_xlat(UNUSED void *instance, REQUEST *request,
643 			char const *fmt, char *out, size_t outlen)
644 {
645 	VALUE_PAIR *vp;
646 
647 	while (isspace((int) *fmt)) fmt++;
648 
649 	if (outlen < 3) {
650 	nothing:
651 		*out = '\0';
652 		return 0;
653 	}
654 
655 	if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
656 
657 	if (vp->da->type != PW_TYPE_STRING) goto nothing;
658 
659 	return radius_xlat(out, outlen, request, vp->vp_strvalue, NULL, NULL);
660 }
661 
662 /** Dynamically change the debugging level for the current request
663  *
664  * Example %{debug:3}
665  */
xlat_debug(UNUSED void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)666 static ssize_t xlat_debug(UNUSED void *instance, REQUEST *request,
667 			  char const *fmt, char *out, size_t outlen)
668 {
669 	int level = 0;
670 
671 	/*
672 	 *  Expand to previous (or current) level
673 	 */
674 	snprintf(out, outlen, "%d", request->log.lvl);
675 
676 	/*
677 	 *  Assume we just want to get the current value and NOT set it to 0
678 	 */
679 	if (!*fmt)
680 		goto done;
681 
682 	level = atoi(fmt);
683 	if (level == 0) {
684 		request->log.lvl = RAD_REQUEST_LVL_NONE;
685 		request->log.func = NULL;
686 	} else {
687 		if (level > 4) level = 4;
688 
689 		request->log.lvl = level;
690 		request->log.func = vradlog_request;
691 	}
692 
693 	done:
694 	return strlen(out);
695 }
696 
697 /*
698  *	Compare two xlat_t structs, based ONLY on the module name.
699  */
xlat_cmp(void const * one,void const * two)700 static int xlat_cmp(void const *one, void const *two)
701 {
702 	xlat_t const *a = one;
703 	xlat_t const *b = two;
704 
705 	if (a->length != b->length) {
706 		return a->length - b->length;
707 	}
708 
709 	return memcmp(a->name, b->name, a->length);
710 }
711 
712 
713 /*
714  *	find the appropriate registered xlat function.
715  */
xlat_find(char const * name)716 static xlat_t *xlat_find(char const *name)
717 {
718 	xlat_t my_xlat;
719 
720 	strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
721 	my_xlat.length = strlen(my_xlat.name);
722 
723 	return rbtree_finddata(xlat_root, &my_xlat);
724 }
725 
726 
727 /** Register an xlat function.
728  *
729  * @param[in] name xlat name.
730  * @param[in] func xlat function to be called.
731  * @param[in] escape function to sanitize any sub expansions passed to the xlat function.
732  * @param[in] instance of module that's registering the xlat function.
733  * @return 0 on success, -1 on failure
734  */
xlat_register(char const * name,xlat_func_t func,xlat_escape_t escape,void * instance)735 int xlat_register(char const *name, xlat_func_t func, xlat_escape_t escape, void *instance)
736 {
737 	xlat_t	*c;
738 	xlat_t	my_xlat;
739 	rbnode_t *node;
740 
741 	if (!name || !*name) {
742 		DEBUG("xlat_register: Invalid xlat name");
743 		return -1;
744 	}
745 
746 	/*
747 	 *	First time around, build up the tree...
748 	 *
749 	 *	FIXME: This code should be hoisted out of this function,
750 	 *	and into a global "initialization".  But it isn't critical...
751 	 */
752 	if (!xlat_root) {
753 #ifdef WITH_UNLANG
754 		int i;
755 #endif
756 
757 		xlat_root = rbtree_create(NULL, xlat_cmp, NULL, RBTREE_FLAG_REPLACE);
758 		if (!xlat_root) {
759 			DEBUG("xlat_register: Failed to create tree");
760 			return -1;
761 		}
762 
763 #ifdef WITH_UNLANG
764 		for (i = 0; xlat_foreach_names[i] != NULL; i++) {
765 			xlat_register(xlat_foreach_names[i],
766 				      xlat_foreach, NULL, &xlat_inst[i]);
767 			c = xlat_find(xlat_foreach_names[i]);
768 			rad_assert(c != NULL);
769 			c->internal = true;
770 		}
771 #endif
772 
773 #define XLAT_REGISTER(_x) xlat_register(STRINGIFY(_x), xlat_ ## _x, NULL, NULL); \
774 		c = xlat_find(STRINGIFY(_x)); \
775 		rad_assert(c != NULL); \
776 		c->internal = true
777 
778 		XLAT_REGISTER(integer);
779 		XLAT_REGISTER(strlen);
780 		XLAT_REGISTER(length);
781 		XLAT_REGISTER(hex);
782 		XLAT_REGISTER(tag);
783 		XLAT_REGISTER(vendor);
784 		XLAT_REGISTER(vendor_num);
785 		XLAT_REGISTER(attr);
786 		XLAT_REGISTER(attr_num);
787 		XLAT_REGISTER(string);
788 		XLAT_REGISTER(xlat);
789 		XLAT_REGISTER(map);
790 		XLAT_REGISTER(module);
791 		XLAT_REGISTER(debug_attr);
792 #if defined(HAVE_REGEX) && defined(HAVE_PCRE)
793 		XLAT_REGISTER(regex);
794 #endif
795 
796 		xlat_register("debug", xlat_debug, NULL, &xlat_inst[0]);
797 		c = xlat_find("debug");
798 		rad_assert(c != NULL);
799 		c->internal = true;
800 	}
801 
802 	/*
803 	 *	If it already exists, replace the instance.
804 	 */
805 	strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
806 	my_xlat.length = strlen(my_xlat.name);
807 	c = rbtree_finddata(xlat_root, &my_xlat);
808 	if (c) {
809 		if (c->internal) {
810 			DEBUG("xlat_register: Cannot re-define internal xlat");
811 			return -1;
812 		}
813 
814 		c->func = func;
815 		c->escape = escape;
816 		c->instance = instance;
817 		return 0;
818 	}
819 
820 	/*
821 	 *	Doesn't exist.  Create it.
822 	 */
823 	c = talloc_zero(xlat_root, xlat_t);
824 
825 	c->func = func;
826 	c->escape = escape;
827 	strlcpy(c->name, name, sizeof(c->name));
828 	c->length = strlen(c->name);
829 	c->instance = instance;
830 
831 	node = rbtree_insert_node(xlat_root, c);
832 	if (!node) {
833 		talloc_free(c);
834 		return -1;
835 	}
836 
837 	/*
838 	 *	Ensure that the data is deleted when the node is
839 	 *	deleted.
840 	 *
841 	 *	@todo: Maybe this should be the other way around...
842 	 *	when a thing IN the tree is deleted, it's automatically
843 	 *	removed from the tree.  But for now, this works.
844 	 */
845 	(void) talloc_steal(node, c);
846 	return 0;
847 }
848 
849 /** Unregister an xlat function
850  *
851  * We can only have one function to call per name, so the passing of "func"
852  * here is extraneous.
853  *
854  * @param[in] name xlat to unregister.
855  * @param[in] func unused.
856  * @param[in] instance data.
857  */
xlat_unregister(char const * name,UNUSED xlat_func_t func,void * instance)858 void xlat_unregister(char const *name, UNUSED xlat_func_t func, void *instance)
859 {
860 	xlat_t	*c;
861 	xlat_t		my_xlat;
862 
863 	if (!name || !xlat_root) return;
864 
865 	strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
866 	my_xlat.length = strlen(my_xlat.name);
867 
868 	c = rbtree_finddata(xlat_root, &my_xlat);
869 	if (!c) return;
870 
871 	if (c->instance != instance) return;
872 
873 	rbtree_deletebydata(xlat_root, c);
874 }
875 
xlat_unregister_callback(void * instance,void * data)876 static int xlat_unregister_callback(void *instance, void *data)
877 {
878 	xlat_t *c = (xlat_t *) data;
879 
880 	if (c->instance != instance) return 0; /* keep walking */
881 
882 	return 2;		/* delete it */
883 }
884 
xlat_unregister_module(void * instance)885 void xlat_unregister_module(void *instance)
886 {
887 	rbtree_walk(xlat_root, RBTREE_DELETE_ORDER, xlat_unregister_callback, instance);
888 }
889 
890 /*
891  *	Internal redundant handler for xlats
892  */
893 typedef enum xlat_redundant_type_t {
894 	XLAT_INVALID = 0,
895 	XLAT_REDUNDANT,
896 	XLAT_LOAD_BALANCE,
897 	XLAT_REDUNDANT_LOAD_BALANCE,
898 } xlat_redundant_type_t;
899 
900 typedef struct xlat_redundant_t {
901 	xlat_redundant_type_t type;
902 	uint32_t	count;
903 	CONF_SECTION *cs;
904 } xlat_redundant_t;
905 
906 
xlat_redundant(void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)907 static ssize_t xlat_redundant(void *instance, REQUEST *request,
908 			      char const *fmt, char *out, size_t outlen)
909 {
910 	xlat_redundant_t *xr = instance;
911 	CONF_ITEM *ci;
912 	char const *name;
913 	xlat_t *xlat;
914 
915 	rad_assert(xr->type == XLAT_REDUNDANT);
916 
917 	/*
918 	 *	Pick the first xlat which succeeds
919 	 */
920 	for (ci = cf_item_find_next(xr->cs, NULL);
921 	     ci != NULL;
922 	     ci = cf_item_find_next(xr->cs, ci)) {
923 		ssize_t rcode;
924 
925 		if (!cf_item_is_pair(ci)) continue;
926 
927 		name = cf_pair_attr(cf_item_to_pair(ci));
928 		rad_assert(name != NULL);
929 
930 		xlat = xlat_find(name);
931 		if (!xlat) continue;
932 
933 		rcode = xlat->func(xlat->instance, request, fmt, out, outlen);
934 		if (rcode <= 0) continue;
935 		return rcode;
936 	}
937 
938 	/*
939 	 *	Everything failed.  Oh well.
940 	 */
941 	*out  = 0;
942 	return 0;
943 }
944 
945 
xlat_load_balance(void * instance,REQUEST * request,char const * fmt,char * out,size_t outlen)946 static ssize_t xlat_load_balance(void *instance, REQUEST *request,
947 			      char const *fmt, char *out, size_t outlen)
948 {
949 	uint32_t count = 0;
950 	xlat_redundant_t *xr = instance;
951 	CONF_ITEM *ci;
952 	CONF_ITEM *found = NULL;
953 	char const *name;
954 	xlat_t *xlat;
955 
956 	/*
957 	 *	Choose a child at random.
958 	 */
959 	for (ci = cf_item_find_next(xr->cs, NULL);
960 	     ci != NULL;
961 	     ci = cf_item_find_next(xr->cs, ci)) {
962 		if (!cf_item_is_pair(ci)) continue;
963 		count++;
964 
965 		/*
966 		 *	Replace the previously found one with a random
967 		 *	new one.
968 		 */
969 		if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
970 			found = ci;
971 		}
972 	}
973 
974 	/*
975 	 *	Plain load balancing: do one child, and only one child.
976 	 */
977 	if (xr->type == XLAT_LOAD_BALANCE) {
978 		name = cf_pair_attr(cf_item_to_pair(found));
979 		rad_assert(name != NULL);
980 
981 		xlat = xlat_find(name);
982 		if (!xlat) return -1;
983 
984 		return xlat->func(xlat->instance, request, fmt, out, outlen);
985 	}
986 
987 	rad_assert(xr->type == XLAT_REDUNDANT_LOAD_BALANCE);
988 
989 	/*
990 	 *	Try the random one we found.  If it fails, keep going
991 	 *	through the rest of the children.
992 	 */
993 	ci = found;
994 	do {
995 		name = cf_pair_attr(cf_item_to_pair(ci));
996 		rad_assert(name != NULL);
997 
998 		xlat = xlat_find(name);
999 		if (xlat) {
1000 			ssize_t rcode;
1001 
1002 			rcode = xlat->func(xlat->instance, request, fmt, out, outlen);
1003 			if (rcode > 0) return rcode;
1004 		}
1005 
1006 		/*
1007 		 *	Go to the next one, wrapping around at the end.
1008 		 */
1009 		ci = cf_item_find_next(xr->cs, ci);
1010 		if (!ci) ci = cf_item_find_next(xr->cs, NULL);
1011 	} while (ci != found);
1012 
1013 	return -1;
1014 }
1015 
1016 
xlat_register_redundant(CONF_SECTION * cs)1017 bool xlat_register_redundant(CONF_SECTION *cs)
1018 {
1019 	char const *name1, *name2;
1020 	xlat_redundant_t *xr;
1021 
1022 	name1 = cf_section_name1(cs);
1023 	name2 = cf_section_name2(cs);
1024 
1025 	if (!name2) return false;
1026 
1027 	if (xlat_find(name2)) {
1028 		cf_log_err_cs(cs, "An expansion is already registered for this name");
1029 		return false;
1030 	}
1031 
1032 	xr = talloc_zero(cs, xlat_redundant_t);
1033 	if (!xr) return false;
1034 
1035 	if (strcmp(name1, "redundant") == 0) {
1036 		xr->type = XLAT_REDUNDANT;
1037 
1038 	} else if (strcmp(name1, "redundant-load-balance") == 0) {
1039 		xr->type = XLAT_REDUNDANT_LOAD_BALANCE;
1040 
1041 	} else if (strcmp(name1, "load-balance") == 0) {
1042 		xr->type = XLAT_LOAD_BALANCE;
1043 
1044 	} else {
1045 		return false;
1046 	}
1047 
1048 	xr->cs = cs;
1049 
1050 	/*
1051 	 *	Get the number of children for load balancing.
1052 	 */
1053 	if (xr->type == XLAT_REDUNDANT) {
1054 		if (xlat_register(name2, xlat_redundant, NULL, xr) < 0) {
1055 			talloc_free(xr);
1056 			return false;
1057 		}
1058 
1059 	} else {
1060 		CONF_ITEM *ci;
1061 
1062 		for (ci = cf_item_find_next(cs, NULL);
1063 		     ci != NULL;
1064 		     ci = cf_item_find_next(cs, ci)) {
1065 			if (!cf_item_is_pair(ci)) continue;
1066 
1067 			if (!xlat_find(cf_pair_attr(cf_item_to_pair(ci)))) {
1068 				talloc_free(xr);
1069 				return false;
1070 			}
1071 
1072 			xr->count++;
1073 		}
1074 
1075 		if (xlat_register(name2, xlat_load_balance, NULL, xr) < 0) {
1076 			talloc_free(xr);
1077 			return false;
1078 		}
1079 	}
1080 
1081 	return true;
1082 }
1083 
1084 
1085 /** Crappy temporary function to add attribute ref support to xlats
1086  *
1087  * This needs to die, and hopefully will die, when xlat functions accept
1088  * xlat node structures.
1089  *
1090  * Provides either a pointer to a buffer which contains the value of the reference VALUE_PAIR
1091  * in an architecture independent format. Or a pointer to the start of the fmt string.
1092  *
1093  * The pointer is only guaranteed to be valid between calls to xlat_fmt_to_ref,
1094  * and so long as the source VALUE_PAIR is not freed.
1095  *
1096  * @param out where to write a pointer to the buffer to the data the xlat function needs to work on.
1097  * @param request current request.
1098  * @param fmt string.
1099  * @returns the length of the data or -1 on error.
1100  */
xlat_fmt_to_ref(uint8_t const ** out,REQUEST * request,char const * fmt)1101 ssize_t xlat_fmt_to_ref(uint8_t const **out, REQUEST *request, char const *fmt)
1102 {
1103 	VALUE_PAIR *vp;
1104 
1105 	while (isspace((int) *fmt)) fmt++;
1106 
1107 	if (fmt[0] == '&') {
1108 		if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
1109 			*out = NULL;
1110 			return -1;
1111 		}
1112 
1113 		return rad_vp2data(out, vp);
1114 	}
1115 
1116 	*out = (uint8_t const *)fmt;
1117 	return strlen(fmt);
1118 }
1119 
1120 /** De-register all xlat functions, used mainly for debugging.
1121  *
1122  */
xlat_free(void)1123 void xlat_free(void)
1124 {
1125 	rbtree_free(xlat_root);
1126 }
1127 
1128 #ifdef DEBUG_XLAT
1129 #  define XLAT_DEBUG DEBUG3
1130 #else
1131 #  define XLAT_DEBUG(...)
1132 #endif
1133 
1134 static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1135 				       char const **error);
1136 static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1137 				     bool brace, char const **error);
1138 static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const * const head,
1139 			   xlat_escape_t escape, void *escape_ctx);
1140 
xlat_tokenize_alternation(TALLOC_CTX * ctx,char * fmt,xlat_exp_t ** head,char const ** error)1141 static ssize_t xlat_tokenize_alternation(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1142 					 char const **error)
1143 {
1144 	ssize_t slen;
1145 	char *p;
1146 	xlat_exp_t *node;
1147 
1148 	rad_assert(fmt[0] == '%');
1149 	rad_assert(fmt[1] == '{');
1150 	rad_assert(fmt[2] == '%');
1151 	rad_assert(fmt[3] == '{');
1152 
1153 	XLAT_DEBUG("ALTERNATE <-- %s", fmt);
1154 
1155 	node = talloc_zero(ctx, xlat_exp_t);
1156 	node->type = XLAT_ALTERNATE;
1157 
1158 	p = fmt + 2;
1159 	slen = xlat_tokenize_expansion(node, p, &node->child, error);
1160 	if (slen <= 0) {
1161 		talloc_free(node);
1162 		return slen - (p - fmt);
1163 	}
1164 	p += slen;
1165 
1166 	if (p[0] != ':') {
1167 		talloc_free(node);
1168 		*error = "Expected ':' after first expansion";
1169 		return -(p - fmt);
1170 	}
1171 	p++;
1172 
1173 	if (p[0] != '-') {
1174 		talloc_free(node);
1175 		*error = "Expected '-' after ':'";
1176 		return -(p - fmt);
1177 	}
1178 	p++;
1179 
1180 	/*
1181 	 *	Allow the RHS to be empty as a special case.
1182 	 */
1183 	if (*p == '}') {
1184 		/*
1185 		 *	Hack up an empty string.
1186 		 */
1187 		node->alternate = talloc_zero(node, xlat_exp_t);
1188 		node->alternate->type = XLAT_LITERAL;
1189 		node->alternate->fmt = talloc_typed_strdup(node->alternate, "");
1190 		*(p++) = '\0';
1191 
1192 	} else {
1193 		slen = xlat_tokenize_literal(node, p,  &node->alternate, true, error);
1194 		if (slen <= 0) {
1195 			talloc_free(node);
1196 			return slen - (p - fmt);
1197 		}
1198 
1199 		if (!node->alternate) {
1200 			talloc_free(node);
1201 			*error = "Empty expansion is invalid";
1202 			return -(p - fmt);
1203 		}
1204 		p += slen;
1205 	}
1206 
1207 	*head = node;
1208 	return p - fmt;
1209 }
1210 
xlat_tokenize_expansion(TALLOC_CTX * ctx,char * fmt,xlat_exp_t ** head,char const ** error)1211 static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1212 				       char const **error)
1213 {
1214 	ssize_t slen;
1215 	char *p, *q;
1216 	xlat_exp_t *node;
1217 	long num;
1218 
1219 	rad_assert(fmt[0] == '%');
1220 	rad_assert(fmt[1] == '{');
1221 
1222 	/*
1223 	 *	%{%{...}:-bar}
1224 	 */
1225 	if ((fmt[2] == '%') && (fmt[3] == '{')) return xlat_tokenize_alternation(ctx, fmt, head, error);
1226 
1227 	XLAT_DEBUG("EXPANSION <-- %s", fmt);
1228 	node = talloc_zero(ctx, xlat_exp_t);
1229 	node->fmt = fmt + 2;
1230 	node->len = 0;
1231 
1232 #ifdef HAVE_REGEX
1233 	/*
1234 	 *	Handle regex's specially.
1235 	 */
1236 	p = fmt + 2;
1237 	num = strtol(p, &q, 10);
1238 	if (p != q && (*q == '}')) {
1239 		XLAT_DEBUG("REGEX <-- %s", fmt);
1240 		*q = '\0';
1241 
1242 		if ((num > REQUEST_MAX_REGEX) || (num < 0)) {
1243 			talloc_free(node);
1244 			*error = "Invalid regex reference.  Must be in range 0-" STRINGIFY(REQUEST_MAX_REGEX);
1245 			return -2;
1246 		}
1247 		node->attr.tmpl_num = num;
1248 
1249 		node->type = XLAT_REGEX;
1250 		*head = node;
1251 
1252 		return (q - fmt) + 1;
1253 	}
1254 #endif /* HAVE_REGEX */
1255 
1256 	/*
1257 	 *	%{Attr-Name}
1258 	 *	%{Attr-Name[#]}
1259 	 *	%{Tunnel-Password:1}
1260 	 *	%{Tunnel-Password:1[#]}
1261 	 *	%{request:Attr-Name}
1262 	 *	%{request:Tunnel-Password:1}
1263 	 *	%{request:Tunnel-Password:1[#]}
1264 	 *	%{mod:foo}
1265 	 */
1266 
1267 	/*
1268 	 *	This is for efficiency, so we don't search for an xlat,
1269 	 *	when what's being referenced is obviously an attribute.
1270 	 */
1271 	p = fmt + 2;
1272 	for (q = p; *q != '\0'; q++) {
1273 		if (*q == ':') break;
1274 
1275 		if (isspace((int) *q)) break;
1276 
1277 		if (*q == '[') continue;
1278 
1279 		if (*q == '}') break;
1280 	}
1281 
1282 	/*
1283 	 *	Check for empty expressions %{}
1284 	 */
1285 	if ((*q == '}') && (q == p)) {
1286 		talloc_free(node);
1287 		*error = "Empty expression is invalid";
1288 		return -(p - fmt);
1289 	}
1290 
1291 	/*
1292 	 *	Might be a module name reference.
1293 	 *
1294 	 *	If it's not, it's an attribute or parse error.
1295 	 */
1296 	if (*q == ':') {
1297 		*q = '\0';
1298 		node->xlat = xlat_find(node->fmt);
1299 		if (node->xlat) {
1300 			/*
1301 			 *	%{mod:foo}
1302 			 */
1303 			node->type = XLAT_MODULE;
1304 
1305 			p = q + 1;
1306 			XLAT_DEBUG("MOD <-- %s ... %s", node->fmt, p);
1307 
1308 			slen = xlat_tokenize_literal(node, p, &node->child, true, error);
1309 			if (slen < 0) {
1310 				talloc_free(node);
1311 				return slen - (p - fmt);
1312 			}
1313 			p += slen;
1314 
1315 			*head = node;
1316 			rad_assert(node->next == NULL);
1317 
1318 			return p - fmt;
1319 		}
1320 		*q = ':';	/* Avoids a strdup */
1321 	}
1322 
1323 	/*
1324 	 *	The first token ends with:
1325 	 *	- '[' - Which is an attribute index, so it must be an attribute.
1326 	 *      - '}' - The end of the expansion, which means it was a bareword.
1327 	 */
1328 	slen = tmpl_from_attr_substr(&node->attr, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, true, true);
1329 	if (slen <= 0) {
1330 		/*
1331 		 *	If the parse error occurred before the ':'
1332 		 *	then the error is changed to 'Unknown module',
1333 		 *	as it was more likely to be a bad module name,
1334 		 *	than a request qualifier.
1335 		 */
1336 		if ((*q == ':') && ((p + (slen * -1)) < q)) {
1337 			*error = "Unknown module";
1338 		} else {
1339 			*error = fr_strerror();
1340 		}
1341 
1342 		talloc_free(node);
1343 		return slen - (p - fmt);
1344 	}
1345 
1346 	/*
1347 	 *	Might be a virtual XLAT attribute
1348 	 */
1349 	if (node->attr.type == TMPL_TYPE_ATTR_UNDEFINED) {
1350 		node->xlat = xlat_find(node->attr.tmpl_unknown_name);
1351 		if (node->xlat && node->xlat->instance && !node->xlat->internal) {
1352 			talloc_free(node);
1353 			*error = "Missing content in expansion";
1354 			return -(p - fmt) - slen;
1355 		}
1356 
1357 		if (node->xlat) {
1358 			node->type = XLAT_VIRTUAL;
1359 			node->fmt = node->attr.tmpl_unknown_name;
1360 
1361 			XLAT_DEBUG("VIRTUAL <-- %s", node->fmt);
1362 			*head = node;
1363 			rad_assert(node->next == NULL);
1364 			q++;
1365 			return q - fmt;
1366 		}
1367 
1368 		talloc_free(node);
1369 		*error = "Unknown attribute";
1370 		return -(p - fmt);
1371 	}
1372 
1373 	/*
1374 	 *	Might be a list, too...
1375 	 */
1376 	node->type = XLAT_ATTRIBUTE;
1377 	p += slen;
1378 
1379 	if (*p != '}') {
1380 		talloc_free(node);
1381 		*error = "No matching closing brace";
1382 		return -1;	/* second character of format string */
1383 	}
1384 	*p++ = '\0';
1385 	*head = node;
1386 	rad_assert(node->next == NULL);
1387 
1388 	return p - fmt;
1389 }
1390 
1391 
xlat_tokenize_literal(TALLOC_CTX * ctx,char * fmt,xlat_exp_t ** head,bool brace,char const ** error)1392 static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1393 				     bool brace, char const **error)
1394 {
1395 	char *p;
1396 	xlat_exp_t *node;
1397 
1398 	if (!*fmt) return 0;
1399 
1400 	XLAT_DEBUG("LITERAL <-- %s", fmt);
1401 
1402 	node = talloc_zero(ctx, xlat_exp_t);
1403 	node->fmt = fmt;
1404 	node->len = 0;
1405 	node->type = XLAT_LITERAL;
1406 
1407 	p = fmt;
1408 
1409 	while (*p) {
1410 		if (*p == '\\') {
1411 			if (!p[1]) {
1412 				talloc_free(node);
1413 				*error = "Invalid escape at end of string";
1414 				return -(p - fmt);
1415 			}
1416 
1417 			p += 2;
1418 			node->len += 2;
1419 			continue;
1420 		}
1421 
1422 		/*
1423 		 *	Process the expansion.
1424 		 */
1425 		if ((p[0] == '%') && (p[1] == '{')) {
1426 			ssize_t slen;
1427 
1428 			XLAT_DEBUG("EXPANSION-2 <-- %s", node->fmt);
1429 
1430 			slen = xlat_tokenize_expansion(node, p, &node->next, error);
1431 			if (slen <= 0) {
1432 				talloc_free(node);
1433 				return slen - (p - fmt);
1434 			}
1435 			*p = '\0'; /* end the literal */
1436 			p += slen;
1437 
1438 			rad_assert(node->next != NULL);
1439 
1440 			/*
1441 			 *	Short-circuit the recursive call.
1442 			 *	This saves another function call and
1443 			 *	memory allocation.
1444 			 */
1445 			if (!*p) break;
1446 
1447 			/*
1448 			 *	"foo %{User-Name} bar"
1449 			 *	LITERAL		"foo "
1450 			 *	EXPANSION	User-Name
1451 			 *	LITERAL		" bar"
1452 			 */
1453 			slen = xlat_tokenize_literal(node->next, p, &(node->next->next), brace, error);
1454 			rad_assert(slen != 0);
1455 			if (slen < 0) {
1456 				talloc_free(node);
1457 				return slen - (p - fmt);
1458 			}
1459 
1460 			brace = false; /* it was found above, or else the above code errored out */
1461 			p += slen;
1462 			break;	/* stop processing the string */
1463 		}
1464 
1465 		/*
1466 		 *	Check for valid single-character expansions.
1467 		 */
1468 		if (p[0] == '%') {
1469 			ssize_t slen;
1470 			xlat_exp_t *next;
1471 
1472 			if (!p[1] || !strchr("%}cdelmntCDGHIMSTYv", p[1])) {
1473 				talloc_free(node);
1474 				*error = "Invalid variable expansion";
1475 				p++;
1476 				return - (p - fmt);
1477 			}
1478 
1479 			next = talloc_zero(node, xlat_exp_t);
1480 			next->len = 1;
1481 
1482 			switch (p[1]) {
1483 			case '%':
1484 			case '}':
1485 				next->fmt = talloc_strndup(next, p + 1, 1);
1486 
1487 				XLAT_DEBUG("LITERAL-ESCAPED <-- %s", next->fmt);
1488 				next->type = XLAT_LITERAL;
1489 				break;
1490 
1491 			default:
1492 				next->fmt = p + 1;
1493 
1494 				XLAT_DEBUG("PERCENT <-- %c", *next->fmt);
1495 				next->type = XLAT_PERCENT;
1496 				break;
1497 			}
1498 
1499 			node->next = next;
1500 			*p = '\0';
1501 			p += 2;
1502 
1503 			if (!*p) break;
1504 
1505 			/*
1506 			 *	And recurse.
1507 			 */
1508 			slen = xlat_tokenize_literal(node->next, p, &(node->next->next), brace, error);
1509 			rad_assert(slen != 0);
1510 			if (slen < 0) {
1511 				talloc_free(node);
1512 				return slen - (p - fmt);
1513 			}
1514 
1515 			brace = false; /* it was found above, or else the above code errored out */
1516 			p += slen;
1517 			break;	/* stop processing the string */
1518 		}
1519 
1520 		/*
1521 		 *	If required, eat the brace.
1522 		 */
1523 		if (brace && (*p == '}')) {
1524 			brace = false;
1525 			*p = '\0';
1526 			p++;
1527 			break;
1528 		}
1529 
1530 		p++;
1531 		node->len++;
1532 	}
1533 
1534 	/*
1535 	 *	We were told to look for a brace, but we ran off of
1536 	 *	the end of the string before we found one.
1537 	 */
1538 	if (brace) {
1539 		*error = "Missing closing brace at end of string";
1540 		return -(p - fmt);
1541 	}
1542 
1543 	/*
1544 	 *	Squash zero-width literals
1545 	 */
1546 	if (node->len > 0) {
1547 		*head = node;
1548 
1549 	} else {
1550 		(void) talloc_steal(ctx, node->next);
1551 		*head = node->next;
1552 		talloc_free(node);
1553 	}
1554 
1555 	return p - fmt;
1556 }
1557 
1558 
1559 static char const xlat_tabs[] = "																																																																																																																																";
1560 
xlat_tokenize_debug(xlat_exp_t const * node,int lvl)1561 static void xlat_tokenize_debug(xlat_exp_t const *node, int lvl)
1562 {
1563 	rad_assert(node != NULL);
1564 
1565 	if (lvl >= (int) sizeof(xlat_tabs)) lvl = sizeof(xlat_tabs);
1566 
1567 	while (node) {
1568 		switch (node->type) {
1569 		case XLAT_LITERAL:
1570 			DEBUG("%.*sliteral --> %s", lvl, xlat_tabs, node->fmt);
1571 			break;
1572 
1573 		case XLAT_PERCENT:
1574 			DEBUG("%.*spercent --> %c", lvl, xlat_tabs, node->fmt[0]);
1575 			break;
1576 
1577 		case XLAT_ATTRIBUTE:
1578 			rad_assert(node->attr.tmpl_da != NULL);
1579 			DEBUG("%.*sattribute --> %s", lvl, xlat_tabs, node->attr.tmpl_da->name);
1580 			rad_assert(node->child == NULL);
1581 			if ((node->attr.tmpl_tag != TAG_ANY) || (node->attr.tmpl_num != NUM_ANY)) {
1582 				DEBUG("%.*s{", lvl, xlat_tabs);
1583 
1584 				DEBUG("%.*sref  %d", lvl + 1, xlat_tabs, node->attr.tmpl_request);
1585 				DEBUG("%.*slist %d", lvl + 1, xlat_tabs, node->attr.tmpl_list);
1586 
1587 				if (node->attr.tmpl_tag != TAG_ANY) {
1588 					DEBUG("%.*stag %d", lvl + 1, xlat_tabs, node->attr.tmpl_tag);
1589 				}
1590 				if (node->attr.tmpl_num != NUM_ANY) {
1591 					if (node->attr.tmpl_num == NUM_COUNT) {
1592 						DEBUG("%.*s[#]", lvl + 1, xlat_tabs);
1593 					} else if (node->attr.tmpl_num == NUM_ALL) {
1594 						DEBUG("%.*s[*]", lvl + 1, xlat_tabs);
1595 					} else {
1596 						DEBUG("%.*s[%d]", lvl + 1, xlat_tabs, node->attr.tmpl_num);
1597 					}
1598 				}
1599 
1600 				DEBUG("%.*s}", lvl, xlat_tabs);
1601 			}
1602 			break;
1603 
1604 		case XLAT_VIRTUAL:
1605 			rad_assert(node->fmt != NULL);
1606 			DEBUG("%.*svirtual --> %s", lvl, xlat_tabs, node->fmt);
1607 			break;
1608 
1609 		case XLAT_MODULE:
1610 			rad_assert(node->xlat != NULL);
1611 			DEBUG("%.*sxlat --> %s", lvl, xlat_tabs, node->xlat->name);
1612 			if (node->child) {
1613 				DEBUG("%.*s{", lvl, xlat_tabs);
1614 				xlat_tokenize_debug(node->child, lvl + 1);
1615 				DEBUG("%.*s}", lvl, xlat_tabs);
1616 			}
1617 			break;
1618 
1619 #ifdef HAVE_REGEX
1620 		case XLAT_REGEX:
1621 			DEBUG("%.*sregex-var --> %d", lvl, xlat_tabs, node->attr.tmpl_num);
1622 			break;
1623 #endif
1624 
1625 		case XLAT_ALTERNATE:
1626 			DEBUG("%.*sXLAT-IF {", lvl, xlat_tabs);
1627 			xlat_tokenize_debug(node->child, lvl + 1);
1628 			DEBUG("%.*s}", lvl, xlat_tabs);
1629 			DEBUG("%.*sXLAT-ELSE {", lvl, xlat_tabs);
1630 			xlat_tokenize_debug(node->alternate, lvl + 1);
1631 			DEBUG("%.*s}", lvl, xlat_tabs);
1632 			break;
1633 		}
1634 		node = node->next;
1635 	}
1636 }
1637 
xlat_sprint(char * buffer,size_t bufsize,xlat_exp_t const * node)1638 size_t xlat_sprint(char *buffer, size_t bufsize, xlat_exp_t const *node)
1639 {
1640 	size_t len;
1641 	char *p, *end;
1642 
1643 	if (!node) {
1644 		*buffer = '\0';
1645 		return 0;
1646 	}
1647 
1648 	p = buffer;
1649 	end = buffer + bufsize;
1650 
1651 	while (node) {
1652 		switch (node->type) {
1653 		case XLAT_LITERAL:
1654 			strlcpy(p, node->fmt, end - p);
1655 			p += strlen(p);
1656 			break;
1657 
1658 		case XLAT_PERCENT:
1659 			p[0] = '%';
1660 			p[1] = node->fmt[0];
1661 			p += 2;
1662 			break;
1663 
1664 		case XLAT_ATTRIBUTE:
1665 			*(p++) = '%';
1666 			*(p++) = '{';
1667 
1668 			/*
1669 			 *	The node MAY NOT be an attribute.  It
1670 			 *	may be a list.
1671 			 */
1672 			tmpl_prints(p, end - p, &node->attr, NULL);
1673 			if (*p == '&') {
1674 				memmove(p, p + 1, strlen(p + 1) + 1);
1675 			}
1676 			p += strlen(p);
1677 			*(p++) = '}';
1678 			break;
1679 #ifdef HAVE_REGEX
1680 		case XLAT_REGEX:
1681 			snprintf(p, end - p, "%%{%i}", node->attr.tmpl_num);
1682 			p += strlen(p);
1683 			break;
1684 #endif
1685 		case XLAT_VIRTUAL:
1686 			*(p++) = '%';
1687 			*(p++) = '{';
1688 			strlcpy(p, node->fmt, end - p);
1689 			p += strlen(p);
1690 			*(p++) = '}';
1691 			break;
1692 
1693 		case XLAT_MODULE:
1694 			*(p++) = '%';
1695 			*(p++) = '{';
1696 			strlcpy(p, node->xlat->name, end - p);
1697 			p += strlen(p);
1698 			*(p++) = ':';
1699 			rad_assert(node->child != NULL);
1700 			len = xlat_sprint(p, end - p, node->child);
1701 			p += len;
1702 			*(p++) = '}';
1703 			break;
1704 
1705 		case XLAT_ALTERNATE:
1706 			*(p++) = '%';
1707 			*(p++) = '{';
1708 
1709 			len = xlat_sprint(p, end - p, node->child);
1710 			p += len;
1711 
1712 			*(p++) = ':';
1713 			*(p++) = '-';
1714 
1715 			len = xlat_sprint(p, end - p, node->alternate);
1716 			p += len;
1717 
1718 			*(p++) = '}';
1719 			break;
1720 		}
1721 
1722 
1723 		if (p == end) break;
1724 
1725 		node = node->next;
1726 	}
1727 
1728 	*p = '\0';
1729 
1730 	return p - buffer;
1731 }
1732 
xlat_tokenize(TALLOC_CTX * ctx,char * fmt,xlat_exp_t ** head,char const ** error)1733 ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1734 		      char const **error)
1735 {
1736 	return xlat_tokenize_literal(ctx, fmt, head, false, error);
1737 }
1738 
1739 
1740 /** Tokenize an xlat expansion
1741  *
1742  * @param[in] request the input request.  Memory will be attached here.
1743  * @param[in] fmt the format string to expand
1744  * @param[out] head the head of the xlat list / tree structure.
1745  */
xlat_tokenize_request(REQUEST * request,char const * fmt,xlat_exp_t ** head)1746 static ssize_t xlat_tokenize_request(REQUEST *request, char const *fmt, xlat_exp_t **head)
1747 {
1748 	ssize_t slen;
1749 	char *tokens;
1750 	char const *error = NULL;
1751 
1752 	*head = NULL;
1753 
1754 	/*
1755 	 *	Copy the original format string to a buffer so that
1756 	 *	the later functions can mangle it in-place, which is
1757 	 *	much faster.
1758 	 */
1759 	tokens = talloc_typed_strdup(request, fmt);
1760 	if (!tokens) {
1761 		error = "Out of memory";
1762 		return -1;
1763 	}
1764 
1765 	slen = xlat_tokenize_literal(request, tokens, head, false, &error);
1766 
1767 	/*
1768 	 *	Zero length expansion, return a zero length node.
1769 	 */
1770 	if (slen == 0) {
1771 		*head = talloc_zero(request, xlat_exp_t);
1772 	}
1773 
1774 	/*
1775 	 *	Output something like:
1776 	 *
1777 	 *	"format string"
1778 	 *	"       ^ error was here"
1779 	 */
1780 	if (slen < 0) {
1781 		talloc_free(tokens);
1782 
1783 		if (!error) error = "Unknown error";
1784 
1785 		REMARKER(fmt, -slen, error);
1786 		return slen;
1787 	}
1788 
1789 	if (*head && (rad_debug_lvl > 2)) {
1790 		DEBUG("%s", fmt);
1791 		DEBUG("Parsed xlat tree:");
1792 		xlat_tokenize_debug(*head, 0);
1793 	}
1794 
1795 	/*
1796 	 *	All of the nodes point to offsets in the "tokens"
1797 	 *	string.  Let's ensure that free'ing head will free
1798 	 *	"tokens", too.
1799 	 */
1800 	(void) talloc_steal(*head, tokens);
1801 
1802 	return slen;
1803 }
1804 
1805 
xlat_getvp(TALLOC_CTX * ctx,REQUEST * request,vp_tmpl_t const * vpt,bool escape,bool return_null)1806 static char *xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, vp_tmpl_t const *vpt,
1807 			bool escape, bool return_null)
1808 {
1809 	VALUE_PAIR *vp = NULL, *virtual = NULL;
1810 	RADIUS_PACKET *packet = NULL;
1811 	DICT_VALUE *dv;
1812 	char *ret = NULL;
1813 
1814 	vp_cursor_t cursor;
1815 	char quote = escape ? '"' : '\0';
1816 
1817 	rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
1818 
1819 	/*
1820 	 *	We only support count and concatenate operations on lists.
1821 	 */
1822 	if (vpt->type == TMPL_TYPE_LIST) {
1823 		vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
1824 		goto do_print;
1825 	}
1826 
1827 	/*
1828 	 *	See if we're dealing with an attribute in the request
1829 	 *
1830 	 *	This allows users to manipulate virtual attributes as if
1831 	 *	they were real ones.
1832 	 */
1833 	vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
1834 	if (vp) goto do_print;
1835 
1836 	/*
1837 	 *	We didn't find the VP in a list.
1838 	 *	If it's not a virtual one, and we're not meant to
1839 	 *	be counting it, return.
1840 	 */
1841 	if (!vpt->tmpl_da->flags.virtual) {
1842 		if (vpt->tmpl_num == NUM_COUNT) goto do_print;
1843 		return NULL;
1844 	}
1845 
1846 	/*
1847 	 *	Switch out the request to the one specified by the template
1848 	 */
1849 	if (radius_request(&request, vpt->tmpl_request) < 0) return NULL;
1850 
1851 	/*
1852 	 *	Some non-packet expansions
1853 	 */
1854 	switch (vpt->tmpl_da->attr) {
1855 	default:
1856 		break;		/* ignore them */
1857 
1858 	case PW_CLIENT_SHORTNAME:
1859 		if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
1860 		if (request->client && request->client->shortname) {
1861 			return talloc_typed_strdup(ctx, request->client->shortname);
1862 		}
1863 		return talloc_typed_strdup(ctx, "<UNKNOWN-CLIENT>");
1864 
1865 	case PW_REQUEST_PROCESSING_STAGE:
1866 		if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
1867 		if (request->component) {
1868 			return talloc_typed_strdup(ctx, request->component);
1869 		}
1870 		return talloc_typed_strdup(ctx, "server_core");
1871 
1872 	case PW_VIRTUAL_SERVER:
1873 		if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
1874 		if (!request->server) return NULL;
1875 		return talloc_typed_strdup(ctx, request->server);
1876 
1877 	case PW_MODULE_RETURN_CODE:
1878 		if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
1879 		if (!request->rcode) return NULL;
1880 		return talloc_typed_strdup(ctx, fr_int2str(modreturn_table, request->rcode, ""));
1881 	}
1882 
1883 	/*
1884 	 *	All of the attributes must now refer to a packet.
1885 	 *	If there's no packet, we can't print any attribute
1886 	 *	referencing it.
1887 	 */
1888 	packet = radius_packet(request, vpt->tmpl_list);
1889 	if (!packet) {
1890 		if (return_null) return NULL;
1891 		return vp_aprints_type(ctx, vpt->tmpl_da->type);
1892 	}
1893 
1894 	vp = NULL;
1895 	switch (vpt->tmpl_da->attr) {
1896 	default:
1897 		break;
1898 
1899 	case PW_PACKET_TYPE:
1900 		dv = dict_valbyattr(PW_PACKET_TYPE, 0, packet->code);
1901 		if (dv) return talloc_typed_strdup(ctx, dv->name);
1902 		return talloc_typed_asprintf(ctx, "%d", packet->code);
1903 
1904 	case PW_RESPONSE_PACKET_TYPE:
1905 	{
1906 		int code = 0;
1907 
1908 #ifdef WITH_PROXY
1909 		if (request->proxy_reply && (!request->reply || !request->reply->code)) {
1910 			code = request->proxy_reply->code;
1911 		} else
1912 #endif
1913 			if (request->reply) {
1914 				code = request->reply->code;
1915 			}
1916 
1917 		if (!code) return NULL;
1918 
1919 		if (code >= FR_MAX_PACKET_CODE) {
1920 			return talloc_typed_asprintf(ctx, "%d", packet->code);
1921 		}
1922 
1923 		return talloc_typed_strdup(ctx, fr_packet_codes[code]);
1924 	}
1925 
1926 	/*
1927 	 *	Virtual attributes which require a temporary VALUE_PAIR
1928 	 *	to be allocated. We can't use stack allocated memory
1929 	 *	because of the talloc checks sprinkled throughout the
1930 	 *	various VP functions.
1931 	 */
1932 	case PW_PACKET_AUTHENTICATION_VECTOR:
1933 		virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1934 		fr_pair_value_memcpy(virtual, packet->vector, sizeof(packet->vector));
1935 		vp = virtual;
1936 		break;
1937 
1938 	case PW_CLIENT_IP_ADDRESS:
1939 	case PW_PACKET_SRC_IP_ADDRESS:
1940 		if (packet->src_ipaddr.af == AF_INET) {
1941 			virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1942 			virtual->vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
1943 			vp = virtual;
1944 		}
1945 		break;
1946 
1947 	case PW_PACKET_DST_IP_ADDRESS:
1948 		if (packet->dst_ipaddr.af == AF_INET) {
1949 			virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1950 			virtual->vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
1951 			vp = virtual;
1952 		}
1953 		break;
1954 
1955 	case PW_PACKET_SRC_IPV6_ADDRESS:
1956 		if (packet->src_ipaddr.af == AF_INET6) {
1957 			virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1958 			memcpy(&virtual->vp_ipv6addr,
1959 			       &packet->src_ipaddr.ipaddr.ip6addr,
1960 			       sizeof(packet->src_ipaddr.ipaddr.ip6addr));
1961 			vp = virtual;
1962 		}
1963 		break;
1964 
1965 	case PW_PACKET_DST_IPV6_ADDRESS:
1966 		if (packet->dst_ipaddr.af == AF_INET6) {
1967 			virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1968 			memcpy(&virtual->vp_ipv6addr,
1969 			       &packet->dst_ipaddr.ipaddr.ip6addr,
1970 			       sizeof(packet->dst_ipaddr.ipaddr.ip6addr));
1971 			vp = virtual;
1972 		}
1973 		break;
1974 
1975 	case PW_PACKET_SRC_PORT:
1976 		virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1977 		virtual->vp_integer = packet->src_port;
1978 		vp = virtual;
1979 		break;
1980 
1981 	case PW_PACKET_DST_PORT:
1982 		virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1983 		virtual->vp_integer = packet->dst_port;
1984 		vp = virtual;
1985 		break;
1986 	}
1987 
1988 	/*
1989 	 *	Fake various operations for virtual attributes.
1990 	 */
1991 	if (virtual) {
1992 		if (vpt->tmpl_num != NUM_ANY) switch (vpt->tmpl_num) {
1993 		/*
1994 		 *	[n] is NULL (we only have [0])
1995 		 */
1996 		default:
1997 			goto finish;
1998 		/*
1999 		 *	[*] means only one.
2000 		 */
2001 		case NUM_ALL:
2002 			break;
2003 
2004 		/*
2005 		 *	[#] means 1 (as there's only one)
2006 		 */
2007 		case NUM_COUNT:
2008 		count_virtual:
2009 			ret = talloc_strdup(ctx, "1");
2010 			goto finish;
2011 
2012 		/*
2013 		 *	[0] is fine (get the first instance)
2014 		 */
2015 		case 0:
2016 			break;
2017 		}
2018 		goto print;
2019 	}
2020 
2021 do_print:
2022 	switch (vpt->tmpl_num) {
2023 	/*
2024 	 *	Return a count of the VPs.
2025 	 */
2026 	case NUM_COUNT:
2027 	{
2028 		int count = 0;
2029 
2030 		for (vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
2031 		     vp;
2032 		     vp = tmpl_cursor_next(&cursor, vpt)) count++;
2033 
2034 		return talloc_typed_asprintf(ctx, "%d", count);
2035 	}
2036 
2037 
2038 	/*
2039 	 *	Concatenate all values together,
2040 	 *	separated by commas.
2041 	 */
2042 	case NUM_ALL:
2043 	{
2044 		char *p, *q;
2045 
2046 		if (!fr_cursor_current(&cursor)) return NULL;
2047 		p = vp_aprints_value(ctx, vp, quote);
2048 		if (!p) return NULL;
2049 
2050 		while ((vp = tmpl_cursor_next(&cursor, vpt)) != NULL) {
2051 			q = vp_aprints_value(ctx, vp, quote);
2052 			if (!q) return NULL;
2053 			p = talloc_strdup_append(p, ",");
2054 			p = talloc_strdup_append(p, q);
2055 		}
2056 
2057 		return p;
2058 	}
2059 
2060 	default:
2061 		/*
2062 		 *	The cursor was set to the correct
2063 		 *	position above by tmpl_cursor_init.
2064 		 */
2065 		vp = fr_cursor_current(&cursor);
2066 		break;
2067 	}
2068 
2069 	if (!vp) {
2070 		if (return_null) return NULL;
2071 		return vp_aprints_type(ctx, vpt->tmpl_da->type);
2072 	}
2073 
2074 print:
2075 	ret = vp_aprints_value(ctx, vp, quote);
2076 
2077 finish:
2078 	talloc_free(virtual);
2079 	return ret;
2080 }
2081 
2082 #ifdef DEBUG_XLAT
2083 static const char xlat_spaces[] = "                                                                                                                                                                                                                                                                ";
2084 #endif
2085 
xlat_aprint(TALLOC_CTX * ctx,REQUEST * request,xlat_exp_t const * const node,xlat_escape_t escape,void * escape_ctx,UNUSED int lvl)2086 static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * const node,
2087 			 xlat_escape_t escape, void *escape_ctx,
2088 #ifndef DEBUG_XLAT
2089 			 UNUSED
2090 #endif
2091 			 int lvl)
2092 {
2093 	ssize_t rcode;
2094 	char *str = NULL, *child;
2095 	char const *p;
2096 
2097 	XLAT_DEBUG("%.*sxlat aprint %d %s", lvl, xlat_spaces, node->type, node->fmt);
2098 
2099 	switch (node->type) {
2100 		/*
2101 		 *	Don't escape this.
2102 		 */
2103 	case XLAT_LITERAL:
2104 		XLAT_DEBUG("%.*sxlat_aprint LITERAL", lvl, xlat_spaces);
2105 		return talloc_typed_strdup(ctx, node->fmt);
2106 
2107 		/*
2108 		 *	Do a one-character expansion.
2109 		 */
2110 	case XLAT_PERCENT:
2111 	{
2112 		char *nl;
2113 		size_t freespace = 256;
2114 		struct tm ts;
2115 		time_t when;
2116 		int usec;
2117 
2118 		XLAT_DEBUG("%.*sxlat_aprint PERCENT", lvl, xlat_spaces);
2119 
2120 		str = talloc_array(ctx, char, freespace); /* @todo do better allocation */
2121 		p = node->fmt;
2122 
2123 		when = request->timestamp;
2124 		usec = 0;
2125 		if (request->packet) {
2126 			when = request->packet->timestamp.tv_sec;
2127 			usec = request->packet->timestamp.tv_usec;
2128 		}
2129 
2130 		switch (*p) {
2131 		case '%':
2132 			str[0] = '%';
2133 			str[1] = '\0';
2134 			break;
2135 
2136 		case 'c':	/* current epoch time seconds */
2137 			snprintf(str, freespace, "%" PRIu64, (uint64_t) time(NULL));
2138 			break;
2139 
2140 		case 'd': /* request day */
2141 			if (!localtime_r(&when, &ts)) goto error;
2142 			strftime(str, freespace, "%d", &ts);
2143 			break;
2144 
2145 		case 'e': /* request second */
2146 			if (!localtime_r(&when, &ts)) goto error;
2147 
2148 			snprintf(str, freespace, "%d", ts.tm_sec);
2149 			break;
2150 
2151 		case 'l': /* request timestamp */
2152 			snprintf(str, freespace, "%lu",
2153 				 (unsigned long) when);
2154 			break;
2155 
2156 		case 'm': /* request month */
2157 			if (!localtime_r(&when, &ts)) goto error;
2158 			strftime(str, freespace, "%m", &ts);
2159 			break;
2160 
2161 		case 'n': /* Request Number*/
2162 			snprintf(str, freespace, "%u", request->number);
2163 			break;
2164 
2165 		case 't': /* request timestamp */
2166 			CTIME_R(&when, str, freespace);
2167 			nl = strchr(str, '\n');
2168 			if (nl) *nl = '\0';
2169 			break;
2170 
2171 		case 'C':	/* current epoch time microseconds */
2172 			{
2173 				struct timeval tv;
2174 
2175 				gettimeofday(&tv, NULL);
2176 
2177 				snprintf(str, freespace, "%" PRIu64, (uint64_t) tv.tv_usec);
2178 			}
2179 			break;
2180 
2181 		case 'D': /* request date */
2182 			if (!localtime_r(&when, &ts)) goto error;
2183 			strftime(str, freespace, "%Y%m%d", &ts);
2184 			break;
2185 
2186 		case 'G': /* request minute */
2187 			if (!localtime_r(&when, &ts)) goto error;
2188 			strftime(str, freespace, "%M", &ts);
2189 			break;
2190 
2191 		case 'H': /* request hour */
2192 			if (!localtime_r(&when, &ts)) goto error;
2193 			strftime(str, freespace, "%H", &ts);
2194 			break;
2195 
2196 		case 'I': /* Request ID */
2197 			if (request->packet) {
2198 				snprintf(str, freespace, "%i", request->packet->id);
2199 			}
2200 			break;
2201 
2202 		case 'M': /* request microsecond component */
2203 			snprintf(str, freespace, "%06u", (unsigned int) usec);
2204 			break;
2205 
2206 		case 'S': /* request timestamp in SQL format*/
2207 			if (!localtime_r(&when, &ts)) goto error;
2208 			strftime(str, freespace, "%Y-%m-%d %H:%M:%S", &ts);
2209 			break;
2210 
2211 		case 'T': /* request timestamp */
2212 			if (!localtime_r(&when, &ts)) goto error;
2213 			nl = str + strftime(str, freespace, "%Y-%m-%d-%H.%M.%S", &ts);
2214 			rad_assert(((str + freespace) - nl) >= 8);
2215 			snprintf(nl, (str + freespace) - nl, ".%06d",  usec);
2216 			break;
2217 
2218 		case 'Y': /* request year */
2219 			if (!localtime_r(&when, &ts)) {
2220 				error:
2221 				REDEBUG("Failed converting packet timestamp to localtime: %s", fr_syserror(errno));
2222 				talloc_free(str);
2223 				return NULL;
2224 			}
2225 			strftime(str, freespace, "%Y", &ts);
2226 			break;
2227 
2228 		case 'v': /* Version of code */
2229 			RWDEBUG("%%v is deprecated and will be removed.  Use ${version.freeradius-server}");
2230 			snprintf(str, freespace, "%s", radiusd_version_short);
2231 			break;
2232 
2233 		default:
2234 			rad_assert(0 == 1);
2235 			break;
2236 		}
2237 	}
2238 		break;
2239 
2240 	case XLAT_ATTRIBUTE:
2241 		XLAT_DEBUG("%.*sxlat_aprint ATTRIBUTE", lvl, xlat_spaces);
2242 
2243 		/*
2244 		 *	Some attributes are virtual <sigh>
2245 		 */
2246 		str = xlat_getvp(ctx, request, &node->attr, escape ? false : true, true);
2247 		if (str) {
2248 			XLAT_DEBUG("%.*sEXPAND attr %s", lvl, xlat_spaces, node->attr.tmpl_da->name);
2249 			XLAT_DEBUG("%.*s       ---> %s", lvl ,xlat_spaces, str);
2250 		}
2251 		break;
2252 
2253 	case XLAT_VIRTUAL:
2254 		XLAT_DEBUG("xlat_aprint VIRTUAL");
2255 		str = talloc_array(ctx, char, 2048); /* FIXME: have the module call talloc_typed_asprintf */
2256 		rcode = node->xlat->func(node->xlat->instance, request, NULL, str, 2048);
2257 		if (rcode < 0) {
2258 			talloc_free(str);
2259 			return NULL;
2260 		}
2261 		RDEBUG2("EXPAND %s", node->xlat->name);
2262 		RDEBUG2("   --> %s", str);
2263 
2264 		/*
2265 		 *	Resize the buffer to the correct size.
2266 		 */
2267 		if (rcode == 0) {
2268 			talloc_free(str);
2269 			str = talloc_strdup(ctx, "");
2270 		} else if (rcode < 2047) {
2271 			child = talloc_memdup(ctx, str, rcode + 1);
2272 			talloc_free(str);
2273 			str = child;
2274 		}
2275 		break;
2276 
2277 	case XLAT_MODULE:
2278 		XLAT_DEBUG("xlat_aprint MODULE");
2279 
2280 		if (node->child) {
2281 			if (xlat_process(&child, request, node->child, node->xlat->escape, node->xlat->instance) == 0) {
2282 				return NULL;
2283 			}
2284 
2285 			XLAT_DEBUG("%.*sEXPAND mod %s %s", lvl, xlat_spaces, node->fmt, node->child->fmt);
2286 		} else {
2287 			XLAT_DEBUG("%.*sEXPAND mod %s", lvl, xlat_spaces, node->fmt);
2288 			child = talloc_typed_strdup(ctx, "");
2289 		}
2290 
2291 		XLAT_DEBUG("%.*s      ---> %s", lvl, xlat_spaces, child);
2292 
2293 		/*
2294 		 *	Smash \n --> CR.
2295 		 *
2296 		 *	The OUTPUT of xlat is a "raw" string.  The INPUT is a printable string.
2297 		 *
2298 		 *	This is really the reverse of fr_prints().
2299 		 */
2300 		if (cf_new_escape && *child) {
2301 			ssize_t slen;
2302 			PW_TYPE type;
2303 			value_data_t data;
2304 
2305 			type = PW_TYPE_STRING;
2306 			slen = value_data_from_str(request, &data, &type, NULL, child, talloc_array_length(child) - 1, '"');
2307 			if (slen <= 0) {
2308 				talloc_free(child);
2309 				return NULL;
2310 			}
2311 
2312 			talloc_free(child);
2313 			child = data.ptr;
2314 
2315 		} else {
2316 			char *q;
2317 
2318 			p = q = child;
2319 			while (*p) {
2320 				if (*p == '\\') switch (p[1]) {
2321 					default:
2322 						*(q++) = p[1];
2323 						p += 2;
2324 						continue;
2325 
2326 					case 'n':
2327 						*(q++) = '\n';
2328 						p += 2;
2329 						continue;
2330 
2331 					case 't':
2332 						*(q++) = '\t';
2333 						p += 2;
2334 						continue;
2335 					}
2336 
2337 				*(q++) = *(p++);
2338 			}
2339 			*q = '\0';
2340 		}
2341 
2342 		str = talloc_array(ctx, char, 2048); /* FIXME: have the module call talloc_typed_asprintf */
2343 		*str = '\0';	/* Be sure the string is NULL terminated, we now only free on error */
2344 
2345 		rcode = node->xlat->func(node->xlat->instance, request, child, str, 2048);
2346 		talloc_free(child);
2347 		if (rcode < 0) {
2348 			talloc_free(str);
2349 			return NULL;
2350 		}
2351 		break;
2352 
2353 #ifdef HAVE_REGEX
2354 	case XLAT_REGEX:
2355 		XLAT_DEBUG("%.*sxlat_aprint REGEX", lvl, xlat_spaces);
2356 		if (regex_request_to_sub(ctx, &str, request, node->attr.tmpl_num) < 0) return NULL;
2357 
2358 		break;
2359 #endif
2360 
2361 	case XLAT_ALTERNATE:
2362 		XLAT_DEBUG("%.*sxlat_aprint ALTERNATE", lvl, xlat_spaces);
2363 		rad_assert(node->child != NULL);
2364 		rad_assert(node->alternate != NULL);
2365 
2366 		/*
2367 		 *	Call xlat_process recursively.  The child /
2368 		 *	alternate nodes may have "next" pointers, and
2369 		 *	those need to be expanded.
2370 		 */
2371 		if (xlat_process(&str, request, node->child, escape, escape_ctx) > 0) {
2372 			XLAT_DEBUG("%.*sALTERNATE got first string: %s", lvl, xlat_spaces, str);
2373 		} else {
2374 			(void) xlat_process(&str, request, node->alternate, escape, escape_ctx);
2375 			XLAT_DEBUG("%.*sALTERNATE got alternate string %s", lvl, xlat_spaces, str);
2376 		}
2377 		break;
2378 	}
2379 
2380 	/*
2381 	 *	If there's no data, return that, instead of an empty string.
2382 	 */
2383 	if (str && !str[0]) {
2384 		talloc_free(str);
2385 		return NULL;
2386 	}
2387 
2388 	/*
2389 	 *	Escape the non-literals we found above.
2390 	 */
2391 	if (str && escape) {
2392 		size_t len;
2393 		char *escaped;
2394 
2395 		len = talloc_array_length(str) * 3;
2396 
2397 		escaped = talloc_array(ctx, char, len);
2398 		escape(request, escaped, len, str, escape_ctx);
2399 		talloc_free(str);
2400 		str = escaped;
2401 	}
2402 
2403 	return str;
2404 }
2405 
2406 
xlat_process(char ** out,REQUEST * request,xlat_exp_t const * const head,xlat_escape_t escape,void * escape_ctx)2407 static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const * const head,
2408 			   xlat_escape_t escape, void *escape_ctx)
2409 {
2410 	int i, list;
2411 	size_t total;
2412 	char **array, *answer;
2413 	xlat_exp_t const *node;
2414 
2415 	*out = NULL;
2416 
2417 	/*
2418 	 *	There are no nodes to process, so the result is a zero
2419 	 *	length string.
2420 	 */
2421 	if (!head) {
2422 		*out = talloc_zero_array(request, char, 1);
2423 		return 0;
2424 	}
2425 
2426 	/*
2427 	 *	Hack for speed.  If it's one expansion, just allocate
2428 	 *	that and return, instead of allocating an intermediary
2429 	 *	array.
2430 	 */
2431 	if (!head->next) {
2432 		/*
2433 		 *	Pass the MAIN escape function.  Recursive
2434 		 *	calls will call node-specific escape
2435 		 *	functions.
2436 		 */
2437 		answer = xlat_aprint(request, request, head, escape, escape_ctx, 0);
2438 		if (!answer) {
2439 			*out = talloc_zero_array(request, char, 1);
2440 			return 0;
2441 		}
2442 		*out = answer;
2443 		return strlen(answer);
2444 	}
2445 
2446 	list = 0;		/* FIXME: calculate this once */
2447 	for (node = head; node != NULL; node = node->next) {
2448 		list++;
2449 	}
2450 
2451 	array = talloc_array(request, char *, list);
2452 	if (!array) return -1;
2453 
2454 	for (node = head, i = 0; node != NULL; node = node->next, i++) {
2455 		array[i] = xlat_aprint(array, request, node, escape, escape_ctx, 0); /* may be NULL */
2456 	}
2457 
2458 	total = 0;
2459 	for (i = 0; i < list; i++) {
2460 		if (array[i]) total += strlen(array[i]); /* FIXME: calculate strlen once */
2461 	}
2462 
2463 	if (!total) {
2464 		talloc_free(array);
2465 		*out = talloc_zero_array(request, char, 1);
2466 		return 0;
2467 	}
2468 
2469 	answer = talloc_array(request, char, total + 1);
2470 
2471 	total = 0;
2472 	for (i = 0; i < list; i++) {
2473 		size_t len;
2474 
2475 		if (array[i]) {
2476 			len = strlen(array[i]);
2477 			memcpy(answer + total, array[i], len);
2478 			total += len;
2479 		}
2480 	}
2481 	answer[total] = '\0';
2482 	talloc_free(array);	/* and child entries */
2483 
2484 	*out = answer;
2485 	return total;
2486 }
2487 
2488 
2489 /** Replace %whatever in a string.
2490  *
2491  * See 'doc/configuration/variables.rst' for more information.
2492  *
2493  * @param[out] out Where to write pointer to output buffer.
2494  * @param[in] outlen Size of out.
2495  * @param[in] request current request.
2496  * @param[in] node the xlat structure to expand
2497  * @param[in] escape function to escape final value e.g. SQL quoting.
2498  * @param[in] escape_ctx pointer to pass to escape function.
2499  * @return length of string written @bug should really have -1 for failure
2500  */
xlat_expand_struct(char ** out,size_t outlen,REQUEST * request,xlat_exp_t const * node,xlat_escape_t escape,void * escape_ctx)2501 static ssize_t xlat_expand_struct(char **out, size_t outlen, REQUEST *request, xlat_exp_t const *node,
2502 				  xlat_escape_t escape, void *escape_ctx)
2503 {
2504 	char *buff;
2505 	ssize_t len;
2506 
2507 	rad_assert(node != NULL);
2508 
2509 	len = xlat_process(&buff, request, node, escape, escape_ctx);
2510 	if ((len < 0) || !buff) {
2511 		rad_assert(buff == NULL);
2512 		if (*out) *out[0] = '\0';
2513 		return len;
2514 	}
2515 
2516 	len = strlen(buff);
2517 
2518 	/*
2519 	 *	If out doesn't point to an existing buffer
2520 	 *	copy the pointer to our buffer over.
2521 	 */
2522 	if (!*out) {
2523 		*out = buff;
2524 		return len;
2525 	}
2526 
2527 	/*
2528 	 *	Otherwise copy the malloced buffer to the fixed one.
2529 	 */
2530 	strlcpy(*out, buff, outlen);
2531 	talloc_free(buff);
2532 	return len;
2533 }
2534 
2535 static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
2536 			   xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull (1, 3, 4));
2537 
2538 /** Replace %whatever in a string.
2539  *
2540  * See 'doc/configuration/variables.rst' for more information.
2541  *
2542  * @param[out] out Where to write pointer to output buffer.
2543  * @param[in] outlen Size of out.
2544  * @param[in] request current request.
2545  * @param[in] fmt string to expand.
2546  * @param[in] escape function to escape final value e.g. SQL quoting.
2547  * @param[in] escape_ctx pointer to pass to escape function.
2548  * @return length of string written @bug should really have -1 for failure
2549  */
xlat_expand(char ** out,size_t outlen,REQUEST * request,char const * fmt,xlat_escape_t escape,void * escape_ctx)2550 static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
2551 			   xlat_escape_t escape, void *escape_ctx)
2552 {
2553 	ssize_t len;
2554 	xlat_exp_t *node;
2555 
2556 	/*
2557 	 *	Give better errors than the old code.
2558 	 */
2559 	len = xlat_tokenize_request(request, fmt, &node);
2560 	if (len == 0) {
2561 		if (*out) {
2562 			*out[0] = '\0';
2563 		} else {
2564 			*out = talloc_zero_array(request, char, 1);
2565 		}
2566 		return 0;
2567 	}
2568 
2569 	if (len < 0) {
2570 		if (*out) *out[0] = '\0';
2571 		return -1;
2572 	}
2573 
2574 	len = xlat_expand_struct(out, outlen, request, node, escape, escape_ctx);
2575 	talloc_free(node);
2576 
2577 	RDEBUG2("EXPAND %s", fmt);
2578 	RDEBUG2("   --> %s", *out);
2579 
2580 	return len;
2581 }
2582 
2583 /** Try to convert an xlat to a tmpl for efficiency
2584  *
2585  * @param ctx to allocate new vp_tmpl_t in.
2586  * @param node to convert.
2587  * @return NULL if unable to convert (not necessarily error), or a new vp_tmpl_t.
2588  */
xlat_to_tmpl_attr(TALLOC_CTX * ctx,xlat_exp_t * node)2589 vp_tmpl_t *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_t *node)
2590 {
2591 	vp_tmpl_t *vpt;
2592 
2593 	if (node->next || (node->type != XLAT_ATTRIBUTE) || (node->attr.type != TMPL_TYPE_ATTR)) return NULL;
2594 
2595 	/*
2596 	 *   Concat means something completely different as an attribute reference
2597 	 *   Count isn't implemented.
2598 	 */
2599 	if ((node->attr.tmpl_num == NUM_COUNT) || (node->attr.tmpl_num == NUM_ALL)) return NULL;
2600 
2601 	vpt = tmpl_alloc(ctx, TMPL_TYPE_ATTR, node->fmt, -1);
2602 	if (!vpt) return NULL;
2603 	memcpy(&vpt->data, &node->attr.data, sizeof(vpt->data));
2604 
2605 	VERIFY_TMPL(vpt);
2606 
2607 	return vpt;
2608 }
2609 
2610 /** Try to convert attr tmpl to an xlat for &attr[*] and artificially constructing expansions
2611  *
2612  * @param ctx to allocate new xlat_expt_t in.
2613  * @param vpt to convert.
2614  * @return NULL if unable to convert (not necessarily error), or a new vp_tmpl_t.
2615  */
xlat_from_tmpl_attr(TALLOC_CTX * ctx,vp_tmpl_t * vpt)2616 xlat_exp_t *xlat_from_tmpl_attr(TALLOC_CTX *ctx, vp_tmpl_t *vpt)
2617 {
2618 	xlat_exp_t *node;
2619 
2620 	if (vpt->type != TMPL_TYPE_ATTR) return NULL;
2621 
2622 	node = talloc_zero(ctx, xlat_exp_t);
2623 	node->type = XLAT_ATTRIBUTE;
2624 	node->fmt = talloc_bstrndup(node, vpt->name, vpt->len);
2625 	tmpl_init(&node->attr, TMPL_TYPE_ATTR, node->fmt, talloc_array_length(node->fmt) - 1);
2626 	memcpy(&node->attr.data, &vpt->data, sizeof(vpt->data));
2627 
2628 	return node;
2629 }
2630 
radius_xlat(char * out,size_t outlen,REQUEST * request,char const * fmt,xlat_escape_t escape,void * ctx)2631 ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
2632 {
2633 	return xlat_expand(&out, outlen, request, fmt, escape, ctx);
2634 }
2635 
radius_xlat_struct(char * out,size_t outlen,REQUEST * request,xlat_exp_t const * xlat,xlat_escape_t escape,void * ctx)2636 ssize_t radius_xlat_struct(char *out, size_t outlen, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
2637 {
2638 	return xlat_expand_struct(&out, outlen, request, xlat, escape, ctx);
2639 }
2640 
radius_axlat(char ** out,REQUEST * request,char const * fmt,xlat_escape_t escape,void * ctx)2641 ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
2642 {
2643 	*out = NULL;
2644 	return xlat_expand(out, 0, request, fmt, escape, ctx);
2645 }
2646 
radius_axlat_struct(char ** out,REQUEST * request,xlat_exp_t const * xlat,xlat_escape_t escape,void * ctx)2647 ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
2648 {
2649 	*out = NULL;
2650 	return xlat_expand_struct(out, 0, request, xlat, escape, ctx);
2651 }
2652