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