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