Add support for tags to remaining functions in lib/valuepair.c
[freeradius.git] / src / main / xlat.c
1 /*
2  * @file xlat.c
3  * @brief String expansion ("translation"). Implements %Attribute -> value
4  *
5  * Version:     $Id$
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * Copyright 2000,2006  The FreeRADIUS server project
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  */
24
25 #include <freeradius-devel/ident.h>
26 RCSID("$Id$")
27
28 #include        <freeradius-devel/radiusd.h>
29 #include        <freeradius-devel/rad_assert.h>
30 #include        <freeradius-devel/base64.h>
31
32 #include        <ctype.h>
33
34 typedef struct xlat_t {
35         char            module[MAX_STRING_LEN];
36         int             length;
37         void            *instance;
38         RAD_XLAT_FUNC   do_xlat;
39         int             internal;       /* not allowed to re-define these */
40 } xlat_t;
41
42 static rbtree_t *xlat_root = NULL;
43
44 /*
45  *      Define all xlat's in the structure.
46  */
47 static const char * const internal_xlat[] = {"check",
48                                              "request",
49                                              "reply",
50                                              "proxy-request",
51                                              "proxy-reply",
52                                              "outer.request",
53                                              "outer.reply",
54                                              "outer.control",
55                                              NULL};
56 #ifdef WITH_UNLANG
57 static const char * const xlat_foreach_names[] = {"Foreach-Variable-0",
58                                                   "Foreach-Variable-1",
59                                                   "Foreach-Variable-2",
60                                                   "Foreach-Variable-3",
61                                                   "Foreach-Variable-4",
62                                                   "Foreach-Variable-5",
63                                                   "Foreach-Variable-6",
64                                                   "Foreach-Variable-7",
65                                                   "Foreach-Variable-8",
66                                                   "Foreach-Variable-9",
67                                                   NULL};
68 #endif
69
70 #if REQUEST_MAX_REGEX > 8
71 #error Please fix the following line
72 #endif
73 static int xlat_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; /* up to 8 for regex */
74
75 /**
76  * @brief Convert the value on a VALUE_PAIR to string
77  */
78 static int valuepair2str(char * out,int outlen,VALUE_PAIR * pair, int type)
79 {
80         if (pair != NULL) {
81                 vp_prints_value(out, outlen, pair, -1);
82                 return strlen(out);
83         }
84
85         switch (type) {
86         case PW_TYPE_STRING :
87                 strlcpy(out,"_",outlen);
88                 break;
89         case PW_TYPE_INTEGER64:
90         case PW_TYPE_SIGNED:
91         case PW_TYPE_INTEGER:
92                 strlcpy(out,"0",outlen);
93                 break;
94         case PW_TYPE_IPADDR :
95                 strlcpy(out,"?.?.?.?",outlen);
96                 break;
97         case PW_TYPE_IPV6ADDR :
98                 strlcpy(out,":?:",outlen);
99                 break;
100         case PW_TYPE_DATE :
101                 strlcpy(out,"0",outlen);
102                 break;
103         default :
104                 strlcpy(out,"unknown_type",outlen);
105         }
106         return strlen(out);
107 }
108
109 /*
110  *      Dynamically translate for check:, request:, reply:, etc.
111  */
112 static size_t xlat_packet(void *instance, REQUEST *request,
113                           const char *fmt, char *out, size_t outlen)
114 {
115         DICT_ATTR       *da;
116         VALUE_PAIR      *vp;
117         VALUE_PAIR      *vps = NULL;
118         RADIUS_PACKET   *packet = NULL;
119
120         switch (*(int*) instance) {
121         case 0:
122                 vps = request->config_items;
123                 break;
124
125         case 1:
126                 vps = request->packet->vps;
127                 packet = request->packet;
128                 break;
129
130         case 2:
131                 vps = request->reply->vps;
132                 packet = request->reply;
133                 break;
134
135         case 3:
136 #ifdef WITH_PROXY
137                 if (request->proxy) vps = request->proxy->vps;
138                 packet = request->proxy;
139 #endif
140                 break;
141
142         case 4:
143 #ifdef WITH_PROXY
144                 if (request->proxy_reply) vps = request->proxy_reply->vps;
145                 packet = request->proxy_reply;
146 #endif
147                 break;
148
149         case 5:
150                 if (request->parent) {
151                         vps = request->parent->packet->vps;
152                         packet = request->parent->packet;
153                 }
154                 break;
155                         
156         case 6:
157                 if (request->parent && request->parent->reply) {
158                         vps = request->parent->reply->vps;
159                         packet = request->parent->reply;
160                 }
161                 break;
162                         
163         case 7:
164                 if (request->parent) {
165                         vps = request->parent->config_items;
166                 }
167                 break;
168                         
169         default:                /* WTF? */
170                 return 0;
171         }
172
173         /*
174          *      The "format" string is the attribute name.
175          */
176         da = dict_attrbyname(fmt);
177         if (!da) {
178                 int do_number = FALSE;
179                 int do_array = FALSE;
180                 int do_count = FALSE;
181                 int do_all = FALSE;
182                 int tag = 0;
183                 size_t count = 0, total;
184                 char *p;
185                 char buffer[256];
186
187                 if (strlen(fmt) > sizeof(buffer)) return 0;
188
189                 strlcpy(buffer, fmt, sizeof(buffer));
190
191                 /*
192                  *      %{Attribute-name#} - print integer version of it.
193                  */
194                 p = buffer + strlen(buffer) - 1;
195                 if (*p == '#') {
196                         *p = '\0';
197                         do_number = TRUE;
198                 }
199
200                 /*
201                  *      %{Attribute-Name:tag} - get the name with the specified
202                  *      value of the tag.
203                  */
204                 p = strchr(buffer, ':');
205                 if (p) {
206                         tag = atoi(p + 1);
207                         *p = '\0';
208                         p++;
209
210                 } else {
211                         /*
212                          *      Allow %{Attribute-Name:tag[...]}
213                          */
214                         p = buffer;
215                 }
216
217                 /*
218                  *      %{Attribute-Name[...] does more stuff
219                  */
220                 p = strchr(p, '[');
221                 if (p) {
222                         *p = '\0';
223                         do_array = TRUE;
224                         if (p[1] == '#') {
225                                 do_count = TRUE;
226                         } else if (p[1] == '*') {
227                                 do_all = TRUE;
228                         } else {
229                                 count = atoi(p + 1);
230                                 p += 1 + strspn(p + 1, "0123456789");
231                                 if (*p != ']') {
232                                         RDEBUG2("xlat: Invalid array reference in string at %s %s",
233                                                 fmt, p);
234                                         return 0;
235                                 }
236                         }
237                 }
238
239                 /*
240                  *      We COULD argue about %{Attribute-Name[#]#} etc.
241                  *      But that looks like more work than it's worth.
242                  */
243
244                 da = dict_attrbyname(buffer);
245                 if (!da) return 0;
246
247                 /*
248                  *      No array, print the tagged attribute.
249                  */
250                 if (!do_array) {
251                         vp = pairfind(vps, da->attr, da->vendor, tag);
252                         goto just_print;
253                 }
254
255                 total = 0;
256
257                 /*
258                  *      Array[#] - return the total
259                  */
260                 if (do_count) {
261                         for (vp = pairfind(vps, da->attr, da->vendor, tag);
262                              vp != NULL;
263                              vp = pairfind(vp->next, da->attr, da->vendor, tag)) {
264                                 total++;
265                         }
266
267                         snprintf(out, outlen, "%d", (int) total);
268                         return strlen(out);
269                 }
270
271                 /*
272                  *      %{Attribute-Name[*]} returns ALL of the
273                  *      the attributes, separated by a newline.
274                  */
275                 if (do_all) {
276                         for (vp = pairfind(vps, da->attr, da->vendor, tag);
277                              vp != NULL;
278                              vp = pairfind(vp->next, da->attr, da->vendor, tag)) {
279                                 count = valuepair2str(out, outlen - 1, vp, da->type);
280                                 rad_assert(count <= outlen);
281                                 total += count + 1;
282                                 outlen -= (count + 1);
283                                 out += count;
284
285                                 *(out++) = '\n';
286
287                                 if (outlen <= 1) break;
288                         }
289
290                         *out = '\0';
291                         return total;
292                 }
293
294                 /*
295                  *      Find the N'th value.
296                  */
297                 for (vp = pairfind(vps, da->attr, da->vendor, tag);
298                      vp != NULL;
299                      vp = pairfind(vp->next, da->attr, da->vendor, tag)) {
300                         if (total == count) break;
301                         total++;
302                         if (total > count) {
303                                 vp = NULL;
304                                 break;
305                         }
306                 }
307
308                 /*
309                  *      Non-existent array reference.
310                  */
311         just_print:
312                 if (!vp) return 0;
313
314                 if (do_number) {
315                         if ((vp->type != PW_TYPE_IPADDR) &&
316                             (vp->type != PW_TYPE_INTEGER) &&
317                             (vp->type != PW_TYPE_SHORT) &&
318                             (vp->type != PW_TYPE_BYTE) &&
319                             (vp->type != PW_TYPE_DATE)) {
320                                 *out = '\0';
321                                 return 0;
322                         }
323                         
324                         return snprintf(out, outlen, "%u", vp->vp_integer);
325                 }
326
327                 return valuepair2str(out, outlen, vp, da->type);
328         }
329
330         vp = pairfind(vps, da->attr, da->vendor, TAG_ANY);
331         if (!vp) {
332                 /*
333                  *      Some "magic" handlers, which are never in VP's, but
334                  *      which are in the packet.
335                  *
336                  *      @bug FIXME: We should really do this in a more
337                  *      intelligent way...
338                  */
339                 if (packet) {
340                         VALUE_PAIR localvp;
341
342                         memset(&localvp, 0, sizeof(localvp));
343
344                         switch (da->attr) {
345                         case PW_PACKET_TYPE:
346                         {
347                                 DICT_VALUE *dval;
348
349                                 dval = dict_valbyattr(da->attr, da->vendor, packet->code);
350                                 if (dval) {
351                                         snprintf(out, outlen, "%s", dval->name);
352                                 } else {
353                                         snprintf(out, outlen, "%d", packet->code);
354                                 }
355                                 return strlen(out);
356                         }
357                         break;
358
359                         case PW_CLIENT_SHORTNAME:
360                                 if (request->client && request->client->shortname) {
361                                         strlcpy(out, request->client->shortname, outlen);
362                                 } else {
363                                         strlcpy(out, "<UNKNOWN-CLIENT>", outlen);
364                                 }
365                                 return strlen(out);
366
367                         case PW_CLIENT_IP_ADDRESS: /* the same as below */
368                         case PW_PACKET_SRC_IP_ADDRESS:
369                                 if (packet->src_ipaddr.af != AF_INET) {
370                                         return 0;
371                                 }
372                                 localvp.attribute = da->attr;
373                                 localvp.vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
374                                 break;
375
376                         case PW_PACKET_DST_IP_ADDRESS:
377                                 if (packet->dst_ipaddr.af != AF_INET) {
378                                         return 0;
379                                 }
380                                 localvp.attribute = da->attr;
381                                 localvp.vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
382                                 break;
383
384                         case PW_PACKET_SRC_PORT:
385                                 localvp.attribute = da->attr;
386                                 localvp.vp_integer = packet->src_port;
387                                 break;
388
389                         case PW_PACKET_DST_PORT:
390                                 localvp.attribute = da->attr;
391                                 localvp.vp_integer = packet->dst_port;
392                                 break;
393
394                         case PW_PACKET_AUTHENTICATION_VECTOR:
395                                 localvp.attribute = da->attr;
396                                 memcpy(localvp.vp_strvalue, packet->vector,
397                                        sizeof(packet->vector));
398                                 localvp.length = sizeof(packet->vector);
399                                 break;
400
401                                 /*
402                                  *      Authorization, accounting, etc.
403                                  */
404                         case PW_REQUEST_PROCESSING_STAGE:
405                                 if (request->component) {
406                                         strlcpy(out, request->component, outlen);
407                                 } else {
408                                         strlcpy(out, "server_core", outlen);
409                                 }
410                                 return strlen(out);
411
412                         case PW_PACKET_SRC_IPV6_ADDRESS:
413                                 if (packet->src_ipaddr.af != AF_INET6) {
414                                         return 0;
415                                 }
416                                 localvp.attribute = da->attr;
417                                 memcpy(localvp.vp_strvalue,
418                                        &packet->src_ipaddr.ipaddr.ip6addr,
419                                        sizeof(packet->src_ipaddr.ipaddr.ip6addr));
420                                 break;
421
422                         case PW_PACKET_DST_IPV6_ADDRESS:
423                                 if (packet->dst_ipaddr.af != AF_INET6) {
424                                         return 0;
425                                 }
426                                 localvp.attribute = da->attr;
427                                 memcpy(localvp.vp_strvalue,
428                                        &packet->dst_ipaddr.ipaddr.ip6addr,
429                                        sizeof(packet->dst_ipaddr.ipaddr.ip6addr));
430                                 break;
431
432                         case PW_VIRTUAL_SERVER:
433                                 if (!request->server) return 0;
434
435                                 snprintf(out, outlen, "%s", request->server);
436                                 return strlen(out);
437                                 break;
438
439                         case PW_MODULE_RETURN_CODE:
440                                 localvp.attribute = da->attr;
441
442                                 /*
443                                  *      See modcall.c for a bit of a hack.
444                                  */
445                                 localvp.vp_integer = request->simul_max;
446                                 break;
447
448                         default:
449                                 return 0; /* not found */
450                                 break;
451                         }
452
453                         localvp.type = da->type;
454                         return valuepair2str(out, outlen, &localvp, da->type);
455                 }
456
457                 /*
458                  *      Not found, die.
459                  */
460                 return 0;
461         }
462
463         if (!vps) return 0;     /* silently fail */
464
465         /*
466          *      Convert the VP to a string, and return it.
467          */
468         return valuepair2str(out, outlen, vp, da->type);
469 }
470
471 /**
472  * @brief Print data as integer, not as VALUE.
473  */
474 static size_t xlat_integer(UNUSED void *instance, REQUEST *request,
475                            const char *fmt, char *out, size_t outlen)
476 {
477         VALUE_PAIR      *vp;
478
479         uint64_t        integer;
480         
481         while (isspace((int) *fmt)) fmt++;
482
483         if ((radius_get_vp(request, fmt, &vp) < 0) || !vp) {
484                 *out = '\0';
485                 return 0;
486         }
487
488         switch (vp->type)
489         {               
490                 case PW_TYPE_OCTETS:
491                 case PW_TYPE_STRING:
492                         if (vp->length > 8) {
493                                 break;
494                         } 
495
496                         memcpy(&integer, &(vp->vp_octets), vp->length);
497                         
498                         return snprintf(out, outlen, "%llu", ntohll(integer));  
499                         
500                 case PW_TYPE_INTEGER64:
501                         return snprintf(out, outlen, "%llu", vp->vp_integer64);
502                         
503                 case PW_TYPE_IPADDR:
504                 case PW_TYPE_INTEGER:
505                 case PW_TYPE_SHORT:
506                 case PW_TYPE_BYTE:
507                 case PW_TYPE_DATE:
508                         return snprintf(out, outlen, "%u", vp->vp_integer);
509         }
510         
511         *out = '\0';
512         return 0;
513 }
514
515 /**
516  * @brief Print data as hex, not as VALUE.
517  */
518 static size_t xlat_hex(UNUSED void *instance, REQUEST *request,
519                        const char *fmt, char *out, size_t outlen)
520 {
521         size_t i;
522         VALUE_PAIR *vp;
523         uint8_t buffer[MAX_STRING_LEN];
524         ssize_t ret;
525         size_t  len;
526
527         while (isspace((int) *fmt)) fmt++;
528
529         if ((radius_get_vp(request, fmt, &vp) < 0) || !vp) {
530                 *out = '\0';
531                 return 0;
532         }
533         
534         ret = rad_vp2data(vp, buffer, sizeof(buffer));
535         len = (size_t) ret;
536         
537         /*
538          *      Don't truncate the data.
539          */
540         if ((ret < 0 ) || (outlen < (len * 2))) {
541                 *out = 0;
542                 return 0;
543         }
544
545         for (i = 0; i < len; i++) {
546                 snprintf(out + 2*i, 3, "%02x", buffer[i]);
547         }
548
549         return len * 2;
550 }
551
552 /**
553  * @brief Print data as base64, not as VALUE
554  */
555 static size_t xlat_base64(UNUSED void *instance, REQUEST *request,
556                           const char *fmt, char *out, size_t outlen)
557 {
558         VALUE_PAIR *vp;
559         uint8_t buffer[MAX_STRING_LEN];
560         ssize_t ret;
561         size_t  len;
562         size_t  enc;
563         
564         while (isspace((int) *fmt)) fmt++;
565
566         if ((radius_get_vp(request, fmt, &vp) < 0) || !vp) {
567                 *out = '\0';
568                 return 0;
569         }
570         
571         ret = rad_vp2data(vp, buffer, sizeof(buffer));
572         if (ret < 0) {
573                 *out = 0;
574                 return 0;
575         }
576         
577         len = (size_t) ret;
578         
579         enc = FR_BASE64_ENC_LENGTH(len);
580         
581         /*
582          *      Don't truncate the data.
583          */
584         if (outlen < (enc + 1)) {
585                 *out = 0;
586                 return 0;
587         }
588         
589         fr_base64_encode(buffer, len, out, outlen);
590
591         return enc;
592 }
593
594 /**
595  * @brief Prints the current module processing the request
596  */
597 static size_t xlat_module(UNUSED void *instance, REQUEST *request,
598                           UNUSED const char *fmt, char *out, size_t outlen)
599 {
600         strlcpy(out, request->module, outlen);
601
602         return strlen(out);
603 }
604
605 #ifdef WITH_UNLANG
606 /**
607  * @brief Implements the Foreach-Variable-X
608  *
609  * @see modcall()
610  */
611 static size_t xlat_foreach(void *instance, REQUEST *request,
612                            UNUSED const char *fmt, char *out, size_t outlen)
613 {
614         VALUE_PAIR      **pvp;
615
616         /*
617          *      See modcall, "FOREACH" for how this works.
618          */
619         pvp = (VALUE_PAIR **) request_data_reference(request, radius_get_vp,
620                                                      *(int*) instance);
621         if (!pvp || !*pvp) {
622                 *out = '\0';
623                 return 0;
624         }
625
626         return valuepair2str(out, outlen, (*pvp), (*pvp)->type);
627 }
628 #endif
629
630 /**
631  * @brief Print data as string, if possible.
632  *
633  * If attribute "Foo" is defined as "octets" it will normally
634  * be printed as 0x0a0a0a. The xlat "%{string:Foo}" will instead
635  * expand to "\n\n\n"
636  */
637 static size_t xlat_string(UNUSED void *instance, REQUEST *request,
638                           const char *fmt, char *out, size_t outlen)
639 {
640         int len;
641         VALUE_PAIR *vp;
642
643         while (isspace((int) *fmt)) fmt++;
644
645         if (outlen < 3) {
646         nothing:
647                 *out = '\0';
648                 return 0;
649         }
650
651         if (radius_get_vp(request, fmt, &vp) < 0) goto nothing;
652
653         if (!vp) goto nothing;
654
655         if (vp->type != PW_TYPE_OCTETS) goto nothing;
656
657         len = fr_print_string(vp->vp_strvalue, vp->length, out, outlen);
658         out[len] = '\0';
659
660         return len;
661 }
662
663 /**
664  * @brief xlat expand string attribute value
665  */
666 static size_t xlat_xlat(UNUSED void *instance, REQUEST *request,
667                         const char *fmt, char *out, size_t outlen)
668 {
669         VALUE_PAIR *vp;
670
671         while (isspace((int) *fmt)) fmt++;
672
673         if (outlen < 3) {
674         nothing:
675                 *out = '\0';
676                 return 0;
677         }
678
679         if (radius_get_vp(request, fmt, &vp) < 0) goto nothing;
680
681         if (!vp) goto nothing;
682
683         return radius_xlat(out, outlen, vp->vp_strvalue, request, NULL, NULL);
684 }
685
686 #ifdef HAVE_REGEX_H
687 /*
688  * @brief Expand regexp matches %{0} to %{8}
689  */
690 static size_t xlat_regex(void *instance, REQUEST *request,
691                          const char *fmt, char *out, size_t outlen)
692 {
693         char *regex;
694
695         /*
696          *      We cheat: fmt is "0" to "8", but those numbers
697          *      are already in the "instance".
698          */
699         fmt = fmt;              /* -Wunused */
700
701         regex = request_data_reference(request, request,
702                                  REQUEST_DATA_REGEX | *(int *)instance);
703         if (!regex) return 0;
704
705         /*
706          *      Copy UP TO "freespace" bytes, including
707          *      a zero byte.
708          */
709         strlcpy(out, regex, outlen);
710         return strlen(out);
711 }
712 #endif                          /* HAVE_REGEX_H */
713
714 /**
715  * @brief Dynamically change the debugging level for the current request
716  *
717  * Example %{debug:3}
718  */
719 static size_t xlat_debug(UNUSED void *instance, REQUEST *request,
720                          const char *fmt, char *out, size_t outlen)
721 {
722         int level = 0;
723         
724         /* 
725          *  Expand to previous (or current) level
726          */
727         snprintf(out, outlen, "%d", request->options & RAD_REQUEST_OPTION_DEBUG4);
728
729         /* 
730          *  Assume we just want to get the current value and NOT set it to 0
731          */
732         if (!*fmt)
733                 goto done;
734                 
735         level = atoi(fmt);
736         if (level == 0) {
737                 request->options = RAD_REQUEST_OPTION_NONE;
738                 request->radlog = NULL;
739         } else {
740                 if (level > 4) level = 4;
741
742                 request->options = level;
743                 request->radlog = radlog_request;
744         }
745         
746         done:
747         return strlen(out);
748 }
749
750 /*
751  *      Compare two xlat_t structs, based ONLY on the module name.
752  */
753 static int xlat_cmp(const void *a, const void *b)
754 {
755         if (((const xlat_t *)a)->length != ((const xlat_t *)b)->length) {
756                 return ((const xlat_t *)a)->length - ((const xlat_t *)b)->length;
757         }
758
759         return memcmp(((const xlat_t *)a)->module,
760                       ((const xlat_t *)b)->module,
761                       ((const xlat_t *)a)->length);
762 }
763
764
765 /*
766  *      find the appropriate registered xlat function.
767  */
768 static xlat_t *xlat_find(const char *module)
769 {
770         xlat_t my_xlat;
771
772         strlcpy(my_xlat.module, module, sizeof(my_xlat.module));
773         my_xlat.length = strlen(my_xlat.module);
774
775         return rbtree_finddata(xlat_root, &my_xlat);
776 }
777
778
779 /**
780  * @brief Register an xlat function.
781  *
782  * @param module xlat name
783  * @param func xlat function to be called
784  * @param instance argument to xlat function
785  * @return 0 on success, -1 on failure
786  */
787 int xlat_register(const char *module, RAD_XLAT_FUNC func, void *instance)
788 {
789         xlat_t  *c;
790         xlat_t  my_xlat;
791
792         if (!module || !*module) {
793                 DEBUG("xlat_register: Invalid module name");
794                 return -1;
795         }
796
797         /*
798          *      First time around, build up the tree...
799          *
800          *      FIXME: This code should be hoisted out of this function,
801          *      and into a global "initialization".  But it isn't critical...
802          */
803         if (!xlat_root) {
804                 int i;
805 #ifdef HAVE_REGEX_H
806                 char buffer[2];
807 #endif
808
809                 xlat_root = rbtree_create(xlat_cmp, free, 0);
810                 if (!xlat_root) {
811                         DEBUG("xlat_register: Failed to create tree.");
812                         return -1;
813                 }
814
815                 /*
816                  *      Register the internal packet xlat's.
817                  */
818                 for (i = 0; internal_xlat[i] != NULL; i++) {
819                         xlat_register(internal_xlat[i], xlat_packet, &xlat_inst[i]);
820                         c = xlat_find(internal_xlat[i]);
821                         rad_assert(c != NULL);
822                         c->internal = TRUE;
823                 }
824
825 #ifdef WITH_UNLANG
826                 for (i = 0; xlat_foreach_names[i] != NULL; i++) {
827                         xlat_register(xlat_foreach_names[i],
828                                       xlat_foreach, &xlat_inst[i]);
829                         c = xlat_find(xlat_foreach_names[i]);
830                         rad_assert(c != NULL);
831                         c->internal = TRUE;
832                 }
833 #endif
834
835                 /*
836                  *      New name: "control"
837                  */
838                 xlat_register("control", xlat_packet, &xlat_inst[0]);
839                 c = xlat_find("control");
840                 rad_assert(c != NULL);
841                 c->internal = TRUE;
842
843 #define XLAT_REGISTER(_x) xlat_register(Stringify(_x), xlat_ ## _x, NULL); \
844                 c = xlat_find(Stringify(_x)); \
845                 rad_assert(c != NULL); \
846                 c->internal = TRUE
847
848                 XLAT_REGISTER(integer);
849                 XLAT_REGISTER(hex);
850                 XLAT_REGISTER(base64);
851                 XLAT_REGISTER(string);
852                 XLAT_REGISTER(xlat);
853                 XLAT_REGISTER(module);
854
855 #ifdef HAVE_REGEX_H
856                 /*
857                  *      Register xlat's for regexes.
858                  */
859                 buffer[1] = '\0';
860                 for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
861                         buffer[0] = '0' + i;
862                         xlat_register(buffer, xlat_regex, &xlat_inst[i]);
863                         c = xlat_find(buffer);
864                         rad_assert(c != NULL);
865                         c->internal = TRUE;
866                 }
867 #endif /* HAVE_REGEX_H */
868
869
870                 xlat_register("debug", xlat_debug, &xlat_inst[0]);
871                 c = xlat_find("debug");
872                 rad_assert(c != NULL);
873                 c->internal = TRUE;
874         }
875
876         /*
877          *      If it already exists, replace the instance.
878          */
879         strlcpy(my_xlat.module, module, sizeof(my_xlat.module));
880         my_xlat.length = strlen(my_xlat.module);
881         c = rbtree_finddata(xlat_root, &my_xlat);
882         if (c) {
883                 if (c->internal) {
884                         DEBUG("xlat_register: Cannot re-define internal xlat");
885                         return -1;
886                 }
887
888                 c->do_xlat = func;
889                 c->instance = instance;
890                 return 0;
891         }
892
893         /*
894          *      Doesn't exist.  Create it.
895          */
896         c = rad_malloc(sizeof(*c));
897         memset(c, 0, sizeof(*c));
898
899         c->do_xlat = func;
900         strlcpy(c->module, module, sizeof(c->module));
901         c->length = strlen(c->module);
902         c->instance = instance;
903
904         rbtree_insert(xlat_root, c);
905
906         return 0;
907 }
908
909 /**
910  * @brief Unregister an xlat function.
911  *
912  *      We can only have one function to call per name, so the
913  *      passing of "func" here is extraneous.
914  *
915  * @param module xlat to unregister
916  * @param func Unused
917  * @return Void.
918  */
919 void xlat_unregister(const char *module, RAD_XLAT_FUNC func, void *instance)
920 {
921         xlat_t  *c;
922         xlat_t          my_xlat;
923
924         func = func;            /* -Wunused */
925
926         if (!module) return;
927
928         strlcpy(my_xlat.module, module, sizeof(my_xlat.module));
929         my_xlat.length = strlen(my_xlat.module);
930
931         c = rbtree_finddata(xlat_root, &my_xlat);
932         if (!c) return;
933
934         if (c->instance != instance) return;
935
936         rbtree_deletebydata(xlat_root, c);
937 }
938
939 /**
940  * @brief De-register all xlat functions, used mainly for debugging.
941  */
942 void xlat_free(void)
943 {
944         rbtree_free(xlat_root);
945 }
946
947
948 /**
949  * @brief Decode an attribute name into a string.
950  *
951  * This expands the various formats:
952  * - %{Name}
953  * - %{xlat:name}
954  * - %{Name:-Other}
955  *
956  * calls radius_xlat() to do most of the work
957  *
958  * @param from string to expand
959  * @param to buffer for output
960  * @param freespace space remaining in output buffer
961  * @param request current server request
962  * @param func optional function to escape output; passed to radius_xlat()
963  * @return 0 on success, -1 on failure
964  */
965 static int decode_attribute(const char **from, char **to, int freespace,
966                              REQUEST *request,
967                              RADIUS_ESCAPE_STRING func, void *funcarg)
968 {
969         int     do_length = 0;
970         const char *module_name, *xlat_str;
971         char *p, *q, *l, *next = NULL;
972         int retlen=0;
973         const xlat_t *c;
974         int varlen;
975         char buffer[8192];
976
977         q = *to;
978
979         *q = '\0';
980
981         /*
982          *      Copy the input string to an intermediate buffer where
983          *      we can mangle it.
984          */
985         varlen = rad_copy_variable(buffer, *from);
986         if (varlen < 0) {
987                 RDEBUG2("ERROR: Badly formatted variable: %s", *from);
988                 return -1;
989         }
990         *from += varlen;
991
992         /*
993          *      Kill the %{} around the data we are looking for.
994          */
995         p = buffer;
996         p[varlen - 1] = '\0';   /*  */
997         p += 2;
998         if (*p == '#') {
999                 p++;
1000                 do_length = 1;
1001         }
1002
1003         /*
1004          *      Handle %{%{foo}:-%{bar}}, which is useful, too.
1005          *
1006          *      Did I mention that this parser is garbage?
1007          */
1008         if ((p[0] == '%') && (p[1] == '{')) {
1009                 int len1, len2;
1010                 int expand2 = FALSE;
1011
1012                 /*
1013                  *      'p' is after the start of 'buffer', so we can
1014                  *      safely do this.
1015                  */
1016                 len1 = rad_copy_variable(buffer, p);
1017                 if (len1 < 0) {
1018                         RDEBUG2("ERROR: Badly formatted variable: %s", p);
1019                         return -1;
1020                 }
1021
1022                 /*
1023                  *      They did %{%{foo}}, which is stupid, but allowed.
1024                  */
1025                 if (!p[len1]) {
1026                         RDEBUG2("Improperly nested variable; %%{%s}", p);
1027                         return -1;
1028                 }
1029
1030                 /*
1031                  *      It SHOULD be %{%{foo}:-%{bar}}.  If not, it's
1032                  *      an error.
1033                  */
1034                 if ((p[len1] != ':') || (p[len1 + 1] != '-')) {
1035                         RDEBUG2("No trailing :- after variable at %s", p);
1036                         return -1;
1037                 }
1038
1039                 /*
1040                  *      Parse the second bit.  The second bit can be
1041                  *      either %{foo}, or a string "foo", or a string
1042                  *      'foo', or just a bare word: foo
1043                  */
1044                 p += len1 + 2;
1045                 l = buffer + len1 + 1;
1046
1047                 if ((p[0] == '%') && (p[1] == '{')) {
1048                         len2 = rad_copy_variable(l, p);
1049
1050                         if (len2 < 0) {
1051                                 RDEBUG2("ERROR: Invalid text after :- at %s", p);
1052                                 return -1;
1053                         }
1054                         p += len2;
1055                         expand2 = TRUE;
1056
1057                 } else if ((p[0] == '"') || p[0] == '\'') {
1058                   getstring((const char **) &p, l, strlen(l));
1059
1060                 } else {
1061                         l = p;
1062                 }
1063
1064                 /*
1065                  *      Expand the first one.  If we did, exit the
1066                  *      conditional.
1067                  */
1068                 retlen = radius_xlat(q, freespace, buffer, request, func, funcarg);
1069                 if (retlen) {
1070                         q += retlen;
1071                         goto done;
1072                 }
1073
1074                 RDEBUG2("\t... expanding second conditional");
1075                 /*
1076                  *      Expand / copy the second string if required.
1077                  */
1078                 if (expand2) {
1079                         retlen = radius_xlat(q, freespace, l,
1080                                             request, func, funcarg);
1081                         if (retlen) {
1082                                 q += retlen;
1083                         }
1084                 } else {
1085                         strlcpy(q, l, freespace);
1086                         q += strlen(q);
1087                 }
1088
1089                 /*
1090                  *      Else the output is an empty string.
1091                  */
1092                 goto done;
1093         }
1094
1095         /*
1096          *      See if we're supposed to expand a module name.
1097          */
1098         module_name = NULL;
1099         for (l = p; *l != '\0'; l++) {
1100                 /*
1101                  *      module:string
1102                  */
1103                 if (*l == ':') {
1104                         module_name = p; /* start of name */
1105                         *l = '\0';
1106                         p = l + 1;
1107                         break;
1108                 }
1109
1110                 /*
1111                  *      Module names can't have spaces.
1112                  */
1113                 if ((*l == ' ') || (*l == '\t')) break;
1114         }
1115
1116         /*
1117          *      %{name} is a simple attribute reference,
1118          *      or regex reference.
1119          */
1120         if (!module_name) {
1121                 if (isdigit(*p) && !p[1]) { /* regex 0..8 */
1122                         module_name = xlat_str = p;
1123                 } else {
1124                         xlat_str = p;
1125                 }
1126                 goto do_xlat;
1127         }
1128
1129         /*
1130          *      Maybe it's the old-style %{foo:-bar}
1131          */
1132         if (*p == '-') {
1133                 RDEBUG2("WARNING: Deprecated conditional expansion \":-\".  See \"man unlang\" for details");
1134                 p++;
1135
1136                 xlat_str = module_name;
1137                 next = p;
1138                 goto do_xlat;
1139         }
1140
1141         /*
1142          *      FIXME: For backwards "WTF" compatibility, check for
1143          *      {...}, (after the :), and copy that, too.
1144          */
1145
1146         /* module name, followed by (possibly) per-module string */
1147         xlat_str = p;
1148         
1149 do_xlat:
1150         /*
1151          *      Just "foo".  Maybe it's a magic attr, which doesn't
1152          *      really exist.
1153          *
1154          *      If we can't find that, then assume it's a dictionary
1155          *      attribute in the request.
1156          *
1157          *      Else if it's module:foo, look for module, and pass it "foo".
1158          */
1159         if (!module_name) {
1160                 c = xlat_find(xlat_str);
1161                 if (!c) c = xlat_find("request");
1162         } else {
1163                 c = xlat_find(module_name);
1164         }
1165         if (!c) {
1166                 if (!module_name) {
1167                         RDEBUG2("WARNING: Unknown Attribute \"%s\" in string expansion \"%%%s\"", xlat_str, *from);
1168                 } else {
1169                         RDEBUG2("WARNING: Unknown module \"%s\" in string expansion \"%%%s\"", module_name, *from);
1170                 }
1171                 return -1;
1172         }
1173
1174         if (!c->internal) RDEBUG3("radius_xlat: Running registered xlat function of module %s for string \'%s\'",
1175                                   c->module, xlat_str);
1176         if (func) {
1177                 /* xlat to a temporary buffer, then escape */
1178                 char tmpbuf[8192];
1179                 retlen = c->do_xlat(c->instance, request, xlat_str, tmpbuf, sizeof(tmpbuf));
1180                 if (retlen > 0) {
1181                         retlen = func(request, q, freespace, tmpbuf, funcarg);
1182                         if (retlen > 0) {
1183                                 RDEBUG2("\tescape: \'%s\' -> \'%s\'", tmpbuf, q);
1184                         } else if (retlen < 0) {
1185                                 RDEBUG2("String escape failed");
1186                         }
1187                 }
1188         } else {
1189                 retlen = c->do_xlat(c->instance, request, xlat_str, q, freespace);
1190         }
1191         if (retlen > 0) {
1192                 if (do_length) {
1193                         snprintf(q, freespace, "%d", retlen);
1194                         retlen = strlen(q);
1195                 }
1196                 
1197         } else if (next) {
1198                 /*
1199                  *      Expand the second bit.
1200                  */
1201                 RDEBUG2("\t... expanding second conditional");
1202                 retlen = radius_xlat(q, freespace, next, request, func, funcarg);
1203         }
1204         q += retlen;
1205
1206 done:
1207         *to = q;
1208         return 0;
1209 }
1210
1211 /**
1212  * @brief Replace %whatever in a string.
1213  *
1214  *      See 'doc/variables.txt' for more information.
1215  *
1216  * @param out output buffer
1217  * @param outlen size of output buffer
1218  * @param fmt string to expand
1219  * @param request current request
1220  * @param func function to escape final value e.g. SQL quoting
1221  * @return length of string written @bug should really have -1 for failure
1222  */
1223 size_t radius_xlat(char *out, int outlen, const char *fmt,
1224                 REQUEST *request,
1225                 RADIUS_ESCAPE_STRING func, void *funcarg)
1226 {
1227         int c, len, freespace;
1228         const char *p;
1229         char *q;
1230         char *nl;
1231         VALUE_PAIR *tmp;
1232         struct tm *TM, s_TM;
1233         char tmpdt[40]; /* For temporary storing of dates */
1234
1235         /*
1236          *      Catch bad modules.
1237          */
1238         if (!fmt || !out || !request) return 0;
1239
1240         q = out;
1241         p = fmt;
1242         while (*p) {
1243                 /* Calculate freespace in output */
1244                 freespace = outlen - (q - out);
1245                 if (freespace <= 1)
1246                         break;
1247                 c = *p;
1248
1249                 if ((c != '%') && (c != '$') && (c != '\\')) {
1250                         /*
1251                          * We check if we're inside an open brace.  If we are
1252                          * then we assume this brace is NOT literal, but is
1253                          * a closing brace and apply it
1254                          */
1255                         *q++ = *p++;
1256                         continue;
1257                 }
1258
1259                 /*
1260                  *      There's nothing after this character, copy
1261                  *      the last '%' or "$' or '\\' over to the output
1262                  *      buffer, and exit.
1263                  */
1264                 if (*++p == '\0') {
1265                         *q++ = c;
1266                         break;
1267                 }
1268
1269                 if (c == '\\') {
1270                         switch(*p) {
1271                         case '\\':
1272                                 *q++ = *p;
1273                                 break;
1274                         case 't':
1275                                 *q++ = '\t';
1276                                 break;
1277                         case 'n':
1278                                 *q++ = '\n';
1279                                 break;
1280                         default:
1281                                 *q++ = c;
1282                                 *q++ = *p;
1283                                 break;
1284                         }
1285                         p++;
1286
1287                 } else if (c == '%') switch(*p) {
1288                         case '{':
1289                                 p--;
1290                                 if (decode_attribute(&p, &q, freespace, request, func, funcarg) < 0) return 0;
1291                                 break;
1292
1293                         case '%':
1294                                 *q++ = *p++;
1295                                 break;
1296                         case 'd': /* request day */
1297                                 TM = localtime_r(&request->timestamp, &s_TM);
1298                                 len = strftime(tmpdt, sizeof(tmpdt), "%d", TM);
1299                                 if (len > 0) {
1300                                         strlcpy(q, tmpdt, freespace);
1301                                         q += strlen(q);
1302                                 }
1303                                 p++;
1304                                 break;
1305                         case 'l': /* request timestamp */
1306                                 snprintf(tmpdt, sizeof(tmpdt), "%lu",
1307                                          (unsigned long) request->timestamp);
1308                                 strlcpy(q,tmpdt,freespace);
1309                                 q += strlen(q);
1310                                 p++;
1311                                 break;
1312                         case 'm': /* request month */
1313                                 TM = localtime_r(&request->timestamp, &s_TM);
1314                                 len = strftime(tmpdt, sizeof(tmpdt), "%m", TM);
1315                                 if (len > 0) {
1316                                         strlcpy(q, tmpdt, freespace);
1317                                         q += strlen(q);
1318                                 }
1319                                 p++;
1320                                 break;
1321                         case 't': /* request timestamp */
1322                                 CTIME_R(&request->timestamp, tmpdt, sizeof(tmpdt));
1323                                 nl = strchr(tmpdt, '\n');
1324                                 if (nl) *nl = '\0';
1325                                 strlcpy(q, tmpdt, freespace);
1326                                 q += strlen(q);
1327                                 p++;
1328                                 break;
1329                         case 'C': /* ClientName */
1330                                 strlcpy(q,request->client->shortname,freespace);
1331                                 q += strlen(q);
1332                                 p++;
1333                                 break;
1334                         case 'D': /* request date */
1335                                 TM = localtime_r(&request->timestamp, &s_TM);
1336                                 len = strftime(tmpdt, sizeof(tmpdt), "%Y%m%d", TM);
1337                                 if (len > 0) {
1338                                         strlcpy(q, tmpdt, freespace);
1339                                         q += strlen(q);
1340                                 }
1341                                 p++;
1342                                 break;
1343                         case 'G': /* request minute */
1344                                 TM = localtime_r(&request->timestamp, &s_TM);
1345                                 len = strftime(tmpdt, sizeof(tmpdt), "%M", TM);
1346                                 if (len > 0) {
1347                                         strlcpy(q, tmpdt, freespace);
1348                                         q += strlen(q);
1349                                 }
1350                                 p++;
1351                                 break;
1352                         case 'H': /* request hour */
1353                                 TM = localtime_r(&request->timestamp, &s_TM);
1354                                 len = strftime(tmpdt, sizeof(tmpdt), "%H", TM);
1355                                 if (len > 0) {
1356                                         strlcpy(q, tmpdt, freespace);
1357                                         q += strlen(q);
1358                                 }
1359                                 p++;
1360                                 break;
1361                         case 'I': /* Request ID */
1362                                 snprintf(tmpdt, sizeof(tmpdt), "%i", request->packet->id);
1363                                 strlcpy(q, tmpdt, freespace);
1364                                 q += strlen(q);
1365                                 p++;
1366                                 break;
1367                         case 'S': /* request timestamp in SQL format*/
1368                                 TM = localtime_r(&request->timestamp, &s_TM);
1369                                 len = strftime(tmpdt, sizeof(tmpdt), "%Y-%m-%d %H:%M:%S", TM);
1370                                 if (len > 0) {
1371                                         strlcpy(q, tmpdt, freespace);
1372                                         q += strlen(q);
1373                                 }
1374                                 p++;
1375                                 break;
1376                         case 'T': /* request timestamp */
1377                                 TM = localtime_r(&request->timestamp, &s_TM);
1378                                 len = strftime(tmpdt, sizeof(tmpdt), "%Y-%m-%d-%H.%M.%S.000000", TM);
1379                                 if (len > 0) {
1380                                         strlcpy(q, tmpdt, freespace);
1381                                         q += strlen(q);
1382                                 }
1383                                 p++;
1384                                 break;
1385                         case 'V': /* Request-Authenticator */
1386                                 strlcpy(q,"Verified",freespace);
1387                                 q += strlen(q);
1388                                 p++;
1389                                 break;
1390                         case 'Y': /* request year */
1391                                 TM = localtime_r(&request->timestamp, &s_TM);
1392                                 len = strftime(tmpdt, sizeof(tmpdt), "%Y", TM);
1393                                 if (len > 0) {
1394                                         strlcpy(q, tmpdt, freespace);
1395                                         q += strlen(q);
1396                                 }
1397                                 p++;
1398                                 break;
1399                         case 'Z': /* Full request pairs except password */
1400                                 tmp = request->packet->vps;
1401                                 while (tmp && (freespace > 3)) {
1402                                         if (tmp->attribute != PW_USER_PASSWORD) {
1403                                                 *q++ = '\t';
1404                                                 len = vp_prints(q, freespace - 2, tmp);
1405                                                 q += len;
1406                                                 freespace -= (len + 2);
1407                                                 *q++ = '\n';
1408                                         }
1409                                         tmp = tmp->next;
1410                                 }
1411                                 p++;
1412                                 break;
1413                         default:
1414                                 RDEBUG2("WARNING: Unknown variable '%%%c': See 'doc/variables.txt'", *p);
1415                                 if (freespace > 2) {
1416                                         *q++ = '%';
1417                                         *q++ = *p++;
1418                                 }
1419                                 break;
1420                 }
1421         }
1422         *q = '\0';
1423
1424         RDEBUG2("\texpand: '%s' -> '%s'", fmt, out);
1425
1426         return strlen(out);
1427 }