Add value_data_cast and use it to perform casts for hex xlat
[freeradius.git] / src / main / xlat.c
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$
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$")
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         RAD_XLAT_FUNC           func;                   //!< xlat function.
41         RADIUS_ESCAPE_STRING    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         value_pair_tmpl_t attr; //!< An attribute template.
68         xlat_t const *xlat;     //!< The xlat expansion to expand format with.
69 };
70
71 typedef struct xlat_out {
72         char const *out;        //!< Output data.
73         size_t len;             //!< Length of the output string.
74 } xlat_out_t;
75
76 static rbtree_t *xlat_root = NULL;
77
78 #ifdef WITH_UNLANG
79 static char const * const xlat_foreach_names[] = {"Foreach-Variable-0",
80                                                   "Foreach-Variable-1",
81                                                   "Foreach-Variable-2",
82                                                   "Foreach-Variable-3",
83                                                   "Foreach-Variable-4",
84                                                   "Foreach-Variable-5",
85                                                   "Foreach-Variable-6",
86                                                   "Foreach-Variable-7",
87                                                   "Foreach-Variable-8",
88                                                   "Foreach-Variable-9",
89                                                   NULL};
90 #endif
91
92 #if REQUEST_MAX_REGEX > 8
93 #  error Please fix the following line
94 #endif
95 static int xlat_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; /* up to 8 for regex */
96
97 char const *radiusd_short_version = RADIUSD_VERSION_STRING;
98
99 /** Print length of its RHS.
100  *
101  */
102 static ssize_t xlat_strlen(UNUSED void *instance, UNUSED REQUEST *request,
103                            char const *fmt, char *out, size_t outlen)
104 {
105         snprintf(out, outlen, "%u", (unsigned int) strlen(fmt));
106         return strlen(out);
107 }
108
109 /** Print the size of the attribute in bytes.
110  *
111  */
112 static ssize_t xlat_length(UNUSED void *instance, UNUSED REQUEST *request,
113                            char const *fmt, char *out, size_t outlen)
114 {
115         VALUE_PAIR *vp;
116         while (isspace((int) *fmt)) fmt++;
117
118         if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
119                 *out = '\0';
120                 return 0;
121         }
122
123         snprintf(out, outlen, "%zu", vp->length);
124         return strlen(out);
125 }
126
127 /** Print data as integer, not as VALUE.
128  *
129  */
130 static ssize_t xlat_integer(UNUSED void *instance, REQUEST *request,
131                             char const *fmt, char *out, size_t outlen)
132 {
133         VALUE_PAIR      *vp;
134
135         uint64_t        int64 = 0;      /* Needs to be initialised to zero */
136         uint32_t        int32 = 0;      /* Needs to be initialised to zero */
137
138         while (isspace((int) *fmt)) fmt++;
139
140         if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
141                 *out = '\0';
142                 return 0;
143         }
144
145         switch (vp->da->type) {
146         case PW_TYPE_OCTETS:
147         case PW_TYPE_STRING:
148                 if (vp->length > 8) {
149                         break;
150                 }
151
152                 if (vp->length > 4) {
153                         memcpy(&int64, vp->vp_octets, vp->length);
154                         return snprintf(out, outlen, "%" PRIu64, htonll(int64));
155                 }
156
157                 memcpy(&int32, vp->vp_octets, vp->length);
158                 return snprintf(out, outlen, "%i", htonl(int32));
159
160         case PW_TYPE_INTEGER64:
161                 return snprintf(out, outlen, "%" PRIu64, vp->vp_integer64);
162
163         /*
164          *      IP addresses are treated specially, as parsing functions assume the value
165          *      is bigendian and will convert it for us.
166          */
167         case PW_TYPE_IPV4_ADDR:
168                 return snprintf(out, outlen, "%u", htonl(vp->vp_ipaddr));
169
170         case PW_TYPE_IPV4_PREFIX:
171                 return snprintf(out, outlen, "%u", htonl((*(uint32_t *)(vp->vp_ipv4prefix + 2))));
172
173         case PW_TYPE_INTEGER:
174         case PW_TYPE_DATE:
175                 return snprintf(out, outlen, "%u", vp->vp_integer);
176         case PW_TYPE_BYTE:
177                 return snprintf(out, outlen, "%u", (unsigned int) vp->vp_byte);
178         case PW_TYPE_SHORT:
179                 return snprintf(out, outlen, "%u", (unsigned int) vp->vp_short);
180
181         /*
182          *      Ethernet is weird... It's network related, so we assume to it should be
183          *      bigendian.
184          */
185         case PW_TYPE_ETHERNET:
186                 memcpy(&int64, &vp->vp_ether, vp->length);
187                 return snprintf(out, outlen, "%" PRIu64, htonll(int64));
188
189         case PW_TYPE_SIGNED:
190                 return snprintf(out, outlen, "%i", vp->vp_signed);
191
192         case PW_TYPE_IPV6_ADDR:
193                 return fr_prints_uint128(out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6addr));
194
195         case PW_TYPE_IPV6_PREFIX:
196                 return fr_prints_uint128(out, outlen, ntohlll(*(uint128_t const *) &(vp->vp_ipv6prefix[2])));
197
198         default:
199                 break;
200         }
201
202         REDEBUG("Type '%s' of length %zu cannot be converted to integer",
203                 fr_int2str(dict_attr_types, vp->da->type, "???"), vp->length);
204         *out = '\0';
205
206         return -1;
207 }
208
209 /** Print data as hex, not as VALUE.
210  *
211  */
212 static ssize_t xlat_hex(UNUSED void *instance, REQUEST *request,
213                         char const *fmt, char *out, size_t outlen)
214 {
215         size_t i;
216         VALUE_PAIR *vp;
217         uint8_t const *p;
218         ssize_t ret;
219         size_t  len;
220         value_data_t dst;
221         uint8_t const *buff = NULL;
222
223         while (isspace((int) *fmt)) fmt++;
224
225         if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
226         error:
227                 *out = '\0';
228                 return -1;
229         }
230
231         /*
232          *      The easy case.
233          */
234         if (vp->da->type == PW_TYPE_OCTETS) {
235                 p = vp->vp_octets;
236                 len = vp->length;
237         /*
238          *      Cast the value_data_t of the VP to an octets string and
239          *      print that as hex.
240          */
241         } else {
242                 ret = value_data_cast(request, &dst, PW_TYPE_OCTETS, NULL, vp->da->type,
243                                       NULL, &vp->data, vp->length);
244                 if (ret < 0) {
245                         REDEBUG("%s", fr_strerror());
246                         goto error;
247                 }
248                 len = (size_t) ret;
249                 p = buff = dst.octets;
250         }
251
252         rad_assert(p);
253
254         /*
255          *      Don't truncate the data.
256          */
257         if (outlen < (len * 2)) {
258                 rad_const_free(buff);
259                 goto error;
260         }
261
262         for (i = 0; i < len; i++) {
263                 snprintf(out + 2*i, 3, "%02x", p[i]);
264         }
265         rad_const_free(buff);
266
267         return len * 2;
268 }
269
270 /** Return the tag of an attribute reference
271  *
272  */
273 static ssize_t xlat_tag(UNUSED void *instance, REQUEST *request,
274                         char const *fmt, char *out, size_t outlen)
275 {
276         VALUE_PAIR *vp;
277
278         while (isspace((int) *fmt)) fmt++;
279
280         if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
281                 *out = '\0';
282                 return 0;
283         }
284
285         if (!vp->da->flags.has_tag || !TAG_VALID(vp->tag)) {
286                 *out = '\0';
287                 return 0;
288         }
289
290         return snprintf(out, outlen, "%u", vp->tag);
291 }
292
293 /** Print out attribute info
294  *
295  * Prints out all instances of a current attribute, or all attributes in a list.
296  *
297  * At higher debugging levels, also prints out alternative decodings of the same
298  * value. This is helpful to determine types for unknown attributes of long
299  * passed vendors, or just crazy/broken NAS.
300  *
301  * It's also useful for exposing issues in the packet decoding functions, as in
302  * some cases they get fed random garbage data.
303  *
304  * This expands to a zero length string.
305  */
306 static ssize_t xlat_debug_attr(UNUSED void *instance, REQUEST *request, char const *fmt,
307                                char *out, UNUSED size_t outlen)
308 {
309         VALUE_PAIR *vp, **vps;
310         REQUEST *current;
311         vp_cursor_t cursor;
312         char buffer[1024];
313
314         value_pair_tmpl_t vpt;
315
316         if (!RDEBUG_ENABLED2) {
317                 *out = '\0';
318                 return -1;
319         }
320
321         while (isspace((int) *fmt)) fmt++;
322
323         if (tmpl_from_attr_str(&vpt, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST) <= 0) {
324                 RDEBUG("%s", fr_strerror());
325                 return -1;
326         }
327
328         current = request;
329         if (radius_request(&current, vpt.tmpl_request) < 0) return -2;
330
331         vps = radius_list(current, vpt.tmpl_list);
332         if (!vps) {
333                 return -2;
334         }
335
336         RIDEBUG("Attributes matching \"%s\"", fmt);
337         vp = fr_cursor_init(&cursor, vps);
338
339         if (vpt.tmpl_da) {
340                 vp = fr_cursor_next_by_da(&cursor, vpt.tmpl_da, TAG_ANY);
341         }
342         while (vp) {
343                 DICT_ATTR *dac = NULL;
344                 DICT_VENDOR *dv;
345
346                 vp_prints_value(buffer, sizeof(buffer), vp, '\'');
347
348                 RINDENT();
349                 if (vp->da->flags.has_tag) {
350                         RIDEBUG2("%s:%s:%i %s %s",
351                                 fr_int2str(pair_lists, vpt.tmpl_list, "<INVALID>"),
352                                 vp->da->name,
353                                 vp->tag,
354                                 fr_int2str(fr_tokens, vp->op, "<INVALID>"),
355                                 buffer);
356                 } else {
357                         RIDEBUG2("%s:%s %s %s",
358                                 fr_int2str(pair_lists, vpt.tmpl_list, "<INVALID>"),
359                                 vp->da->name,
360                                 fr_int2str(fr_tokens, vp->op, "<INVALID>"),
361                                 buffer);
362                 }
363                 REXDENT();
364
365                 if (!RDEBUG_ENABLED3) goto next_vp;
366
367                 RINDENT();
368                 RINDENT();
369                 if (vp->da->vendor) {
370                         dv = dict_vendorbyvalue(vp->da->vendor);
371                         RDEBUG3("Vendor : %i (%s)", vp->da->vendor, dv ? dv->name : "unknown");
372                 }
373                 RDEBUG3("Type   : %s", fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"));
374                 RDEBUG3("Length : %zu", vp->length);
375                 REXDENT();
376                 REXDENT();
377
378                 dac = talloc_memdup(request, vp->da, sizeof(DICT_ATTR));
379                 if (!dac) return -1;
380                 talloc_set_type(dac, DICT_ATTR);
381
382         next_vp:
383                 talloc_free(dac);
384
385                 if (vpt.tmpl_da) {
386                         vp = fr_cursor_next_by_da(&cursor, vpt.tmpl_da, TAG_ANY);
387                 } else {
388                         vp = fr_cursor_next(&cursor);
389                 }
390         }
391
392         *out = '\0';
393         return 0;
394 }
395
396 /** Prints the current module processing the request
397  *
398  */
399 static ssize_t xlat_module(UNUSED void *instance, REQUEST *request,
400                            UNUSED char const *fmt, char *out, size_t outlen)
401 {
402         strlcpy(out, request->module, outlen);
403
404         return strlen(out);
405 }
406
407 #ifdef WITH_UNLANG
408 /** Implements the Foreach-Variable-X
409  *
410  * @see modcall()
411  */
412 static ssize_t xlat_foreach(void *instance, REQUEST *request,
413                             UNUSED char const *fmt, char *out, size_t outlen)
414 {
415         VALUE_PAIR      **pvp;
416         size_t          len;
417
418         /*
419          *      See modcall, "FOREACH" for how this works.
420          */
421         pvp = (VALUE_PAIR **) request_data_reference(request, radius_get_vp, *(int*) instance);
422         if (!pvp || !*pvp) {
423                 *out = '\0';
424                 return 0;
425         }
426
427         len = vp_prints_value(out, outlen, *pvp, 0);
428         if (is_truncated(len, outlen)) {
429                 RDEBUG("Insufficient buffer space to write foreach value");
430                 return -1;
431         }
432
433         return len;
434 }
435 #endif
436
437 /** Print data as string, if possible.
438  *
439  * If attribute "Foo" is defined as "octets" it will normally
440  * be printed as 0x0a0a0a. The xlat "%{string:Foo}" will instead
441  * expand to "\n\n\n"
442  */
443 static ssize_t xlat_string(UNUSED void *instance, REQUEST *request,
444                            char const *fmt, char *out, size_t outlen)
445 {
446         size_t len;
447         ssize_t ret;
448         VALUE_PAIR *vp;
449         uint8_t const *p;
450
451         while (isspace((int) *fmt)) fmt++;
452
453         if (outlen < 3) {
454         nothing:
455                 *out = '\0';
456                 return 0;
457         }
458
459         if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
460
461         ret = rad_vp2data(&p, vp);
462         if (ret < 0) {
463                 return ret;
464         }
465
466         switch (vp->da->type) {
467         case PW_TYPE_OCTETS:
468                 len = fr_print_string((char const *) p, vp->length, out, outlen, '\0');
469                 break;
470
471         case PW_TYPE_STRING:
472                 len = strlcpy(out, vp->vp_strvalue, outlen);
473                 break;
474
475         default:
476                 len = fr_print_string((char const *) p, ret, out, outlen, '\0');
477                 break;
478         }
479
480         return len;
481 }
482
483 /** xlat expand string attribute value
484  *
485  */
486 static ssize_t xlat_xlat(UNUSED void *instance, REQUEST *request,
487                         char const *fmt, char *out, size_t outlen)
488 {
489         VALUE_PAIR *vp;
490
491         while (isspace((int) *fmt)) fmt++;
492
493         if (outlen < 3) {
494         nothing:
495                 *out = '\0';
496                 return 0;
497         }
498
499         if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
500
501         return radius_xlat(out, outlen, request, vp->vp_strvalue, NULL, NULL);
502 }
503
504 /** Dynamically change the debugging level for the current request
505  *
506  * Example %{debug:3}
507  */
508 static ssize_t xlat_debug(UNUSED void *instance, REQUEST *request,
509                           char const *fmt, char *out, size_t outlen)
510 {
511         int level = 0;
512
513         /*
514          *  Expand to previous (or current) level
515          */
516         snprintf(out, outlen, "%d", request->log.lvl & RAD_REQUEST_OPTION_DEBUG4);
517
518         /*
519          *  Assume we just want to get the current value and NOT set it to 0
520          */
521         if (!*fmt)
522                 goto done;
523
524         level = atoi(fmt);
525         if (level == 0) {
526                 request->log.lvl = RAD_REQUEST_OPTION_NONE;
527                 request->log.func = NULL;
528         } else {
529                 if (level > 4) level = 4;
530
531                 request->log.lvl = level;
532                 request->log.func = vradlog_request;
533         }
534
535         done:
536         return strlen(out);
537 }
538
539 /*
540  *      Compare two xlat_t structs, based ONLY on the module name.
541  */
542 static int xlat_cmp(void const *one, void const *two)
543 {
544         xlat_t const *a = one;
545         xlat_t const *b = two;
546
547         if (a->length != b->length) {
548                 return a->length - b->length;
549         }
550
551         return memcmp(a->name, b->name, a->length);
552 }
553
554
555 /*
556  *      find the appropriate registered xlat function.
557  */
558 static xlat_t *xlat_find(char const *name)
559 {
560         xlat_t my_xlat;
561
562         strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
563         my_xlat.length = strlen(my_xlat.name);
564
565         return rbtree_finddata(xlat_root, &my_xlat);
566 }
567
568
569 /** Register an xlat function.
570  *
571  * @param[in] name xlat name.
572  * @param[in] func xlat function to be called.
573  * @param[in] escape function to sanitize any sub expansions passed to the xlat function.
574  * @param[in] instance of module that's registering the xlat function.
575  * @return 0 on success, -1 on failure
576  */
577 int xlat_register(char const *name, RAD_XLAT_FUNC func, RADIUS_ESCAPE_STRING escape, void *instance)
578 {
579         xlat_t   *c;
580         xlat_t   my_xlat;
581         rbnode_t *node;
582
583         if (!name || !*name) {
584                 DEBUG("xlat_register: Invalid xlat name");
585                 return -1;
586         }
587
588         /*
589          *      First time around, build up the tree...
590          *
591          *      FIXME: This code should be hoisted out of this function,
592          *      and into a global "initialization".  But it isn't critical...
593          */
594         if (!xlat_root) {
595 #ifdef WITH_UNLANG
596                 int i;
597 #endif
598
599                 xlat_root = rbtree_create(NULL, xlat_cmp, free, RBTREE_FLAG_REPLACE);
600                 if (!xlat_root) {
601                         DEBUG("xlat_register: Failed to create tree");
602                         return -1;
603                 }
604
605 #ifdef WITH_UNLANG
606                 for (i = 0; xlat_foreach_names[i] != NULL; i++) {
607                         xlat_register(xlat_foreach_names[i],
608                                       xlat_foreach, NULL, &xlat_inst[i]);
609                         c = xlat_find(xlat_foreach_names[i]);
610                         rad_assert(c != NULL);
611                         c->internal = true;
612                 }
613 #endif
614
615 #define XLAT_REGISTER(_x) xlat_register(STRINGIFY(_x), xlat_ ## _x, NULL, NULL); \
616                 c = xlat_find(STRINGIFY(_x)); \
617                 rad_assert(c != NULL); \
618                 c->internal = true
619
620                 XLAT_REGISTER(integer);
621                 XLAT_REGISTER(strlen);
622                 XLAT_REGISTER(length);
623                 XLAT_REGISTER(hex);
624                 XLAT_REGISTER(tag);
625                 XLAT_REGISTER(string);
626                 XLAT_REGISTER(xlat);
627                 XLAT_REGISTER(module);
628                 XLAT_REGISTER(debug_attr);
629
630                 xlat_register("debug", xlat_debug, NULL, &xlat_inst[0]);
631                 c = xlat_find("debug");
632                 rad_assert(c != NULL);
633                 c->internal = true;
634         }
635
636         /*
637          *      If it already exists, replace the instance.
638          */
639         strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
640         my_xlat.length = strlen(my_xlat.name);
641         c = rbtree_finddata(xlat_root, &my_xlat);
642         if (c) {
643                 if (c->internal) {
644                         DEBUG("xlat_register: Cannot re-define internal xlat");
645                         return -1;
646                 }
647
648                 c->func = func;
649                 c->escape = escape;
650                 c->instance = instance;
651                 return 0;
652         }
653
654         /*
655          *      Doesn't exist.  Create it.
656          */
657         c = rad_malloc(sizeof(*c));
658         memset(c, 0, sizeof(*c));
659
660         c->func = func;
661         c->escape = escape;
662         strlcpy(c->name, name, sizeof(c->name));
663         c->length = strlen(c->name);
664         c->instance = instance;
665
666         node = rbtree_insert_node(xlat_root, c);
667         if (!node) {
668                 talloc_free(c);
669                 return -1;
670         }
671
672         return 0;
673 }
674
675 /** Unregister an xlat function
676  *
677  * We can only have one function to call per name, so the passing of "func"
678  * here is extraneous.
679  *
680  * @param[in] name xlat to unregister.
681  * @param[in] func unused.
682  * @param[in] instance data.
683  */
684 void xlat_unregister(char const *name, UNUSED RAD_XLAT_FUNC func, void *instance)
685 {
686         xlat_t  *c;
687         xlat_t          my_xlat;
688
689         if (!name) return;
690
691         strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
692         my_xlat.length = strlen(my_xlat.name);
693
694         c = rbtree_finddata(xlat_root, &my_xlat);
695         if (!c) return;
696
697         if (c->instance != instance) return;
698
699         rbtree_deletebydata(xlat_root, c);
700 }
701
702 static int xlat_unregister_callback(void *instance, void *data)
703 {
704         xlat_t *c = (xlat_t *) data;
705
706         if (c->instance != instance) return 0; /* keep walking */
707
708         return 2;               /* delete it */
709 }
710
711 void xlat_unregister_module(void *instance)
712 {
713         rbtree_walk(xlat_root, RBTREE_DELETE_ORDER, xlat_unregister_callback, instance);
714 }
715
716
717 /** Crappy temporary function to add attribute ref support to xlats
718  *
719  * This needs to die, and hopefully will die, when xlat functions accept
720  * xlat node structures.
721  *
722  * Provides either a pointer to a buffer which contains the value of the reference VALUE_PAIR
723  * in an architecture independent format. Or a pointer to the start of the fmt string.
724  *
725  * The pointer is only guaranteed to be valid between calls to xlat_fmt_to_ref,
726  * and so long as the source VALUE_PAIR is not freed.
727  *
728  * @param out where to write a pointer to the buffer to the data the xlat function needs to work on.
729  * @param request current request.
730  * @param fmt string.
731  * @returns the length of the data or -1 on error.
732  */
733 ssize_t xlat_fmt_to_ref(uint8_t const **out, REQUEST *request, char const *fmt)
734 {
735         VALUE_PAIR *vp;
736
737         while (isspace((int) *fmt)) fmt++;
738
739         if (fmt[0] == '&') {
740                 if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
741                         *out = NULL;
742                         return -1;
743                 }
744
745                 return rad_vp2data(out, vp);
746         }
747
748         *out = (uint8_t const *)fmt;
749         return strlen(fmt);
750 }
751
752 /** De-register all xlat functions, used mainly for debugging.
753  *
754  */
755 void xlat_free(void)
756 {
757         rbtree_free(xlat_root);
758 }
759
760
761 #ifdef DEBUG_XLAT
762 #  define XLAT_DEBUG DEBUG3
763 #else
764 #  define XLAT_DEBUG(...)
765 #endif
766
767 static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
768                                        char const **error);
769 static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
770                                      int brace, char const **error);
771 static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const * const head,
772                            RADIUS_ESCAPE_STRING escape, void *escape_ctx);
773
774 static ssize_t xlat_tokenize_alternation(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
775                                          char const **error)
776 {
777         ssize_t slen;
778         char *p;
779         xlat_exp_t *node;
780
781         rad_assert(fmt[0] == '%');
782         rad_assert(fmt[1] == '{');
783         rad_assert(fmt[2] == '%');
784         rad_assert(fmt[3] == '{');
785
786         XLAT_DEBUG("ALTERNATE <-- %s", fmt);
787
788         node = talloc_zero(ctx, xlat_exp_t);
789         node->type = XLAT_ALTERNATE;
790
791         p = fmt + 2;
792         slen = xlat_tokenize_expansion(node, p, &node->child, error);
793         if (slen <= 0) {
794                 talloc_free(node);
795                 return slen - (p - fmt);
796         }
797         p += slen;
798
799         if (p[0] != ':') {
800                 talloc_free(node);
801                 *error = "Expected ':' after first expansion";
802                 return -(p - fmt);
803         }
804         p++;
805
806         if (p[0] != '-') {
807                 talloc_free(node);
808                 *error = "Expected '-' after ':'";
809                 return -(p - fmt);
810         }
811         p++;
812
813         /*
814          *      Allow the RHS to be empty as a special case.
815          */
816         if (*p == '}') {
817                 /*
818                  *      Hack up an empty string.
819                  */
820                 node->alternate = talloc_zero(node, xlat_exp_t);
821                 node->alternate->type = XLAT_LITERAL;
822                 node->alternate->fmt = talloc_typed_strdup(node->alternate, "");
823                 *(p++) = '\0';
824
825         } else {
826                 slen = xlat_tokenize_literal(node, p,  &node->alternate, true, error);
827                 if (slen <= 0) {
828                         talloc_free(node);
829                         return slen - (p - fmt);
830                 }
831
832                 if (!node->alternate) {
833                         talloc_free(node);
834                         *error = "Empty expansion is invalid";
835                         return -(p - fmt);
836                 }
837                 p += slen;
838         }
839
840         *head = node;
841         return p - fmt;
842 }
843
844 static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
845                                        char const **error)
846 {
847         ssize_t slen;
848         char *p, *q, *brace;
849         char const *attrname;
850         xlat_exp_t *node;
851
852         rad_assert(fmt[0] == '%');
853         rad_assert(fmt[1] == '{');
854
855         /*
856          *      %{%{...}:-bar}
857          */
858         if ((fmt[2] == '%') && (fmt[3] == '{')) {
859                 return xlat_tokenize_alternation(ctx, fmt, head, error);
860         }
861
862         XLAT_DEBUG("EXPANSION <-- %s", fmt);
863         node = talloc_zero(ctx, xlat_exp_t);
864         attrname = node->fmt = fmt + 2;
865         node->len = 0;
866
867 #ifdef HAVE_REGEX
868         /*
869          *      Handle regex's specially.
870          */
871         if (isdigit((int) fmt[2]) && (fmt[3] == '}')) {
872                 if (fmt[2] == '9') {
873                         talloc_free(node);
874                         *error = "Invalid regex reference";
875                         return -2;
876                 }
877
878                 XLAT_DEBUG("REGEX <-- %s", fmt);
879                 fmt[3] = '\0';
880                 node->attr.tmpl_num = fmt[2] - '0'; /* ASCII */
881
882                 node->type = XLAT_REGEX;
883                 *head = node;
884                 return 4;
885         }
886 #endif /* HAVE_REGEX */
887
888         /*
889          *      %{Attr-Name}
890          *      %{Attr-Name[#]}
891          *      %{Tunnel-Password:1}
892          *      %{Tunnel-Password:1[#]}
893          *      %{request:Attr-Name}
894          *      %{request:Tunnel-Password:1}
895          *      %{request:Tunnel-Password:1[#]}
896          *      %{mod:foo}
897          */
898          brace = NULL;
899         for (p = fmt + 2; *p != '\0'; p++) {
900                 if (*p == ':') break;
901
902                 if (isspace((int) *p)) break;
903
904                 if (*p == '[') break;
905
906                 if (*p == '}') break;
907         }
908
909         if (*p != ':') p = NULL;
910
911         /*
912          *      Might be a module name reference.
913          */
914         if (p) {
915                 *p = '\0';
916
917                 /*
918                  *      %{mod:foo}
919                  */
920                 node->xlat = xlat_find(node->fmt);
921                 if (node->xlat) {
922                         node->type = XLAT_MODULE;
923
924                         XLAT_DEBUG("MOD <-- %s ... %s", node->fmt, p + 1);
925
926                         slen = xlat_tokenize_literal(node, p + 1, &node->child, true, error);
927                         if (slen <= 0) {
928                                 talloc_free(node);
929                                 return slen - (p - fmt);
930                         }
931                         p += slen + 1;
932
933                         *head = node;
934                         rad_assert(node->next == NULL);
935                         return p - fmt;
936                 }
937
938                 /*
939                  *      Modules can have '}' in their RHS, so we
940                  *      didn't check for that until now.
941                  *
942                  *      As of now, node->fmt MUST be a reference to an
943                  *      attribute, however complicated.  So it MUST have a closing brace.
944                  */
945                 brace = strchr(p + 1, '}');
946                 if (!brace) goto no_brace;
947                 *brace = '\0';
948
949                 /*
950                  *      %{User-Name}
951                  *      %{User-Name[1]}
952                  *      %{Tunnel-Password:1}
953                  *      %{request:Tunnel-Password:1}
954                  *
955                  *      <sigh>  The syntax is fairly poor.
956                  */
957                 XLAT_DEBUG("Looking for list in '%s'", attrname);
958
959                 /*
960                  *      Not a module.  Has to be an attribute
961                  *      reference.
962                  *
963                  *      As of v3, we've removed %{request: ..>} as
964                  *      internally registered xlats.
965                  */
966                 *p = ':';
967                 node->attr.tmpl_request = radius_request_name(&attrname, REQUEST_CURRENT);
968                 rad_assert(node->attr.tmpl_request != REQUEST_UNKNOWN);
969
970                 node->attr.tmpl_list = radius_list_name(&attrname, PAIR_LIST_REQUEST);
971                 if (node->attr.tmpl_list == PAIR_LIST_UNKNOWN) {
972                         talloc_free(node);
973                         *error = "Unknown module";
974                         return -2;
975                 }
976
977                 /*
978                  *      Check for a trailing tag.
979                  */
980                 p = strchr(attrname, ':');
981                 if (p) *p = '\0';
982
983         } else {
984                 brace = strchr(attrname, '}');
985                 if (!brace) {
986                 no_brace:
987                         talloc_free(node);
988                         *error = "No matching closing brace";
989                         return -1;      /* second character of format string */
990                 }
991                 *brace = '\0';
992
993                 node->attr.tmpl_request = REQUEST_CURRENT;
994                 node->attr.tmpl_list = PAIR_LIST_REQUEST;
995         }
996
997         *brace = '\0';
998
999         XLAT_DEBUG("Looking for attribute name in %s", attrname);
1000
1001         /*
1002          *      Allow for an array reference.  They come AFTER the
1003          *      tag, if the tag exists.  Otherwise, they come after
1004          *      the attribute name.
1005          */
1006         if (p) {
1007                 q = strchr(p + 1, '[');
1008         } else {
1009                 q = strchr(attrname, '[');
1010         }
1011         if (q) *(q++) = '\0';
1012
1013         if (!*attrname) {
1014                 talloc_free(node);
1015                 *error = "Empty expression is invalid";
1016                 return -(attrname - fmt);
1017         }
1018
1019         /*
1020          *      It's either an attribute name, or a Tunnel-Password:TAG
1021          *      with the ':' already set to NULL.
1022          */
1023         node->attr.tmpl_da = dict_attrbyname(attrname);
1024         if (!node->attr.tmpl_da) {
1025                 /*
1026                  *      Foreach.  Maybe other stuff, too.
1027                  */
1028                 node->xlat = xlat_find(attrname);
1029                 if (node->xlat) {
1030                         node->type = XLAT_VIRTUAL;
1031                         node->fmt = attrname;
1032
1033                         XLAT_DEBUG("VIRTUAL <-- %s", node->fmt);
1034                         *head = node;
1035                         rad_assert(node->next == NULL);
1036                         brace++;
1037                         return brace - fmt;
1038                 }
1039
1040                 talloc_free(node);
1041                 *error = "Unknown attribute";
1042                 return -(attrname - fmt);
1043         }
1044
1045         /*
1046          *      Parse the tag.
1047          */
1048         if (p) {
1049                 unsigned long tag;
1050                 char *end;
1051
1052                 if (!node->attr.tmpl_da->flags.has_tag) {
1053                         talloc_free(node);
1054                         *error = "Attribute cannot have a tag";
1055                         return - (p - fmt);
1056                 }
1057
1058                 tag = strtoul(p + 1, &end, 10);
1059                 p++;
1060
1061                 if (tag == ULONG_MAX) {
1062                         talloc_free(node);
1063                         *error = "Invalid tag value";
1064                         return - (p - fmt);
1065                 }
1066
1067                 node->attr.tmpl_tag = tag;
1068                 p = end;
1069
1070                 if (*p) {
1071                         talloc_free(node);
1072                         *error = "Unexpected text after tag";
1073                         return - (p - fmt);
1074                 }
1075
1076         } else {
1077                 node->attr.tmpl_tag = TAG_ANY;
1078                 /* leave p alone */
1079         }
1080
1081         /*
1082          *      Check for array reference
1083          */
1084         if (q) {
1085                 unsigned long num;
1086                 char *end;
1087
1088                 p = q;
1089                 if (*p== '#') {
1090                         node->attr.tmpl_num = NUM_COUNT;
1091                         p++;
1092
1093                 } else if (*p == '*') {
1094                         node->attr.tmpl_num = NUM_ALL;
1095                         p++;
1096
1097                 } else if (isdigit((int) *p)) {
1098                         num = strtoul(p, &end, 10);
1099                         if (num > 1000) {
1100                                 talloc_free(node);
1101                                 *error = "Invalid array index";
1102                                 return - (p - fmt);
1103                         }
1104                         p = end;
1105                         node->attr.tmpl_num = num;
1106
1107                 } else {
1108                         talloc_free(node);
1109                         *error = "Invalid array index";
1110                         return - (p - fmt);
1111                 }
1112
1113                 if (*p != ']') {
1114                         talloc_free(node);
1115                         *error = "Expected ']'";
1116                         return - (p - fmt);
1117                 }
1118
1119                 p++;
1120                 if (*p) {
1121                         talloc_free(node);
1122                         *error = "Unexpected text after array reference";
1123                         return - (p - fmt);
1124                 }
1125         } else {
1126                 node->attr.tmpl_num = NUM_ANY;
1127         }
1128
1129         rad_assert(!p || (p == brace));
1130
1131         node->type = XLAT_ATTRIBUTE;
1132         p = brace + 1;
1133
1134         *head = node;
1135         rad_assert(node->next == NULL);
1136         return p - fmt;
1137 }
1138
1139
1140 static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1141                                      int brace, char const **error)
1142 {
1143         char *p;
1144         xlat_exp_t *node;
1145
1146         if (!*fmt) return 0;
1147
1148         XLAT_DEBUG("LITERAL <-- %s", fmt);
1149
1150         node = talloc_zero(ctx, xlat_exp_t);
1151         node->fmt = fmt;
1152         node->len = 0;
1153         node->type = XLAT_LITERAL;
1154
1155         p = fmt;
1156
1157         while (*p) {
1158                 if (*p == '\\') {
1159                         if (!p[1]) {
1160                                 talloc_free(node);
1161                                 *error = "Invalid escape at end of string";
1162                                 return -(p - fmt);
1163                         }
1164                         p += 2;
1165                         continue;
1166                 }
1167
1168                 /*
1169                  *      Process the expansion.
1170                  */
1171                 if ((p[0] == '%') && (p[1] == '{')) {
1172                         ssize_t slen;
1173
1174                         XLAT_DEBUG("LITERAL <-- %s", node->fmt);
1175
1176                         slen = xlat_tokenize_expansion(node, p, &node->next, error);
1177                         if (slen <= 0) {
1178                                 talloc_free(node);
1179                                 return slen - (p - fmt);
1180                         }
1181                         *p = '\0'; /* end the literal */
1182                         p += slen;
1183
1184                         rad_assert(node->next != NULL);
1185
1186                         /*
1187                          *      Short-circuit the recursive call.
1188                          *      This saves another function call and
1189                          *      memory allocation.
1190                          */
1191                         if (!*p) break;
1192
1193                         /*
1194                          *      "foo %{User-Name} bar"
1195                          *      LITERAL         "foo "
1196                          *      EXPANSION       User-Name
1197                          *      LITERAL         " bar"
1198                          */
1199                         slen = xlat_tokenize_literal(node->next, p, &(node->next->next), brace, error);
1200                         rad_assert(slen != 0);
1201                         if (slen < 0) {
1202                                 talloc_free(node);
1203                                 return slen - (p - fmt);
1204                         }
1205
1206                         p += slen;
1207                         break;  /* stop processing the string */
1208                 }
1209
1210                 /*
1211                  *      Check for valid single-character expansions.
1212                  */
1213                 if (p[0] == '%') {
1214                         ssize_t slen;
1215                         xlat_exp_t *next;
1216
1217                         if (!p[1] || !strchr("%dlmtDGHISTYv", p[1])) {
1218                                         talloc_free(node);
1219                                         *error = "Invalid variable expansion";
1220                                         p++;
1221                                         return - (p - fmt);
1222                         }
1223
1224                         next = talloc_zero(node, xlat_exp_t);
1225                         next->len = 1;
1226
1227                         if (p[1] == '%') {
1228                                 next->fmt = talloc_typed_strdup(next, "%");
1229
1230                                 XLAT_DEBUG("LITERAL <-- %s", next->fmt);
1231                                 next->type = XLAT_LITERAL;
1232
1233                         } else {
1234                                 next->fmt = p + 1;
1235
1236                                 XLAT_DEBUG("PERCENT <-- %c", *next->fmt);
1237                                 next->type = XLAT_PERCENT;
1238                         }
1239
1240                         node->next = next;
1241                         *p = '\0';
1242                         p += 2;
1243
1244                         if (!*p) break;
1245
1246                         /*
1247                          *      And recurse.
1248                          */
1249                         slen = xlat_tokenize_literal(node->next, p, &(node->next->next), brace, error);
1250                         rad_assert(slen != 0);
1251                         if (slen < 0) {
1252                                 talloc_free(node);
1253                                 return slen - (p - fmt);
1254                         }
1255
1256                         p += slen;
1257                         break;  /* stop processing the string */
1258                 }
1259
1260                 /*
1261                  *      If required, eat the brace.
1262                  */
1263                 if (brace && (*p == '}')) {
1264                         *p = '\0';
1265                         p++;
1266                         break;
1267                 }
1268
1269                 p++;
1270                 node->len++;
1271         }
1272
1273         /*
1274          *      Squash zero-width literals
1275          */
1276         if (node->len > 0) {
1277                 *head = node;
1278         } else {
1279                 *head = talloc_steal(ctx, node->next);
1280                 talloc_free(node);
1281         }
1282
1283         return p - fmt;
1284 }
1285
1286
1287 static char const xlat_tabs[] = "                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ";
1288
1289 static void xlat_tokenize_debug(xlat_exp_t const *node, int lvl)
1290 {
1291         rad_assert(node != NULL);
1292
1293         if (lvl >= (int) sizeof(xlat_tabs)) lvl = sizeof(xlat_tabs);
1294
1295         while (node) {
1296                 switch (node->type) {
1297                 case XLAT_LITERAL:
1298                         DEBUG("%.*sliteral --> %s", lvl, xlat_tabs, node->fmt);
1299                         break;
1300
1301                 case XLAT_PERCENT:
1302                         DEBUG("%.*spercent --> %c", lvl, xlat_tabs, node->fmt[0]);
1303                         break;
1304
1305                 case XLAT_ATTRIBUTE:
1306                         rad_assert(node->attr.tmpl_da != NULL);
1307                         DEBUG("%.*sattribute --> %s", lvl, xlat_tabs, node->attr.tmpl_da->name);
1308                         rad_assert(node->child == NULL);
1309                         if ((node->attr.tmpl_tag != TAG_ANY) || (node->attr.tmpl_num != NUM_ANY)) {
1310                                 DEBUG("%.*s{", lvl, xlat_tabs);
1311
1312                                 DEBUG("%.*sref  %d", lvl + 1, xlat_tabs, node->attr.tmpl_request);
1313                                 DEBUG("%.*slist %d", lvl + 1, xlat_tabs, node->attr.tmpl_list);
1314
1315                                 if (node->attr.tmpl_tag != TAG_ANY) {
1316                                         DEBUG("%.*stag %d", lvl + 1, xlat_tabs, node->attr.tmpl_tag);
1317                                 }
1318                                 if (node->attr.tmpl_num != NUM_ANY) {
1319                                         if (node->attr.tmpl_num == NUM_COUNT) {
1320                                                 DEBUG("%.*s[#]", lvl + 1, xlat_tabs);
1321                                         } else if (node->attr.tmpl_num == NUM_ALL) {
1322                                                 DEBUG("%.*s[*]", lvl + 1, xlat_tabs);
1323                                         } else {
1324                                                 DEBUG("%.*s[%d]", lvl + 1, xlat_tabs, node->attr.tmpl_num);
1325                                         }
1326                                 }
1327
1328                                 DEBUG("%.*s}", lvl, xlat_tabs);
1329                         }
1330                         break;
1331
1332                 case XLAT_VIRTUAL:
1333                         rad_assert(node->fmt != NULL);
1334                         DEBUG("%.*svirtual --> %s", lvl, xlat_tabs, node->fmt);
1335                         break;
1336
1337                 case XLAT_MODULE:
1338                         rad_assert(node->xlat != NULL);
1339                         DEBUG("%.*sxlat --> %s", lvl, xlat_tabs, node->xlat->name);
1340                         if (node->child) {
1341                                 DEBUG("%.*s{", lvl, xlat_tabs);
1342                                 xlat_tokenize_debug(node->child, lvl + 1);
1343                                 DEBUG("%.*s}", lvl, xlat_tabs);
1344                         }
1345                         break;
1346
1347 #ifdef HAVE_REGEX
1348                 case XLAT_REGEX:
1349                         DEBUG("%.*sregex-var --> %d", lvl, xlat_tabs, node->attr.tmpl_num);
1350                         break;
1351 #endif
1352
1353                 case XLAT_ALTERNATE:
1354                         DEBUG("%.*sif {", lvl, xlat_tabs);
1355                         xlat_tokenize_debug(node->child, lvl + 1);
1356                         DEBUG("%.*s}", lvl, xlat_tabs);
1357                         DEBUG("%.*selse {", lvl, xlat_tabs);
1358                         xlat_tokenize_debug(node->alternate, lvl + 1);
1359                         DEBUG("%.*s}", lvl, xlat_tabs);
1360                         break;
1361                 }
1362                 node = node->next;
1363         }
1364 }
1365
1366 size_t xlat_sprint(char *buffer, size_t bufsize, xlat_exp_t const *node)
1367 {
1368         size_t len;
1369         char *p, *end;
1370
1371         if (!node) {
1372                 *buffer = '\0';
1373                 return 0;
1374         }
1375
1376         p = buffer;
1377         end = buffer + bufsize;
1378
1379         while (node) {
1380                 switch (node->type) {
1381                 case XLAT_LITERAL:
1382                         strlcpy(p, node->fmt, end - p);
1383                         p += strlen(p);
1384                         break;
1385
1386                 case XLAT_PERCENT:
1387                         p[0] = '%';
1388                         p[1] = node->fmt[0];
1389                         p += 2;
1390                         break;
1391
1392                 case XLAT_ATTRIBUTE:
1393                         *(p++) = '%';
1394                         *(p++) = '{';
1395
1396                         if (node->attr.tmpl_request != REQUEST_CURRENT) {
1397                                 strlcpy(p, fr_int2str(request_refs, node->attr.tmpl_request, "??"), end - p);
1398                                 p += strlen(p);
1399                                 *(p++) = '.';
1400                         }
1401
1402                         if ((node->attr.tmpl_request != REQUEST_CURRENT) ||
1403                             (node->attr.tmpl_list != PAIR_LIST_REQUEST)) {
1404                                 strlcpy(p, fr_int2str(pair_lists, node->attr.tmpl_list, "??"), end - p);
1405                                 p += strlen(p);
1406                                 *(p++) = ':';
1407                         }
1408
1409                         strlcpy(p, node->attr.tmpl_da->name, end - p);
1410                         p += strlen(p);
1411
1412                         if (node->attr.tmpl_tag != TAG_ANY) {
1413                                 *(p++) = ':';
1414                                 snprintf(p, end - p, "%u", node->attr.tmpl_tag);
1415                                 p += strlen(p);
1416                         }
1417
1418                         if (node->attr.tmpl_num != NUM_ANY) {
1419                                 *(p++) = '[';
1420                                 switch (node->attr.tmpl_num) {
1421                                 case NUM_COUNT:
1422                                         *(p++) = '#';
1423                                         break;
1424
1425                                 case NUM_ALL:
1426                                         *(p++) = '*';
1427                                         break;
1428
1429                                 default:
1430                                         snprintf(p, end - p, "%i", node->attr.tmpl_num);
1431                                         p += strlen(p);
1432                                 }
1433                                 *(p++) = ']';
1434                         }
1435                         *(p++) = '}';
1436                         break;
1437 #ifdef HAVE_REGEX
1438                 case XLAT_REGEX:
1439                         snprintf(p, end - p, "%%{%i}", node->attr.tmpl_num);
1440                         p += strlen(p);
1441                         break;
1442 #endif
1443                 case XLAT_VIRTUAL:
1444                         *(p++) = '%';
1445                         *(p++) = '{';
1446                         strlcpy(p, node->fmt, end - p);
1447                         p += strlen(p);
1448                         *(p++) = '}';
1449                         break;
1450
1451                 case XLAT_MODULE:
1452                         *(p++) = '%';
1453                         *(p++) = '{';
1454                         strlcpy(p, node->xlat->name, end - p);
1455                         p += strlen(p);
1456                         *(p++) = ':';
1457                         rad_assert(node->child != NULL);
1458                         len = xlat_sprint(p, end - p, node->child);
1459                         p += len;
1460                         *(p++) = '}';
1461                         break;
1462
1463                 case XLAT_ALTERNATE:
1464                         *(p++) = '%';
1465                         *(p++) = '{';
1466
1467                         len = xlat_sprint(p, end - p, node->child);
1468                         p += len;
1469
1470                         *(p++) = ':';
1471                         *(p++) = '-';
1472
1473                         len = xlat_sprint(p, end - p, node->alternate);
1474                         p += len;
1475
1476                         *(p++) = '}';
1477                         break;
1478                 }
1479
1480
1481                 if (p == end) break;
1482
1483                 node = node->next;
1484         }
1485
1486         *p = '\0';
1487
1488         return p - buffer;
1489 }
1490
1491 ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1492                       char const **error)
1493 {
1494         return xlat_tokenize_literal(ctx, fmt, head, false, error);
1495 }
1496
1497
1498 /** Tokenize an xlat expansion
1499  *
1500  * @param[in] request the input request.  Memory will be attached here.
1501  * @param[in] fmt the format string to expand
1502  * @param[out] head the head of the xlat list / tree structure.
1503  */
1504 static ssize_t xlat_tokenize_request(REQUEST *request, char const *fmt, xlat_exp_t **head)
1505 {
1506         ssize_t slen;
1507         char *tokens;
1508         char const *error;
1509
1510         *head = NULL;
1511
1512         /*
1513          *      Copy the original format string to a buffer so that
1514          *      the later functions can mangle it in-place, which is
1515          *      much faster.
1516          */
1517         tokens = talloc_typed_strdup(request, fmt);
1518         if (!tokens) return -1;
1519
1520         slen = xlat_tokenize_literal(request, tokens, head, false, &error);
1521
1522         /*
1523          *      Zero length expansion, return a zero length node.
1524          */
1525         if (slen == 0) {
1526                 *head = talloc_zero(request, xlat_exp_t);
1527         }
1528
1529         /*
1530          *      Output something like:
1531          *
1532          *      "format string"
1533          *      "       ^ error was here"
1534          */
1535         if (slen < 0) {
1536                 talloc_free(tokens);
1537                 rad_assert(error != NULL);
1538
1539                 REMARKER(fmt, -slen, error);
1540                 return slen;
1541         }
1542
1543         if (*head && (debug_flag > 2)) {
1544                 DEBUG("%s", fmt);
1545                 DEBUG("Parsed xlat tree:");
1546                 xlat_tokenize_debug(*head, 0);
1547         }
1548
1549         /*
1550          *      All of the nodes point to offsets in the "tokens"
1551          *      string.  Let's ensure that free'ing head will free
1552          *      "tokens", too.
1553          */
1554         (void) talloc_steal(*head, tokens);
1555
1556         return slen;
1557 }
1558
1559
1560 static char *xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, pair_lists_t list, DICT_ATTR const *da,
1561                         int8_t tag, int num, bool return_null)
1562 {
1563         VALUE_PAIR *vp, *vps = NULL, *myvp = NULL;
1564         RADIUS_PACKET *packet = NULL;
1565         DICT_VALUE *dv;
1566         char *ret = NULL;
1567
1568         /*
1569          *      Arg.  Too much abstraction is annoying.
1570          */
1571         switch (list) {
1572         default:
1573                 if (return_null) return NULL;
1574                 return vp_aprint_type(ctx, da->type);
1575
1576         case PAIR_LIST_CONTROL:
1577                 vps = request->config_items;
1578                 break;
1579
1580         case PAIR_LIST_REQUEST:
1581                 packet = request->packet;
1582                 if (packet) vps = packet->vps;
1583                 break;
1584
1585         case PAIR_LIST_REPLY:
1586                 packet = request->reply;
1587                 if (packet) vps = packet->vps;
1588                 break;
1589
1590 #ifdef WITH_PROXY
1591         case PAIR_LIST_PROXY_REQUEST:
1592                 packet = request->proxy;
1593                 if (packet) vps = packet->vps;
1594                 break;
1595
1596         case PAIR_LIST_PROXY_REPLY:
1597                 packet = request->proxy_reply;
1598                 if (packet) vps = packet->vps;
1599                 break;
1600 #endif
1601
1602 #ifdef WITH_COA
1603         case PAIR_LIST_COA:
1604         case PAIR_LIST_DM:
1605                 if (request->coa) packet = request->coa->packet;
1606                 if (packet) vps = packet->vps;
1607                 break;
1608
1609         case PAIR_LIST_COA_REPLY:
1610         case PAIR_LIST_DM_REPLY:
1611                 if (request->coa) packet = request->coa->reply;
1612                 if (packet) vps = packet->vps;
1613                 break;
1614
1615 #endif
1616         }
1617
1618         /*
1619          *      Now we have the list, check to see if we have an attribute in
1620          *      the request, if we do, it takes precedence over the virtual
1621          *      attributes.
1622          *
1623          *      This allows users to manipulate virtual attributes as if they
1624          *      were real ones.
1625          */
1626         vp = pairfind(vps, da->attr, da->vendor, tag);
1627         if (vp) goto do_print;
1628
1629         /*
1630          *      We didn't find the VP in a list.  It MIGHT be a
1631          *      virtual one, in which case we do lots more checks
1632          *      below.  However, if we're looking for a normal
1633          *      attribute, it must exist, and therefore not finding it
1634          *      means we return NULL.
1635          */
1636         if (!da->flags.virtual) return NULL;
1637
1638         /*
1639          *      Some non-packet expansions
1640          */
1641         switch (da->attr) {
1642         default:
1643                 break;          /* ignore them */
1644
1645         case PW_CLIENT_SHORTNAME:
1646                 if (num == NUM_COUNT) goto count;
1647                 if (request->client && request->client->shortname) {
1648                         return talloc_typed_strdup(ctx, request->client->shortname);
1649                 }
1650                 return talloc_typed_strdup(ctx, "<UNKNOWN-CLIENT>");
1651
1652         case PW_REQUEST_PROCESSING_STAGE:
1653                 if (num == NUM_COUNT) goto count;
1654                 if (request->component) {
1655                         return talloc_typed_strdup(ctx, request->component);
1656                 }
1657                 return talloc_typed_strdup(ctx, "server_core");
1658
1659         case PW_VIRTUAL_SERVER:
1660                 if (num == NUM_COUNT) goto count;
1661                 if (!request->server) return NULL;
1662                 return talloc_typed_strdup(ctx, request->server);
1663
1664         case PW_MODULE_RETURN_CODE:
1665                 if (num == NUM_COUNT) goto count;
1666                 if (!request->rcode) return NULL;
1667                 return talloc_typed_strdup(ctx, fr_int2str(modreturn_table, request->rcode, ""));
1668         }
1669
1670         /*
1671          *      All of the attributes must now refer to a packet.
1672          *      If there's no packet, we can't print any attribute
1673          *      referencing it.
1674          */
1675         if (!packet) {
1676                 if (return_null) return NULL;
1677                 return vp_aprint_type(ctx, da->type);
1678         }
1679
1680         vp = NULL;
1681         switch (da->attr) {
1682         default:
1683                 break;
1684
1685         case PW_PACKET_TYPE:
1686                 dv = dict_valbyattr(PW_PACKET_TYPE, 0, packet->code);
1687                 if (dv) return talloc_typed_strdup(ctx, dv->name);
1688                 return talloc_typed_asprintf(ctx, "%d", packet->code);
1689
1690         case PW_RESPONSE_PACKET_TYPE:
1691         {
1692                 int code = 0;
1693
1694 #ifdef WITH_PROXY
1695                 if (request->proxy_reply && (!request->reply || !request->reply->code)) {
1696                         code = request->proxy_reply->code;
1697                 } else
1698 #endif
1699                         if (request->reply) {
1700                                 code = request->reply->code;
1701                         }
1702
1703                 return talloc_typed_strdup(ctx, fr_packet_codes[code]);
1704         }
1705
1706         /*
1707          *      Virtual attributes which require a temporary VALUE_PAIR
1708          *      to be allocated. We can't use stack allocated memory
1709          *      because of the talloc checks sprinkled throughout the
1710          *      various VP functions.
1711          */
1712         case PW_PACKET_AUTHENTICATION_VECTOR:
1713                 myvp = pairalloc(ctx, da);
1714                 pairmemcpy(myvp, packet->vector, sizeof(packet->vector));
1715                 vp = myvp;
1716                 break;
1717
1718         case PW_CLIENT_IP_ADDRESS:
1719         case PW_PACKET_SRC_IP_ADDRESS:
1720                 if (packet->src_ipaddr.af == AF_INET) {
1721                         myvp = pairalloc(ctx, da);
1722                         myvp->vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
1723                         vp = myvp;
1724                 }
1725                 break;
1726
1727         case PW_PACKET_DST_IP_ADDRESS:
1728                 if (packet->dst_ipaddr.af == AF_INET) {
1729                         myvp = pairalloc(ctx, da);
1730                         myvp->vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
1731                         vp = myvp;
1732                 }
1733                 break;
1734
1735         case PW_PACKET_SRC_IPV6_ADDRESS:
1736                 if (packet->src_ipaddr.af == AF_INET6) {
1737                         myvp = pairalloc(ctx, da);
1738                         memcpy(&myvp->vp_ipv6addr,
1739                                &packet->src_ipaddr.ipaddr.ip6addr,
1740                                sizeof(packet->src_ipaddr.ipaddr.ip6addr));
1741                         vp = myvp;
1742                 }
1743                 break;
1744
1745         case PW_PACKET_DST_IPV6_ADDRESS:
1746                 if (packet->dst_ipaddr.af == AF_INET6) {
1747                         myvp = pairalloc(ctx, da);
1748                         memcpy(&myvp->vp_ipv6addr,
1749                                &packet->dst_ipaddr.ipaddr.ip6addr,
1750                                sizeof(packet->dst_ipaddr.ipaddr.ip6addr));
1751                         vp = myvp;
1752                 }
1753                 break;
1754
1755         case PW_PACKET_SRC_PORT:
1756                 myvp = pairalloc(ctx, da);
1757                 myvp->vp_integer = packet->src_port;
1758                 vp = myvp;
1759                 break;
1760
1761         case PW_PACKET_DST_PORT:
1762                 myvp = pairalloc(ctx, da);
1763                 myvp->vp_integer = packet->dst_port;
1764                 vp = myvp;
1765                 break;
1766         }
1767
1768         /*
1769          *      Fake various operations for virtual attributes.
1770          */
1771         if (myvp) {
1772                 if (num != NUM_ANY) switch (num) {
1773                 /*
1774                  *      [n] is NULL (we only have [0])
1775                  */
1776                 default:
1777                         goto finish;
1778                 /*
1779                  *      [*] means only one.
1780                  */
1781                 case NUM_ALL:
1782                         break;
1783
1784                 /*
1785                  *      [#] means 1 (as there's only one)
1786                  */
1787                 case NUM_COUNT:
1788                 count:
1789                         ret = talloc_strdup(ctx, "1");
1790                         goto finish;
1791
1792                 /*
1793                  *      [0] is fine (get the first instance)
1794                  */
1795                 case 0:
1796                         break;
1797                 }
1798                 goto print;
1799         }
1800
1801 do_print:
1802         /*
1803          *      We want the N'th VP.
1804          */
1805         if (num != NUM_ANY) {
1806                 int count = 0;
1807                 vp_cursor_t cursor;
1808
1809                 switch (num) {
1810                 /*
1811                  *      Return a count of the VPs.
1812                  */
1813                 case NUM_COUNT:
1814                         fr_cursor_init(&cursor, &vp);
1815                         while (fr_cursor_next_by_da(&cursor, da, tag) != NULL) {
1816                                 count++;
1817                         }
1818                         return talloc_typed_asprintf(ctx, "%d", count);
1819
1820                 /*
1821                  *      Ugly, but working.
1822                  */
1823                 case NUM_ALL:
1824                 {
1825                         char *p, *q;
1826
1827                         (void) fr_cursor_init(&cursor, &vp);
1828                         vp = fr_cursor_next_by_da(&cursor, da, tag);
1829                         if (!vp) return NULL;
1830
1831                         p = vp_aprints_value(ctx, vp, '"');
1832                         if (!p) return NULL;
1833                         while ((vp = fr_cursor_next_by_da(&cursor, da, tag)) != NULL) {
1834                                 q = vp_aprints_value(ctx, vp, '"');
1835                                 if (!q) return NULL;
1836                                 p = talloc_strdup_append(p, ",");
1837                                 p = talloc_strdup_append(p, q);
1838                         }
1839
1840                         return p;
1841                 }
1842
1843                 default:
1844                         fr_cursor_init(&cursor, &vp);
1845                         while ((vp = fr_cursor_next_by_da(&cursor, da, tag)) != NULL) {
1846                                 if (count++ == num) break;
1847                         }
1848                         break;
1849                 }
1850         }
1851
1852         if (!vp) {
1853                 if (return_null) return NULL;
1854                 return vp_aprint_type(ctx, da->type);
1855         }
1856
1857 print:
1858         ret = vp_aprints_value(ctx, vp, '"');
1859
1860 finish:
1861         talloc_free(myvp);
1862         return ret;
1863 }
1864
1865 #ifdef DEBUG_XLAT
1866 static const char xlat_spaces[] = "                                                                                                                                                                                                                                                                ";
1867 #endif
1868
1869 static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * const node,
1870                          RADIUS_ESCAPE_STRING escape, void *escape_ctx, int lvl)
1871 {
1872         ssize_t rcode;
1873         char *str = NULL, *child;
1874         char *q;
1875         char const *p;
1876         REQUEST *ref;
1877
1878         XLAT_DEBUG("%.*sxlat aprint %d", lvl, xlat_spaces, node->type);
1879
1880         switch (node->type) {
1881                 /*
1882                  *      Don't escape this.
1883                  */
1884         case XLAT_LITERAL:
1885                 XLAT_DEBUG("xlat_aprint LITERAL");
1886                 return talloc_typed_strdup(ctx, node->fmt);
1887
1888                 /*
1889                  *      Do a one-character expansion.
1890                  */
1891         case XLAT_PERCENT:
1892         {
1893                 char *nl;
1894                 size_t freespace = 256;
1895                 struct tm ts;
1896                 time_t when;
1897
1898                 XLAT_DEBUG("xlat_aprint PERCENT");
1899
1900                 str = talloc_array(ctx, char, freespace); /* @todo do better allocation */
1901                 p = node->fmt;
1902
1903                 when = request->timestamp;
1904                 if (request->packet) {
1905                         when = request->packet->timestamp.tv_sec;
1906                 }
1907
1908                 switch (*p) {
1909                 case '%':
1910                         str[0] = '%';
1911                         str[1] = '\0';
1912                         break;
1913
1914                 case 'd': /* request day */
1915                         (void) localtime_r(&when, &ts);
1916                         strftime(str, freespace, "%d", &ts);
1917                         break;
1918
1919                 case 'l': /* request timestamp */
1920                         snprintf(str, freespace, "%lu",
1921                                  (unsigned long) when);
1922                         break;
1923
1924                 case 'm': /* request month */
1925                         (void) localtime_r(&when, &ts);
1926                         strftime(str, freespace, "%m", &ts);
1927                         break;
1928
1929                 case 'n': /* Request Number*/
1930                         snprintf(str, freespace, "%u", request->number);
1931                         break;
1932
1933                 case 't': /* request timestamp */
1934                         CTIME_R(&when, str, freespace);
1935                         nl = strchr(str, '\n');
1936                         if (nl) *nl = '\0';
1937                         break;
1938
1939                 case 'D': /* request date */
1940                         (void) localtime_r(&when, &ts);
1941                         strftime(str, freespace, "%Y%m%d", &ts);
1942                         break;
1943
1944                 case 'G': /* request minute */
1945                         (void) localtime_r(&when, &ts);
1946                         strftime(str, freespace, "%M", &ts);
1947                         break;
1948
1949                 case 'H': /* request hour */
1950                         (void) localtime_r(&when, &ts);
1951                         strftime(str, freespace, "%H", &ts);
1952                         break;
1953
1954                 case 'I': /* Request ID */
1955                         if (request->packet) {
1956                                 snprintf(str, freespace, "%i", request->packet->id);
1957                         }
1958                         break;
1959
1960                 case 'S': /* request timestamp in SQL format*/
1961                         (void) localtime_r(&when, &ts);
1962                         strftime(str, freespace, "%Y-%m-%d %H:%M:%S", &ts);
1963                         break;
1964
1965                 case 'T': /* request timestamp */
1966                         (void) localtime_r(&when, &ts);
1967                         strftime(str, freespace, "%Y-%m-%d-%H.%M.%S.000000", &ts);
1968                         break;
1969
1970                 case 'Y': /* request year */
1971                         (void) localtime_r(&when, &ts);
1972                         strftime(str, freespace, "%Y", &ts);
1973                         break;
1974
1975                 case 'v': /* Version of code */
1976                         snprintf(str, freespace, "%s", radiusd_short_version);
1977                         break;
1978
1979                 default:
1980                         rad_assert(0 == 1);
1981                         break;
1982                 }
1983         }
1984                 break;
1985
1986         case XLAT_ATTRIBUTE:
1987                 XLAT_DEBUG("xlat_aprint ATTRIBUTE");
1988                 ref = request;
1989                 if (radius_request(&ref, node->attr.tmpl_request) < 0) {
1990                         return NULL;
1991                 }
1992
1993                 /*
1994                  *      Some attributes are virtual <sigh>
1995                  */
1996                 str = xlat_getvp(ctx, ref, node->attr.tmpl_list, node->attr.tmpl_da, node->attr.tmpl_tag, node->attr.tmpl_num, true);
1997                 if (str) {
1998                         XLAT_DEBUG("EXPAND attr %s", node->attr.tmpl_da->name);
1999                         XLAT_DEBUG("       ---> %s", str);
2000                 }
2001                 break;
2002
2003         case XLAT_VIRTUAL:
2004                 XLAT_DEBUG("xlat_aprint VIRTUAL");
2005                 str = talloc_array(ctx, char, 2048); /* FIXME: have the module call talloc_typed_asprintf */
2006                 rcode = node->xlat->func(node->xlat->instance, request, NULL, str, 2048);
2007                 if (rcode < 0) {
2008                         talloc_free(str);
2009                         return NULL;
2010                 }
2011                 break;
2012
2013         case XLAT_MODULE:
2014                 XLAT_DEBUG("xlat_aprint MODULE");
2015                 if (xlat_process(&child, request, node->child, node->xlat->escape, node->xlat->instance) == 0) {
2016                         return NULL;
2017                 }
2018
2019                 XLAT_DEBUG("%.*sEXPAND mod %s %s", lvl, xlat_spaces, node->fmt, node->child->fmt);
2020                 XLAT_DEBUG("%.*s      ---> %s", lvl, xlat_spaces, child);
2021
2022                 /*
2023                  *      Smash \n --> CR.
2024                  *
2025                  *      The OUTPUT of xlat is a printable string.  The INPUT might not be...
2026                  *
2027                  *      This is really the reverse of fr_print_string().
2028                  */
2029                 p = q = child;
2030                 while (*p) {
2031                         if (*p == '\\') switch (p[1]) {
2032                                 default:
2033                                         *(q++) = p[1];
2034                                         p += 2;
2035                                         continue;
2036
2037                                 case 'n':
2038                                         *(q++) = '\n';
2039                                         p += 2;
2040                                         continue;
2041
2042                                 case 't':
2043                                         *(q++) = '\t';
2044                                         p += 2;
2045                                         continue;
2046                         }
2047
2048                         *(q++) = *(p++);
2049                 }
2050                 *q = '\0';
2051
2052                 str = talloc_array(ctx, char, 2048); /* FIXME: have the module call talloc_typed_asprintf */
2053                 *str = '\0';    /* Be sure the string is NULL terminated, we now only free on error */
2054
2055                 rcode = node->xlat->func(node->xlat->instance, request, child, str, 2048);
2056                 talloc_free(child);
2057                 if (rcode < 0) {
2058                         talloc_free(str);
2059                         return NULL;
2060                 }
2061                 break;
2062
2063 #ifdef HAVE_REGEX
2064         case XLAT_REGEX:
2065                 XLAT_DEBUG("xlat_aprint REGEX");
2066                 child = request_data_reference(request, request,
2067                                                REQUEST_DATA_REGEX | node->attr.tmpl_num);
2068                 if (!child) return NULL;
2069
2070                 str = talloc_typed_strdup(ctx, child);
2071                 break;
2072 #endif
2073
2074         case XLAT_ALTERNATE:
2075                 XLAT_DEBUG("xlat_aprint ALTERNATE");
2076                 rad_assert(node->child != NULL);
2077                 rad_assert(node->alternate != NULL);
2078
2079                 str = xlat_aprint(ctx, request, node->child, escape, escape_ctx, lvl);
2080                 if (str) break;
2081
2082                 str = xlat_aprint(ctx, request, node->alternate, escape, escape_ctx, lvl);
2083                 break;
2084
2085         }
2086
2087         /*
2088          *      Escape the non-literals we found above.
2089          */
2090         if (str && escape) {
2091                 char *escaped;
2092
2093                 escaped = talloc_array(ctx, char, 2048); /* FIXME: do something intelligent */
2094                 escape(request, escaped, 2038, str, escape_ctx);
2095                 talloc_free(str);
2096                 str = escaped;
2097         }
2098
2099         return str;
2100 }
2101
2102
2103 static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const * const head,
2104                            RADIUS_ESCAPE_STRING escape, void *escape_ctx)
2105 {
2106         int i, list;
2107         size_t total;
2108         char **array, *answer;
2109         xlat_exp_t const *node;
2110
2111         *out = NULL;
2112
2113         /*
2114          *      There are no nodes to process, so the result is a zero
2115          *      length string.
2116          */
2117         if (!head) {
2118                 *out = talloc_zero_array(request, char, 1);
2119                 return 0;
2120         }
2121
2122         /*
2123          *      Hack for speed.  If it's one expansion, just allocate
2124          *      that and return, instead of allocating an intermediary
2125          *      array.
2126          */
2127         if (!head->next) {
2128                 /*
2129                  *      Pass the MAIN escape function.  Recursive
2130                  *      calls will call node-specific escape
2131                  *      functions.
2132                  */
2133                 answer = xlat_aprint(request, request, head, escape, escape_ctx, 0);
2134                 if (!answer) {
2135                         *out = talloc_zero_array(request, char, 1);
2136                         return 0;
2137                 }
2138                 *out = answer;
2139                 return strlen(answer);
2140         }
2141
2142         list = 0;               /* FIXME: calculate this once */
2143         for (node = head; node != NULL; node = node->next) {
2144                 list++;
2145         }
2146
2147         array = talloc_array(request, char *, list);
2148         if (!array) return -1;
2149
2150         for (node = head, i = 0; node != NULL; node = node->next, i++) {
2151                 array[i] = xlat_aprint(array, request, node, escape, escape_ctx, 0); /* may be NULL */
2152         }
2153
2154         total = 0;
2155         for (i = 0; i < list; i++) {
2156                 if (array[i]) total += strlen(array[i]); /* FIXME: calculate strlen once */
2157         }
2158
2159         if (!total) {
2160                 talloc_free(array);
2161                 *out = talloc_zero_array(request, char, 1);
2162                 return 0;
2163         }
2164
2165         answer = talloc_array(request, char, total + 1);
2166
2167         total = 0;
2168         for (i = 0; i < list; i++) {
2169                 size_t len;
2170
2171                 if (array[i]) {
2172                         len = strlen(array[i]);
2173                         memcpy(answer + total, array[i], len);
2174                         total += len;
2175                 }
2176         }
2177         answer[total] = '\0';
2178         talloc_free(array);     /* and child entries */
2179
2180         *out = answer;
2181         return total;
2182 }
2183
2184
2185 /** Replace %whatever in a string.
2186  *
2187  * See 'doc/variables.txt' for more information.
2188  *
2189  * @param[out] out Where to write pointer to output buffer.
2190  * @param[in] outlen Size of out.
2191  * @param[in] request current request.
2192  * @param[in] node the xlat structure to expand
2193  * @param[in] escape function to escape final value e.g. SQL quoting.
2194  * @param[in] escape_ctx pointer to pass to escape function.
2195  * @return length of string written @bug should really have -1 for failure
2196  */
2197 static ssize_t xlat_expand_struct(char **out, size_t outlen, REQUEST *request, xlat_exp_t const *node,
2198                                   RADIUS_ESCAPE_STRING escape, void *escape_ctx)
2199 {
2200         char *buff;
2201         ssize_t len;
2202
2203         rad_assert(node != NULL);
2204
2205         len = xlat_process(&buff, request, node, escape, escape_ctx);
2206         if ((len < 0) || !buff) {
2207                 rad_assert(buff == NULL);
2208                 if (*out) *out[0] = '\0';
2209                 return len;
2210         }
2211
2212         if (!*out) {
2213                 *out = buff;
2214         } else {
2215                 strlcpy(*out, buff, outlen);
2216                 talloc_free(buff);
2217         }
2218
2219         return strlen(*out);
2220 }
2221
2222 static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
2223                            RADIUS_ESCAPE_STRING escape, void *escape_ctx) CC_HINT(nonnull (1, 3, 4));
2224
2225 /** Replace %whatever in a string.
2226  *
2227  * See 'doc/variables.txt' for more information.
2228  *
2229  * @param[out] out Where to write pointer to output buffer.
2230  * @param[in] outlen Size of out.
2231  * @param[in] request current request.
2232  * @param[in] fmt string to expand.
2233  * @param[in] escape function to escape final value e.g. SQL quoting.
2234  * @param[in] escape_ctx pointer to pass to escape function.
2235  * @return length of string written @bug should really have -1 for failure
2236  */
2237 static ssize_t CC_HINT(nonnull (1, 3, 4)) xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
2238                                                       RADIUS_ESCAPE_STRING escape, void *escape_ctx)
2239 {
2240         ssize_t len;
2241         xlat_exp_t *node;
2242
2243         /*
2244          *      Give better errors than the old code.
2245          */
2246         len = xlat_tokenize_request(request, fmt, &node);
2247         if (len == 0) {
2248                 if (*out) {
2249                         *out[0] = '\0';
2250                 } else {
2251                         *out = talloc_zero_array(request, char, 1);
2252                 }
2253                 return 0;
2254         }
2255
2256         if (len < 0) {
2257                 if (*out) *out[0] = '\0';
2258                 return -1;
2259         }
2260
2261         len = xlat_expand_struct(out, outlen, request, node, escape, escape_ctx);
2262         talloc_free(node);
2263
2264         RDEBUG2("EXPAND %s", fmt);
2265         RDEBUG2("   --> %s", *out);
2266
2267         return len;
2268 }
2269
2270 /*
2271  *      Try to convert an xlat to a tmpl for efficiency
2272  */
2273 value_pair_tmpl_t *radius_xlat2tmpl(TALLOC_CTX *ctx, xlat_exp_t *node)
2274 {
2275         value_pair_tmpl_t *vpt;
2276
2277         if (node->next || (node->type != XLAT_ATTRIBUTE)) return NULL;
2278
2279         /*
2280          * @todo it should be possible to emulate the concat and count operations in the
2281          * map code.
2282          */
2283         if ((node->attr.tmpl_num == NUM_COUNT) || (node->attr.tmpl_num == NUM_ALL)) return NULL;
2284
2285         vpt = tmpl_alloc(ctx, TMPL_TYPE_ATTR, node->fmt, -1);
2286         if (!vpt) return NULL;
2287         vpt->tmpl_request = node->attr.tmpl_request;
2288         vpt->tmpl_list = node->attr.tmpl_list;
2289         vpt->tmpl_da = node->attr.tmpl_da;
2290         vpt->tmpl_num = node->attr.tmpl_num;
2291         vpt->tmpl_tag = node->attr.tmpl_tag;
2292
2293         VERIFY_TMPL(vpt);
2294
2295         return vpt;
2296 }
2297
2298 ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, RADIUS_ESCAPE_STRING escape, void *ctx)
2299 {
2300         return xlat_expand(&out, outlen, request, fmt, escape, ctx);
2301 }
2302
2303 ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, RADIUS_ESCAPE_STRING escape, void *ctx)
2304 {
2305         return xlat_expand(out, 0, request, fmt, escape, ctx);
2306 }
2307
2308 ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, RADIUS_ESCAPE_STRING escape, void *ctx)
2309 {
2310         return xlat_expand_struct(out, 0, request, xlat, escape, ctx);
2311 }