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