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.
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.
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
21 * @brief String expansion ("translation"). Implements %Attribute -> value
23 * @copyright 2000,2006 The FreeRADIUS server project
24 * @copyright 2000 Alan DeKok <aland@ox.org>
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>
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 xlat_func_t func; //!< xlat function.
41 xlat_escape_t escape; //!< Escape function to apply to dynamic input to func.
42 bool internal; //!< If true, cannot be redefined.
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
52 XLAT_REGEX, //!< regex reference
54 XLAT_ALTERNATE //!< xlat conditional syntax :-
58 char const *fmt; //!< The format string.
59 size_t len; //!< Length of the format string.
61 xlat_state_t type; //!< type of this expansion.
62 xlat_exp_t *next; //!< Next in the list.
64 xlat_exp_t *child; //!< Nested expansion.
65 xlat_exp_t *alternate; //!< Alternative expansion if this one expanded to a zero length string.
67 vp_tmpl_t attr; //!< An attribute template.
68 xlat_t const *xlat; //!< The xlat expansion to expand format with.
71 typedef struct xlat_out {
72 char const *out; //!< Output data.
73 size_t len; //!< Length of the output string.
76 static rbtree_t *xlat_root = NULL;
79 static char const * const xlat_foreach_names[] = {"Foreach-Variable-0",
93 static int xlat_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; /* up to 10 for foreach */
95 /** Print length of its RHS.
98 static ssize_t xlat_strlen(UNUSED void *instance, UNUSED REQUEST *request,
99 char const *fmt, char *out, size_t outlen)
101 snprintf(out, outlen, "%u", (unsigned int) strlen(fmt));
105 /** Print the size of the attribute in bytes.
108 static ssize_t xlat_length(UNUSED void *instance, REQUEST *request,
109 char const *fmt, char *out, size_t outlen)
112 while (isspace((int) *fmt)) fmt++;
114 if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
119 snprintf(out, outlen, "%zu", vp->vp_length);
123 /** Print data as integer, not as VALUE.
126 static ssize_t xlat_integer(UNUSED void *instance, REQUEST *request,
127 char const *fmt, char *out, size_t outlen)
131 uint64_t int64 = 0; /* Needs to be initialised to zero */
132 uint32_t int32 = 0; /* Needs to be initialised to zero */
134 while (isspace((int) *fmt)) fmt++;
136 if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
141 switch (vp->da->type) {
144 if (vp->vp_length > 8) {
148 if (vp->vp_length > 4) {
149 memcpy(&int64, vp->vp_octets, vp->vp_length);
150 return snprintf(out, outlen, "%" PRIu64, htonll(int64));
153 memcpy(&int32, vp->vp_octets, vp->vp_length);
154 return snprintf(out, outlen, "%i", htonl(int32));
156 case PW_TYPE_INTEGER64:
157 return snprintf(out, outlen, "%" PRIu64, vp->vp_integer64);
160 * IP addresses are treated specially, as parsing functions assume the value
161 * is bigendian and will convert it for us.
163 case PW_TYPE_IPV4_ADDR:
164 return snprintf(out, outlen, "%u", htonl(vp->vp_ipaddr));
166 case PW_TYPE_IPV4_PREFIX:
167 return snprintf(out, outlen, "%u", htonl((*(uint32_t *)(vp->vp_ipv4prefix + 2))));
169 case PW_TYPE_INTEGER:
170 return snprintf(out, outlen, "%u", vp->vp_integer);
173 return snprintf(out, outlen, "%u", vp->vp_date);
176 return snprintf(out, outlen, "%u", (unsigned int) vp->vp_byte);
179 return snprintf(out, outlen, "%u", (unsigned int) vp->vp_short);
182 * Ethernet is weird... It's network related, so we assume to it should be
185 case PW_TYPE_ETHERNET:
186 memcpy(&int64, vp->vp_ether, vp->vp_length);
187 return snprintf(out, outlen, "%" PRIu64, htonll(int64));
190 return snprintf(out, outlen, "%i", vp->vp_signed);
192 case PW_TYPE_IPV6_ADDR:
193 return fr_prints_uint128(out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6addr));
195 case PW_TYPE_IPV6_PREFIX:
196 return fr_prints_uint128(out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6prefix[2]));
202 REDEBUG("Type '%s' of length %zu cannot be converted to integer",
203 fr_int2str(dict_attr_types, vp->da->type, "???"), vp->vp_length);
209 /** Print data as hex, not as VALUE.
212 static ssize_t xlat_hex(UNUSED void *instance, REQUEST *request,
213 char const *fmt, char *out, size_t outlen)
221 uint8_t const *buff = NULL;
223 while (isspace((int) *fmt)) fmt++;
225 if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
234 if (vp->da->type == PW_TYPE_OCTETS) {
238 * Cast the value_data_t of the VP to an octets string and
242 ret = value_data_cast(request, &dst, PW_TYPE_OCTETS, NULL, vp->da->type,
243 NULL, &vp->data, vp->vp_length);
245 REDEBUG("%s", fr_strerror());
249 p = buff = dst.octets;
255 * Don't truncate the data.
257 if (outlen < (len * 2)) {
258 rad_const_free(buff);
262 for (i = 0; i < len; i++) {
263 snprintf(out + 2*i, 3, "%02x", p[i]);
265 rad_const_free(buff);
270 /** Return the tag of an attribute reference
273 static ssize_t xlat_tag(UNUSED void *instance, REQUEST *request,
274 char const *fmt, char *out, size_t outlen)
278 while (isspace((int) *fmt)) fmt++;
280 if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
285 if (!vp->da->flags.has_tag || !TAG_VALID(vp->tag)) {
290 return snprintf(out, outlen, "%u", vp->tag);
293 /** Return the vendor of an attribute reference
296 static ssize_t xlat_vendor(UNUSED void *instance, REQUEST *request,
297 char const *fmt, char *out, size_t outlen)
302 while (isspace((int) *fmt)) fmt++;
304 if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
309 vendor = dict_vendorbyvalue(vp->da->vendor);
314 strlcpy(out, vendor->name, outlen);
316 return vendor->length;
319 /** Return the vendor number of an attribute reference
322 static ssize_t xlat_vendor_num(UNUSED void *instance, REQUEST *request,
323 char const *fmt, char *out, size_t outlen)
327 while (isspace((int) *fmt)) fmt++;
329 if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
334 return snprintf(out, outlen, "%u", vp->da->vendor);
337 /** Return the attribute name of an attribute reference
340 static ssize_t xlat_attr(UNUSED void *instance, REQUEST *request,
341 char const *fmt, char *out, size_t outlen)
345 while (isspace((int) *fmt)) fmt++;
347 if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
351 strlcpy(out, vp->da->name, outlen);
353 return strlen(vp->da->name);
356 /** Return the attribute number of an attribute reference
359 static ssize_t xlat_attr_num(UNUSED void *instance, REQUEST *request,
360 char const *fmt, char *out, size_t outlen)
364 while (isspace((int) *fmt)) fmt++;
366 if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
371 return snprintf(out, outlen, "%u", vp->da->attr);
374 /** Print out attribute info
376 * Prints out all instances of a current attribute, or all attributes in a list.
378 * At higher debugging levels, also prints out alternative decodings of the same
379 * value. This is helpful to determine types for unknown attributes of long
380 * passed vendors, or just crazy/broken NAS.
382 * This expands to a zero length string.
384 static ssize_t xlat_debug_attr(UNUSED void *instance, REQUEST *request, char const *fmt,
385 char *out, UNUSED size_t outlen)
392 if (!RDEBUG_ENABLED2) {
397 while (isspace((int) *fmt)) fmt++;
399 if (tmpl_from_attr_str(&vpt, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
400 RDEBUG("%s", fr_strerror());
404 RIDEBUG("Attributes matching \"%s\"", fmt);
407 for (vp = tmpl_cursor_init(NULL, &cursor, request, &vpt);
409 vp = tmpl_cursor_next(&cursor, &vpt)) {
410 FR_NAME_NUMBER const *type;
413 value = vp_aprints_value(vp, vp, '\'');
414 if (vp->da->flags.has_tag) {
415 RIDEBUG2("&%s:%s:%i %s %s",
416 fr_int2str(pair_lists, vpt.tmpl_list, "<INVALID>"),
419 fr_int2str(fr_tokens, vp->op, "<INVALID>"),
422 RIDEBUG2("&%s:%s %s %s",
423 fr_int2str(pair_lists, vpt.tmpl_list, "<INVALID>"),
425 fr_int2str(fr_tokens, vp->op, "<INVALID>"),
430 if (!RDEBUG_ENABLED3) continue;
432 if (vp->da->vendor) {
435 dv = dict_vendorbyvalue(vp->da->vendor);
436 RIDEBUG2("Vendor : %i (%s)", vp->da->vendor, dv ? dv->name : "unknown");
438 RIDEBUG2("Type : %s", fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"));
439 RIDEBUG2("Length : %zu", vp->vp_length);
441 if (!RDEBUG_ENABLED4) continue;
443 type = dict_attr_types;
447 value_data_t *dst = NULL;
451 if ((PW_TYPE) type->number == vp->da->type) {
455 switch (type->number) {
456 case PW_TYPE_INVALID: /* Not real type */
457 case PW_TYPE_MAX: /* Not real type */
458 case PW_TYPE_EXTENDED: /* Not safe/appropriate */
459 case PW_TYPE_LONG_EXTENDED: /* Not safe/appropriate */
460 case PW_TYPE_TLV: /* Not safe/appropriate */
461 case PW_TYPE_EVS: /* Not safe/appropriate */
462 case PW_TYPE_VSA: /* @fixme We need special behaviour for these */
463 case PW_TYPE_COMBO_IP_ADDR: /* Covered by IPv4 address IPv6 address */
464 case PW_TYPE_COMBO_IP_PREFIX: /* Covered by IPv4 address IPv6 address */
465 case PW_TYPE_TIMEVAL: /* Not a VALUE_PAIR type */
472 dst = talloc_zero(vp, value_data_t);
473 ret = value_data_cast(dst, dst, type->number, NULL, vp->da->type, vp->da,
474 &vp->data, vp->vp_length);
475 if (ret < 0) goto next_type; /* We expect some to fail */
477 value = value_data_aprints(dst, type->number, NULL, dst, (size_t)ret, '\'');
478 if (!value) goto next_type;
480 if ((pad = (11 - strlen(type->name))) < 0) {
485 RDEBUG2("as %s%*s: %s", type->name, pad, " ", value);
498 /** Processes fmt as a map string and applies it to the current request
500 * e.g. "%{map:&User-Name := 'foo'}"
502 * Allows sets of modifications to be cached and then applied.
503 * Useful for processing generic attributes from LDAP.
505 static ssize_t xlat_map(UNUSED void *instance, REQUEST *request,
506 char const *fmt, char *out, size_t outlen)
508 vp_map_t *map = NULL;
511 if (map_afrom_attr_str(request, &map, fmt,
512 REQUEST_CURRENT, PAIR_LIST_REQUEST,
513 REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
514 REDEBUG("Failed parsing \"%s\" as map: %s", fmt, fr_strerror());
519 ret = map_to_request(request, map, map_to_vp, NULL);
522 if (ret < 0) return strlcpy(out, "0", outlen);
524 return strlcpy(out, "1", outlen);
527 /** Prints the current module processing the request
530 static ssize_t xlat_module(UNUSED void *instance, REQUEST *request,
531 UNUSED char const *fmt, char *out, size_t outlen)
533 strlcpy(out, request->module, outlen);
538 #if defined(HAVE_REGEX) && defined(HAVE_PCRE)
539 static ssize_t xlat_regex(UNUSED void *instance, REQUEST *request,
540 char const *fmt, char *out, size_t outlen)
545 if (regex_request_to_sub_named(request, &p, request, fmt) < 0) {
550 len = talloc_array_length(p);
552 RDEBUG("Insufficient buffer space to write subcapture value, needed %zu bytes, have %zu bytes",
556 strlcpy(out, p, outlen);
558 return len - 1; /* - \0 */
563 /** Implements the Foreach-Variable-X
567 static ssize_t xlat_foreach(void *instance, REQUEST *request,
568 UNUSED char const *fmt, char *out, size_t outlen)
574 * See modcall, "FOREACH" for how this works.
576 pvp = (VALUE_PAIR **) request_data_reference(request, (void *)radius_get_vp, *(int*) instance);
582 len = vp_prints_value(out, outlen, *pvp, 0);
583 if (is_truncated(len, outlen)) {
584 RDEBUG("Insufficient buffer space to write foreach value");
592 /** Print data as string, if possible.
594 * If attribute "Foo" is defined as "octets" it will normally
595 * be printed as 0x0a0a0a. The xlat "%{string:Foo}" will instead
598 static ssize_t xlat_string(UNUSED void *instance, REQUEST *request,
599 char const *fmt, char *out, size_t outlen)
606 while (isspace((int) *fmt)) fmt++;
614 if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
616 ret = rad_vp2data(&p, vp);
621 switch (vp->da->type) {
623 len = fr_prints(out, outlen, (char const *) p, vp->vp_length, '"');
627 * Note that "%{string:...}" is NOT binary safe!
628 * It is explicitly used to get rid of embedded zeros.
631 len = strlcpy(out, vp->vp_strvalue, outlen);
635 len = fr_prints(out, outlen, (char const *) p, ret, '\0');
642 /** xlat expand string attribute value
645 static ssize_t xlat_xlat(UNUSED void *instance, REQUEST *request,
646 char const *fmt, char *out, size_t outlen)
650 while (isspace((int) *fmt)) fmt++;
658 if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
660 if (vp->da->type != PW_TYPE_STRING) goto nothing;
662 return radius_xlat(out, outlen, request, vp->vp_strvalue, NULL, NULL);
665 /** Dynamically change the debugging level for the current request
669 static ssize_t xlat_debug(UNUSED void *instance, REQUEST *request,
670 char const *fmt, char *out, size_t outlen)
675 * Expand to previous (or current) level
677 snprintf(out, outlen, "%d", request->log.lvl);
680 * Assume we just want to get the current value and NOT set it to 0
687 request->log.lvl = RAD_REQUEST_LVL_NONE;
688 request->log.func = NULL;
690 if (level > 4) level = 4;
692 request->log.lvl = level;
693 request->log.func = vradlog_request;
701 * Compare two xlat_t structs, based ONLY on the module name.
703 static int xlat_cmp(void const *one, void const *two)
705 xlat_t const *a = one;
706 xlat_t const *b = two;
708 if (a->length != b->length) {
709 return a->length - b->length;
712 return memcmp(a->name, b->name, a->length);
717 * find the appropriate registered xlat function.
719 static xlat_t *xlat_find(char const *name)
723 strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
724 my_xlat.length = strlen(my_xlat.name);
726 return rbtree_finddata(xlat_root, &my_xlat);
730 /** Register an xlat function.
732 * @param[in] name xlat name.
733 * @param[in] func xlat function to be called.
734 * @param[in] escape function to sanitize any sub expansions passed to the xlat function.
735 * @param[in] instance of module that's registering the xlat function.
736 * @return 0 on success, -1 on failure
738 int xlat_register(char const *name, xlat_func_t func, xlat_escape_t escape, void *instance)
744 if (!name || !*name) {
745 DEBUG("xlat_register: Invalid xlat name");
750 * First time around, build up the tree...
752 * FIXME: This code should be hoisted out of this function,
753 * and into a global "initialization". But it isn't critical...
760 xlat_root = rbtree_create(NULL, xlat_cmp, NULL, RBTREE_FLAG_REPLACE);
762 DEBUG("xlat_register: Failed to create tree");
767 for (i = 0; xlat_foreach_names[i] != NULL; i++) {
768 xlat_register(xlat_foreach_names[i],
769 xlat_foreach, NULL, &xlat_inst[i]);
770 c = xlat_find(xlat_foreach_names[i]);
771 rad_assert(c != NULL);
776 #define XLAT_REGISTER(_x) xlat_register(STRINGIFY(_x), xlat_ ## _x, NULL, NULL); \
777 c = xlat_find(STRINGIFY(_x)); \
778 rad_assert(c != NULL); \
781 XLAT_REGISTER(integer);
782 XLAT_REGISTER(strlen);
783 XLAT_REGISTER(length);
786 XLAT_REGISTER(vendor);
787 XLAT_REGISTER(vendor_num);
789 XLAT_REGISTER(attr_num);
790 XLAT_REGISTER(string);
793 XLAT_REGISTER(module);
794 XLAT_REGISTER(debug_attr);
795 #if defined(HAVE_REGEX) && defined(HAVE_PCRE)
796 XLAT_REGISTER(regex);
799 xlat_register("debug", xlat_debug, NULL, &xlat_inst[0]);
800 c = xlat_find("debug");
801 rad_assert(c != NULL);
806 * If it already exists, replace the instance.
808 strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
809 my_xlat.length = strlen(my_xlat.name);
810 c = rbtree_finddata(xlat_root, &my_xlat);
813 DEBUG("xlat_register: Cannot re-define internal xlat");
819 c->instance = instance;
824 * Doesn't exist. Create it.
826 c = talloc_zero(xlat_root, xlat_t);
830 strlcpy(c->name, name, sizeof(c->name));
831 c->length = strlen(c->name);
832 c->instance = instance;
834 node = rbtree_insert_node(xlat_root, c);
841 * Ensure that the data is deleted when the node is
844 * @todo: Maybe this should be the other way around...
845 * when a thing IN the tree is deleted, it's automatically
846 * removed from the tree. But for now, this works.
848 (void) talloc_steal(node, c);
852 /** Unregister an xlat function
854 * We can only have one function to call per name, so the passing of "func"
855 * here is extraneous.
857 * @param[in] name xlat to unregister.
858 * @param[in] func unused.
859 * @param[in] instance data.
861 void xlat_unregister(char const *name, UNUSED xlat_func_t func, void *instance)
866 if (!name || !xlat_root) return;
868 strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
869 my_xlat.length = strlen(my_xlat.name);
871 c = rbtree_finddata(xlat_root, &my_xlat);
874 if (c->instance != instance) return;
876 rbtree_deletebydata(xlat_root, c);
879 static int xlat_unregister_callback(void *instance, void *data)
881 xlat_t *c = (xlat_t *) data;
883 if (c->instance != instance) return 0; /* keep walking */
885 return 2; /* delete it */
888 void xlat_unregister_module(void *instance)
890 rbtree_walk(xlat_root, RBTREE_DELETE_ORDER, xlat_unregister_callback, instance);
894 * Internal redundant handler for xlats
896 typedef enum xlat_redundant_type_t {
900 XLAT_REDUNDANT_LOAD_BALANCE,
901 } xlat_redundant_type_t;
903 typedef struct xlat_redundant_t {
904 xlat_redundant_type_t type;
910 static ssize_t xlat_redundant(void *instance, REQUEST *request,
911 char const *fmt, char *out, size_t outlen)
913 xlat_redundant_t *xr = instance;
918 rad_assert(xr->type == XLAT_REDUNDANT);
921 * Pick the first xlat which succeeds
923 for (ci = cf_item_find_next(xr->cs, NULL);
925 ci = cf_item_find_next(xr->cs, ci)) {
928 if (!cf_item_is_pair(ci)) continue;
930 name = cf_pair_attr(cf_item_to_pair(ci));
931 rad_assert(name != NULL);
933 xlat = xlat_find(name);
936 rcode = xlat->func(xlat->instance, request, fmt, out, outlen);
937 if (rcode <= 0) continue;
942 * Everything failed. Oh well.
949 static ssize_t xlat_load_balance(void *instance, REQUEST *request,
950 char const *fmt, char *out, size_t outlen)
953 xlat_redundant_t *xr = instance;
955 CONF_ITEM *found = NULL;
960 * Choose a child at random.
962 for (ci = cf_item_find_next(xr->cs, NULL);
964 ci = cf_item_find_next(xr->cs, ci)) {
965 if (!cf_item_is_pair(ci)) continue;
969 * Replace the previously found one with a random
972 if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
978 * Plain load balancing: do one child, and only one child.
980 if (xr->type == XLAT_LOAD_BALANCE) {
981 name = cf_pair_attr(cf_item_to_pair(found));
982 rad_assert(name != NULL);
984 xlat = xlat_find(name);
985 if (!xlat) return -1;
987 return xlat->func(xlat->instance, request, fmt, out, outlen);
990 rad_assert(xr->type == XLAT_REDUNDANT_LOAD_BALANCE);
993 * Try the random one we found. If it fails, keep going
994 * through the rest of the children.
998 name = cf_pair_attr(cf_item_to_pair(ci));
999 rad_assert(name != NULL);
1001 xlat = xlat_find(name);
1005 rcode = xlat->func(xlat->instance, request, fmt, out, outlen);
1006 if (rcode > 0) return rcode;
1010 * Go to the next one, wrapping around at the end.
1012 ci = cf_item_find_next(xr->cs, ci);
1013 if (!ci) ci = cf_item_find_next(xr->cs, NULL);
1014 } while (ci != found);
1020 bool xlat_register_redundant(CONF_SECTION *cs)
1022 char const *name1, *name2;
1023 xlat_redundant_t *xr;
1025 name1 = cf_section_name1(cs);
1026 name2 = cf_section_name2(cs);
1028 if (!name2) return false;
1030 if (xlat_find(name2)) {
1031 cf_log_err_cs(cs, "An expansion is already registered for this name");
1035 xr = talloc_zero(cs, xlat_redundant_t);
1036 if (!xr) return false;
1038 if (strcmp(name1, "redundant") == 0) {
1039 xr->type = XLAT_REDUNDANT;
1041 } else if (strcmp(name1, "redundant-load-balance") == 0) {
1042 xr->type = XLAT_REDUNDANT_LOAD_BALANCE;
1044 } else if (strcmp(name1, "load-balance") == 0) {
1045 xr->type = XLAT_LOAD_BALANCE;
1054 * Get the number of children for load balancing.
1056 if (xr->type == XLAT_REDUNDANT) {
1057 if (xlat_register(name2, xlat_redundant, NULL, xr) < 0) {
1065 for (ci = cf_item_find_next(cs, NULL);
1067 ci = cf_item_find_next(cs, ci)) {
1068 if (!cf_item_is_pair(ci)) continue;
1070 if (!xlat_find(cf_pair_attr(cf_item_to_pair(ci)))) {
1078 if (xlat_register(name2, xlat_load_balance, NULL, xr) < 0) {
1088 /** Crappy temporary function to add attribute ref support to xlats
1090 * This needs to die, and hopefully will die, when xlat functions accept
1091 * xlat node structures.
1093 * Provides either a pointer to a buffer which contains the value of the reference VALUE_PAIR
1094 * in an architecture independent format. Or a pointer to the start of the fmt string.
1096 * The pointer is only guaranteed to be valid between calls to xlat_fmt_to_ref,
1097 * and so long as the source VALUE_PAIR is not freed.
1099 * @param out where to write a pointer to the buffer to the data the xlat function needs to work on.
1100 * @param request current request.
1101 * @param fmt string.
1102 * @returns the length of the data or -1 on error.
1104 ssize_t xlat_fmt_to_ref(uint8_t const **out, REQUEST *request, char const *fmt)
1108 while (isspace((int) *fmt)) fmt++;
1110 if (fmt[0] == '&') {
1111 if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
1116 return rad_vp2data(out, vp);
1119 *out = (uint8_t const *)fmt;
1123 /** De-register all xlat functions, used mainly for debugging.
1126 void xlat_free(void)
1128 rbtree_free(xlat_root);
1132 # define XLAT_DEBUG DEBUG3
1134 # define XLAT_DEBUG(...)
1137 static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1138 char const **error);
1139 static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1140 bool brace, char const **error);
1141 static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const * const head,
1142 xlat_escape_t escape, void *escape_ctx);
1144 static ssize_t xlat_tokenize_alternation(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1151 rad_assert(fmt[0] == '%');
1152 rad_assert(fmt[1] == '{');
1153 rad_assert(fmt[2] == '%');
1154 rad_assert(fmt[3] == '{');
1156 XLAT_DEBUG("ALTERNATE <-- %s", fmt);
1158 node = talloc_zero(ctx, xlat_exp_t);
1159 node->type = XLAT_ALTERNATE;
1162 slen = xlat_tokenize_expansion(node, p, &node->child, error);
1165 return slen - (p - fmt);
1171 *error = "Expected ':' after first expansion";
1178 *error = "Expected '-' after ':'";
1184 * Allow the RHS to be empty as a special case.
1188 * Hack up an empty string.
1190 node->alternate = talloc_zero(node, xlat_exp_t);
1191 node->alternate->type = XLAT_LITERAL;
1192 node->alternate->fmt = talloc_typed_strdup(node->alternate, "");
1196 slen = xlat_tokenize_literal(node, p, &node->alternate, true, error);
1199 return slen - (p - fmt);
1202 if (!node->alternate) {
1204 *error = "Empty expansion is invalid";
1214 static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1222 rad_assert(fmt[0] == '%');
1223 rad_assert(fmt[1] == '{');
1228 if ((fmt[2] == '%') && (fmt[3] == '{')) return xlat_tokenize_alternation(ctx, fmt, head, error);
1230 XLAT_DEBUG("EXPANSION <-- %s", fmt);
1231 node = talloc_zero(ctx, xlat_exp_t);
1232 node->fmt = fmt + 2;
1237 * Handle regex's specially.
1240 num = strtol(p, &q, 10);
1241 if (p != q && (*q == '}')) {
1242 XLAT_DEBUG("REGEX <-- %s", fmt);
1245 if ((num > REQUEST_MAX_REGEX) || (num < 0)) {
1247 *error = "Invalid regex reference. Must be in range 0-" STRINGIFY(REQUEST_MAX_REGEX);
1250 node->attr.tmpl_num = num;
1252 node->type = XLAT_REGEX;
1255 return (q - fmt) + 1;
1257 #endif /* HAVE_REGEX */
1262 * %{Tunnel-Password:1}
1263 * %{Tunnel-Password:1[#]}
1264 * %{request:Attr-Name}
1265 * %{request:Tunnel-Password:1}
1266 * %{request:Tunnel-Password:1[#]}
1271 * This is for efficiency, so we don't search for an xlat,
1272 * when what's being referenced is obviously an attribute.
1275 for (q = p; *q != '\0'; q++) {
1276 if (*q == ':') break;
1278 if (isspace((int) *q)) break;
1280 if (*q == '[') continue;
1282 if (*q == '}') break;
1286 * Check for empty expressions %{}
1288 if ((*q == '}') && (q == p)) {
1290 *error = "Empty expression is invalid";
1295 * Might be a module name reference.
1297 * If it's not, it's an attribute or parse error.
1301 node->xlat = xlat_find(node->fmt);
1306 node->type = XLAT_MODULE;
1309 XLAT_DEBUG("MOD <-- %s ... %s", node->fmt, p);
1311 slen = xlat_tokenize_literal(node, p, &node->child, true, error);
1314 return slen - (p - fmt);
1319 rad_assert(node->next == NULL);
1323 *q = ':'; /* Avoids a strdup */
1327 * The first token ends with:
1328 * - '[' - Which is an attribute index, so it must be an attribute.
1329 * - '}' - The end of the expansion, which means it was a bareword.
1331 slen = tmpl_from_attr_substr(&node->attr, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, true, true);
1334 * If the parse error occurred before the ':'
1335 * then the error is changed to 'Unknown module',
1336 * as it was more likely to be a bad module name,
1337 * than a request qualifier.
1339 if ((*q == ':') && ((p + (slen * -1)) < q)) {
1340 *error = "Unknown module";
1342 *error = fr_strerror();
1346 return slen - (p - fmt);
1350 * Might be a virtual XLAT attribute
1352 if (node->attr.type == TMPL_TYPE_ATTR_UNDEFINED) {
1353 node->xlat = xlat_find(node->attr.tmpl_unknown_name);
1354 if (node->xlat && node->xlat->instance && !node->xlat->internal) {
1356 *error = "Missing content in expansion";
1357 return -(p - fmt) - slen;
1361 node->type = XLAT_VIRTUAL;
1362 node->fmt = node->attr.tmpl_unknown_name;
1364 XLAT_DEBUG("VIRTUAL <-- %s", node->fmt);
1366 rad_assert(node->next == NULL);
1372 *error = "Unknown attribute";
1376 node->type = XLAT_ATTRIBUTE;
1381 *error = "No matching closing brace";
1382 return -1; /* second character of format string */
1386 rad_assert(node->next == NULL);
1392 static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1393 bool brace, char const **error)
1398 if (!*fmt) return 0;
1400 XLAT_DEBUG("LITERAL <-- %s", fmt);
1402 node = talloc_zero(ctx, xlat_exp_t);
1405 node->type = XLAT_LITERAL;
1413 *error = "Invalid escape at end of string";
1423 * Process the expansion.
1425 if ((p[0] == '%') && (p[1] == '{')) {
1428 XLAT_DEBUG("EXPANSION-2 <-- %s", node->fmt);
1430 slen = xlat_tokenize_expansion(node, p, &node->next, error);
1433 return slen - (p - fmt);
1435 *p = '\0'; /* end the literal */
1438 rad_assert(node->next != NULL);
1441 * Short-circuit the recursive call.
1442 * This saves another function call and
1443 * memory allocation.
1448 * "foo %{User-Name} bar"
1450 * EXPANSION User-Name
1453 slen = xlat_tokenize_literal(node->next, p, &(node->next->next), brace, error);
1454 rad_assert(slen != 0);
1457 return slen - (p - fmt);
1460 brace = false; /* it was found above, or else the above code errored out */
1462 break; /* stop processing the string */
1466 * Check for valid single-character expansions.
1472 if (!p[1] || !strchr("%}dlmntDGHISTYv", p[1])) {
1474 *error = "Invalid variable expansion";
1479 next = talloc_zero(node, xlat_exp_t);
1485 next->fmt = talloc_strndup(next, p + 1, 1);
1487 XLAT_DEBUG("LITERAL-ESCAPED <-- %s", next->fmt);
1488 next->type = XLAT_LITERAL;
1494 XLAT_DEBUG("PERCENT <-- %c", *next->fmt);
1495 next->type = XLAT_PERCENT;
1508 slen = xlat_tokenize_literal(node->next, p, &(node->next->next), brace, error);
1509 rad_assert(slen != 0);
1512 return slen - (p - fmt);
1515 brace = false; /* it was found above, or else the above code errored out */
1517 break; /* stop processing the string */
1521 * If required, eat the brace.
1523 if (brace && (*p == '}')) {
1535 * We were told to look for a brace, but we ran off of
1536 * the end of the string before we found one.
1539 *error = "Missing closing brace at end of string";
1544 * Squash zero-width literals
1546 if (node->len > 0) {
1550 (void) talloc_steal(ctx, node->next);
1559 static char const xlat_tabs[] = " ";
1561 static void xlat_tokenize_debug(xlat_exp_t const *node, int lvl)
1563 rad_assert(node != NULL);
1565 if (lvl >= (int) sizeof(xlat_tabs)) lvl = sizeof(xlat_tabs);
1568 switch (node->type) {
1570 DEBUG("%.*sliteral --> %s", lvl, xlat_tabs, node->fmt);
1574 DEBUG("%.*spercent --> %c", lvl, xlat_tabs, node->fmt[0]);
1577 case XLAT_ATTRIBUTE:
1578 rad_assert(node->attr.tmpl_da != NULL);
1579 DEBUG("%.*sattribute --> %s", lvl, xlat_tabs, node->attr.tmpl_da->name);
1580 rad_assert(node->child == NULL);
1581 if ((node->attr.tmpl_tag != TAG_ANY) || (node->attr.tmpl_num != NUM_ANY)) {
1582 DEBUG("%.*s{", lvl, xlat_tabs);
1584 DEBUG("%.*sref %d", lvl + 1, xlat_tabs, node->attr.tmpl_request);
1585 DEBUG("%.*slist %d", lvl + 1, xlat_tabs, node->attr.tmpl_list);
1587 if (node->attr.tmpl_tag != TAG_ANY) {
1588 DEBUG("%.*stag %d", lvl + 1, xlat_tabs, node->attr.tmpl_tag);
1590 if (node->attr.tmpl_num != NUM_ANY) {
1591 if (node->attr.tmpl_num == NUM_COUNT) {
1592 DEBUG("%.*s[#]", lvl + 1, xlat_tabs);
1593 } else if (node->attr.tmpl_num == NUM_ALL) {
1594 DEBUG("%.*s[*]", lvl + 1, xlat_tabs);
1596 DEBUG("%.*s[%d]", lvl + 1, xlat_tabs, node->attr.tmpl_num);
1600 DEBUG("%.*s}", lvl, xlat_tabs);
1605 rad_assert(node->fmt != NULL);
1606 DEBUG("%.*svirtual --> %s", lvl, xlat_tabs, node->fmt);
1610 rad_assert(node->xlat != NULL);
1611 DEBUG("%.*sxlat --> %s", lvl, xlat_tabs, node->xlat->name);
1613 DEBUG("%.*s{", lvl, xlat_tabs);
1614 xlat_tokenize_debug(node->child, lvl + 1);
1615 DEBUG("%.*s}", lvl, xlat_tabs);
1621 DEBUG("%.*sregex-var --> %d", lvl, xlat_tabs, node->attr.tmpl_num);
1625 case XLAT_ALTERNATE:
1626 DEBUG("%.*sXLAT-IF {", lvl, xlat_tabs);
1627 xlat_tokenize_debug(node->child, lvl + 1);
1628 DEBUG("%.*s}", lvl, xlat_tabs);
1629 DEBUG("%.*sXLAT-ELSE {", lvl, xlat_tabs);
1630 xlat_tokenize_debug(node->alternate, lvl + 1);
1631 DEBUG("%.*s}", lvl, xlat_tabs);
1638 size_t xlat_sprint(char *buffer, size_t bufsize, xlat_exp_t const *node)
1649 end = buffer + bufsize;
1652 switch (node->type) {
1654 strlcpy(p, node->fmt, end - p);
1660 p[1] = node->fmt[0];
1664 case XLAT_ATTRIBUTE:
1668 if (node->attr.tmpl_request != REQUEST_CURRENT) {
1669 strlcpy(p, fr_int2str(request_refs, node->attr.tmpl_request, "??"), end - p);
1674 if ((node->attr.tmpl_request != REQUEST_CURRENT) ||
1675 (node->attr.tmpl_list != PAIR_LIST_REQUEST)) {
1676 strlcpy(p, fr_int2str(pair_lists, node->attr.tmpl_list, "??"), end - p);
1681 strlcpy(p, node->attr.tmpl_da->name, end - p);
1684 if (node->attr.tmpl_tag != TAG_ANY) {
1686 snprintf(p, end - p, "%u", node->attr.tmpl_tag);
1690 if (node->attr.tmpl_num != NUM_ANY) {
1692 switch (node->attr.tmpl_num) {
1702 snprintf(p, end - p, "%i", node->attr.tmpl_num);
1711 snprintf(p, end - p, "%%{%i}", node->attr.tmpl_num);
1718 strlcpy(p, node->fmt, end - p);
1726 strlcpy(p, node->xlat->name, end - p);
1729 rad_assert(node->child != NULL);
1730 len = xlat_sprint(p, end - p, node->child);
1735 case XLAT_ALTERNATE:
1739 len = xlat_sprint(p, end - p, node->child);
1745 len = xlat_sprint(p, end - p, node->alternate);
1753 if (p == end) break;
1763 ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1766 return xlat_tokenize_literal(ctx, fmt, head, false, error);
1770 /** Tokenize an xlat expansion
1772 * @param[in] request the input request. Memory will be attached here.
1773 * @param[in] fmt the format string to expand
1774 * @param[out] head the head of the xlat list / tree structure.
1776 static ssize_t xlat_tokenize_request(REQUEST *request, char const *fmt, xlat_exp_t **head)
1780 char const *error = NULL;
1785 * Copy the original format string to a buffer so that
1786 * the later functions can mangle it in-place, which is
1789 tokens = talloc_typed_strdup(request, fmt);
1790 if (!tokens) return -1;
1792 slen = xlat_tokenize_literal(request, tokens, head, false, &error);
1795 * Zero length expansion, return a zero length node.
1798 *head = talloc_zero(request, xlat_exp_t);
1802 * Output something like:
1805 * " ^ error was here"
1808 talloc_free(tokens);
1809 rad_assert(error != NULL);
1811 REMARKER(fmt, -slen, error);
1815 if (*head && (rad_debug_lvl > 2)) {
1817 DEBUG("Parsed xlat tree:");
1818 xlat_tokenize_debug(*head, 0);
1822 * All of the nodes point to offsets in the "tokens"
1823 * string. Let's ensure that free'ing head will free
1826 (void) talloc_steal(*head, tokens);
1832 static char *xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, vp_tmpl_t const *vpt,
1833 bool escape, bool return_null)
1835 VALUE_PAIR *vp = NULL, *virtual = NULL;
1836 RADIUS_PACKET *packet = NULL;
1841 char quote = escape ? '"' : '\0';
1843 rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
1846 * We only support count and concatenate operations on lists.
1848 if (vpt->type == TMPL_TYPE_LIST) {
1849 vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
1854 * See if we're dealing with an attribute in the request
1856 * This allows users to manipulate virtual attributes as if
1857 * they were real ones.
1859 vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
1860 if (vp) goto do_print;
1863 * We didn't find the VP in a list.
1864 * If it's not a virtual one, and we're not meant to
1865 * be counting it, return.
1867 if (!vpt->tmpl_da->flags.virtual) {
1868 if (vpt->tmpl_num == NUM_COUNT) goto do_print;
1873 * Switch out the request to the one specified by the template
1875 if (radius_request(&request, vpt->tmpl_request) < 0) return NULL;
1878 * Some non-packet expansions
1880 switch (vpt->tmpl_da->attr) {
1882 break; /* ignore them */
1884 case PW_CLIENT_SHORTNAME:
1885 if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
1886 if (request->client && request->client->shortname) {
1887 return talloc_typed_strdup(ctx, request->client->shortname);
1889 return talloc_typed_strdup(ctx, "<UNKNOWN-CLIENT>");
1891 case PW_REQUEST_PROCESSING_STAGE:
1892 if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
1893 if (request->component) {
1894 return talloc_typed_strdup(ctx, request->component);
1896 return talloc_typed_strdup(ctx, "server_core");
1898 case PW_VIRTUAL_SERVER:
1899 if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
1900 if (!request->server) return NULL;
1901 return talloc_typed_strdup(ctx, request->server);
1903 case PW_MODULE_RETURN_CODE:
1904 if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
1905 if (!request->rcode) return NULL;
1906 return talloc_typed_strdup(ctx, fr_int2str(modreturn_table, request->rcode, ""));
1910 * All of the attributes must now refer to a packet.
1911 * If there's no packet, we can't print any attribute
1914 packet = radius_packet(request, vpt->tmpl_list);
1916 if (return_null) return NULL;
1917 return vp_aprints_type(ctx, vpt->tmpl_da->type);
1921 switch (vpt->tmpl_da->attr) {
1925 case PW_PACKET_TYPE:
1926 dv = dict_valbyattr(PW_PACKET_TYPE, 0, packet->code);
1927 if (dv) return talloc_typed_strdup(ctx, dv->name);
1928 return talloc_typed_asprintf(ctx, "%d", packet->code);
1930 case PW_RESPONSE_PACKET_TYPE:
1935 if (request->proxy_reply && (!request->reply || !request->reply->code)) {
1936 code = request->proxy_reply->code;
1939 if (request->reply) {
1940 code = request->reply->code;
1943 return talloc_typed_strdup(ctx, fr_packet_codes[code]);
1947 * Virtual attributes which require a temporary VALUE_PAIR
1948 * to be allocated. We can't use stack allocated memory
1949 * because of the talloc checks sprinkled throughout the
1950 * various VP functions.
1952 case PW_PACKET_AUTHENTICATION_VECTOR:
1953 virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1954 fr_pair_value_memcpy(virtual, packet->vector, sizeof(packet->vector));
1958 case PW_CLIENT_IP_ADDRESS:
1959 case PW_PACKET_SRC_IP_ADDRESS:
1960 if (packet->src_ipaddr.af == AF_INET) {
1961 virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1962 virtual->vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
1967 case PW_PACKET_DST_IP_ADDRESS:
1968 if (packet->dst_ipaddr.af == AF_INET) {
1969 virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1970 virtual->vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
1975 case PW_PACKET_SRC_IPV6_ADDRESS:
1976 if (packet->src_ipaddr.af == AF_INET6) {
1977 virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1978 memcpy(&virtual->vp_ipv6addr,
1979 &packet->src_ipaddr.ipaddr.ip6addr,
1980 sizeof(packet->src_ipaddr.ipaddr.ip6addr));
1985 case PW_PACKET_DST_IPV6_ADDRESS:
1986 if (packet->dst_ipaddr.af == AF_INET6) {
1987 virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1988 memcpy(&virtual->vp_ipv6addr,
1989 &packet->dst_ipaddr.ipaddr.ip6addr,
1990 sizeof(packet->dst_ipaddr.ipaddr.ip6addr));
1995 case PW_PACKET_SRC_PORT:
1996 virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1997 virtual->vp_integer = packet->src_port;
2001 case PW_PACKET_DST_PORT:
2002 virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
2003 virtual->vp_integer = packet->dst_port;
2009 * Fake various operations for virtual attributes.
2012 if (vpt->tmpl_num != NUM_ANY) switch (vpt->tmpl_num) {
2014 * [n] is NULL (we only have [0])
2019 * [*] means only one.
2025 * [#] means 1 (as there's only one)
2029 ret = talloc_strdup(ctx, "1");
2033 * [0] is fine (get the first instance)
2042 switch (vpt->tmpl_num) {
2044 * Return a count of the VPs.
2050 for (vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
2052 vp = tmpl_cursor_next(&cursor, vpt)) count++;
2054 return talloc_typed_asprintf(ctx, "%d", count);
2059 * Concatenate all values together,
2060 * separated by commas.
2066 if (!fr_cursor_current(&cursor)) return NULL;
2067 p = vp_aprints_value(ctx, vp, quote);
2068 if (!p) return NULL;
2070 while ((vp = tmpl_cursor_next(&cursor, vpt)) != NULL) {
2071 q = vp_aprints_value(ctx, vp, quote);
2072 if (!q) return NULL;
2073 p = talloc_strdup_append(p, ",");
2074 p = talloc_strdup_append(p, q);
2082 * The cursor was set to the correct
2083 * position above by tmpl_cursor_init.
2085 vp = fr_cursor_current(&cursor);
2090 if (return_null) return NULL;
2091 return vp_aprints_type(ctx, vpt->tmpl_da->type);
2095 ret = vp_aprints_value(ctx, vp, quote);
2098 talloc_free(virtual);
2103 static const char xlat_spaces[] = " ";
2106 static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * const node,
2107 xlat_escape_t escape, void *escape_ctx, int lvl)
2110 char *str = NULL, *child;
2113 XLAT_DEBUG("%.*sxlat aprint %d %s", lvl, xlat_spaces, node->type, node->fmt);
2115 switch (node->type) {
2117 * Don't escape this.
2120 XLAT_DEBUG("%.*sxlat_aprint LITERAL", lvl, xlat_spaces);
2121 return talloc_typed_strdup(ctx, node->fmt);
2124 * Do a one-character expansion.
2129 size_t freespace = 256;
2134 XLAT_DEBUG("%.*sxlat_aprint PERCENT", lvl, xlat_spaces);
2136 str = talloc_array(ctx, char, freespace); /* @todo do better allocation */
2139 when = request->timestamp;
2141 if (request->packet) {
2142 when = request->packet->timestamp.tv_sec;
2143 usec = request->packet->timestamp.tv_usec;
2152 case 'd': /* request day */
2153 if (!localtime_r(&when, &ts)) goto error;
2154 strftime(str, freespace, "%d", &ts);
2157 case 'l': /* request timestamp */
2158 snprintf(str, freespace, "%lu",
2159 (unsigned long) when);
2162 case 'm': /* request month */
2163 if (!localtime_r(&when, &ts)) goto error;
2164 strftime(str, freespace, "%m", &ts);
2167 case 'n': /* Request Number*/
2168 snprintf(str, freespace, "%u", request->number);
2171 case 't': /* request timestamp */
2172 CTIME_R(&when, str, freespace);
2173 nl = strchr(str, '\n');
2177 case 'D': /* request date */
2178 if (!localtime_r(&when, &ts)) goto error;
2179 strftime(str, freespace, "%Y%m%d", &ts);
2182 case 'G': /* request minute */
2183 if (!localtime_r(&when, &ts)) goto error;
2184 strftime(str, freespace, "%M", &ts);
2187 case 'H': /* request hour */
2188 if (!localtime_r(&when, &ts)) goto error;
2189 strftime(str, freespace, "%H", &ts);
2192 case 'I': /* Request ID */
2193 if (request->packet) {
2194 snprintf(str, freespace, "%i", request->packet->id);
2198 case 'S': /* request timestamp in SQL format*/
2199 if (!localtime_r(&when, &ts)) goto error;
2200 nl = str + strftime(str, freespace, "%Y-%m-%d %H:%M:%S", &ts);
2201 rad_assert(((str + freespace) - nl) >= 8);
2202 snprintf(nl, (str + freespace) - nl, ".%06d", usec);
2205 case 'T': /* request timestamp */
2206 if (!localtime_r(&when, &ts)) goto error;
2207 strftime(str, freespace, "%Y-%m-%d-%H.%M.%S", &ts);
2211 case 'Y': /* request year */
2212 if (!localtime_r(&when, &ts)) {
2214 REDEBUG("Failed converting packet timestamp to localtime: %s", fr_syserror(errno));
2218 strftime(str, freespace, "%Y", &ts);
2221 case 'v': /* Version of code */
2222 RWDEBUG("%%v is deprecated and will be removed. Use ${version.freeradius-server}");
2223 snprintf(str, freespace, "%s", radiusd_version_short);
2233 case XLAT_ATTRIBUTE:
2234 XLAT_DEBUG("%.*sxlat_aprint ATTRIBUTE", lvl, xlat_spaces);
2237 * Some attributes are virtual <sigh>
2239 str = xlat_getvp(ctx, request, &node->attr, escape ? false : true, true);
2241 XLAT_DEBUG("%.*sEXPAND attr %s", lvl, xlat_spaces, node->attr.tmpl_da->name);
2242 XLAT_DEBUG("%.*s ---> %s", lvl ,xlat_spaces, str);
2247 XLAT_DEBUG("xlat_aprint VIRTUAL");
2248 str = talloc_array(ctx, char, 2048); /* FIXME: have the module call talloc_typed_asprintf */
2249 rcode = node->xlat->func(node->xlat->instance, request, NULL, str, 2048);
2254 RDEBUG2("EXPAND %s", node->xlat->name);
2255 RDEBUG2(" --> %s", str);
2259 XLAT_DEBUG("xlat_aprint MODULE");
2262 if (xlat_process(&child, request, node->child, node->xlat->escape, node->xlat->instance) == 0) {
2266 XLAT_DEBUG("%.*sEXPAND mod %s %s", lvl, xlat_spaces, node->fmt, node->child->fmt);
2268 XLAT_DEBUG("%.*sEXPAND mod %s", lvl, xlat_spaces, node->fmt);
2269 child = talloc_typed_strdup(ctx, "");
2272 XLAT_DEBUG("%.*s ---> %s", lvl, xlat_spaces, child);
2277 * The OUTPUT of xlat is a "raw" string. The INPUT is a printable string.
2279 * This is really the reverse of fr_prints().
2281 if (cf_new_escape && *child) {
2286 type = PW_TYPE_STRING;
2287 slen = value_data_from_str(request, &data, &type, NULL, child, talloc_array_length(child) - 1, '"');
2301 if (*p == '\\') switch (p[1]) {
2323 str = talloc_array(ctx, char, 2048); /* FIXME: have the module call talloc_typed_asprintf */
2324 *str = '\0'; /* Be sure the string is NULL terminated, we now only free on error */
2326 rcode = node->xlat->func(node->xlat->instance, request, child, str, 2048);
2336 XLAT_DEBUG("%.*sxlat_aprint REGEX", lvl, xlat_spaces);
2337 if (regex_request_to_sub(ctx, &str, request, node->attr.tmpl_num) < 0) return NULL;
2342 case XLAT_ALTERNATE:
2343 XLAT_DEBUG("%.*sxlat_aprint ALTERNATE", lvl, xlat_spaces);
2344 rad_assert(node->child != NULL);
2345 rad_assert(node->alternate != NULL);
2348 * If there are no "next" nodes, call ourselves
2349 * recursively, which is fast.
2351 * If there are "next" nodes, call xlat_process()
2352 * which does a ton more work.
2355 str = xlat_aprint(ctx, request, node->child, escape, escape_ctx, lvl);
2357 XLAT_DEBUG("%.*sALTERNATE got first string: %s", lvl, xlat_spaces, str);
2359 str = xlat_aprint(ctx, request, node->alternate, escape, escape_ctx, lvl);
2360 XLAT_DEBUG("%.*sALTERNATE got alternate string %s", lvl, xlat_spaces, str);
2364 if (xlat_process(&str, request, node->child, escape, escape_ctx) > 0) {
2365 XLAT_DEBUG("%.*sALTERNATE got first string: %s", lvl, xlat_spaces, str);
2367 (void) xlat_process(&str, request, node->alternate, escape, escape_ctx);
2368 XLAT_DEBUG("%.*sALTERNATE got alternate string %s", lvl, xlat_spaces, str);
2375 * If there's no data, return that, instead of an empty string.
2377 if (str && !str[0]) {
2383 * Escape the non-literals we found above.
2385 if (str && escape) {
2389 len = talloc_array_length(str) * 3;
2391 escaped = talloc_array(ctx, char, len);
2392 escape(request, escaped, len, str, escape_ctx);
2401 static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const * const head,
2402 xlat_escape_t escape, void *escape_ctx)
2406 char **array, *answer;
2407 xlat_exp_t const *node;
2412 * There are no nodes to process, so the result is a zero
2416 *out = talloc_zero_array(request, char, 1);
2421 * Hack for speed. If it's one expansion, just allocate
2422 * that and return, instead of allocating an intermediary
2427 * Pass the MAIN escape function. Recursive
2428 * calls will call node-specific escape
2431 answer = xlat_aprint(request, request, head, escape, escape_ctx, 0);
2433 *out = talloc_zero_array(request, char, 1);
2437 return strlen(answer);
2440 list = 0; /* FIXME: calculate this once */
2441 for (node = head; node != NULL; node = node->next) {
2445 array = talloc_array(request, char *, list);
2446 if (!array) return -1;
2448 for (node = head, i = 0; node != NULL; node = node->next, i++) {
2449 array[i] = xlat_aprint(array, request, node, escape, escape_ctx, 0); /* may be NULL */
2453 for (i = 0; i < list; i++) {
2454 if (array[i]) total += strlen(array[i]); /* FIXME: calculate strlen once */
2459 *out = talloc_zero_array(request, char, 1);
2463 answer = talloc_array(request, char, total + 1);
2466 for (i = 0; i < list; i++) {
2470 len = strlen(array[i]);
2471 memcpy(answer + total, array[i], len);
2475 answer[total] = '\0';
2476 talloc_free(array); /* and child entries */
2483 /** Replace %whatever in a string.
2485 * See 'doc/configuration/variables.rst' for more information.
2487 * @param[out] out Where to write pointer to output buffer.
2488 * @param[in] outlen Size of out.
2489 * @param[in] request current request.
2490 * @param[in] node the xlat structure to expand
2491 * @param[in] escape function to escape final value e.g. SQL quoting.
2492 * @param[in] escape_ctx pointer to pass to escape function.
2493 * @return length of string written @bug should really have -1 for failure
2495 static ssize_t xlat_expand_struct(char **out, size_t outlen, REQUEST *request, xlat_exp_t const *node,
2496 xlat_escape_t escape, void *escape_ctx)
2501 rad_assert(node != NULL);
2503 len = xlat_process(&buff, request, node, escape, escape_ctx);
2504 if ((len < 0) || !buff) {
2505 rad_assert(buff == NULL);
2506 if (*out) *out[0] = '\0';
2513 * If out doesn't point to an existing buffer
2514 * copy the pointer to our buffer over.
2522 * Otherwise copy the malloced buffer to the fixed one.
2524 strlcpy(*out, buff, outlen);
2529 static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
2530 xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull (1, 3, 4));
2532 /** Replace %whatever in a string.
2534 * See 'doc/configuration/variables.rst' for more information.
2536 * @param[out] out Where to write pointer to output buffer.
2537 * @param[in] outlen Size of out.
2538 * @param[in] request current request.
2539 * @param[in] fmt string to expand.
2540 * @param[in] escape function to escape final value e.g. SQL quoting.
2541 * @param[in] escape_ctx pointer to pass to escape function.
2542 * @return length of string written @bug should really have -1 for failure
2544 static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
2545 xlat_escape_t escape, void *escape_ctx)
2551 * Give better errors than the old code.
2553 len = xlat_tokenize_request(request, fmt, &node);
2558 *out = talloc_zero_array(request, char, 1);
2564 if (*out) *out[0] = '\0';
2568 len = xlat_expand_struct(out, outlen, request, node, escape, escape_ctx);
2571 RDEBUG2("EXPAND %s", fmt);
2572 RDEBUG2(" --> %s", *out);
2577 /** Try to convert an xlat to a tmpl for efficiency
2579 * @param ctx to allocate new vp_tmpl_t in.
2580 * @param node to convert.
2581 * @return NULL if unable to convert (not necessarily error), or a new vp_tmpl_t.
2583 vp_tmpl_t *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_t *node)
2587 if (node->next || (node->type != XLAT_ATTRIBUTE) || (node->attr.type != TMPL_TYPE_ATTR)) return NULL;
2590 * Concat means something completely different as an attribute reference
2591 * Count isn't implemented.
2593 if ((node->attr.tmpl_num == NUM_COUNT) || (node->attr.tmpl_num == NUM_ALL)) return NULL;
2595 vpt = tmpl_alloc(ctx, TMPL_TYPE_ATTR, node->fmt, -1);
2596 if (!vpt) return NULL;
2597 memcpy(&vpt->data, &node->attr.data, sizeof(vpt->data));
2604 /** Try to convert attr tmpl to an xlat for &attr[*] and artificially constructing expansions
2606 * @param ctx to allocate new xlat_expt_t in.
2607 * @param vpt to convert.
2608 * @return NULL if unable to convert (not necessarily error), or a new vp_tmpl_t.
2610 xlat_exp_t *xlat_from_tmpl_attr(TALLOC_CTX *ctx, vp_tmpl_t *vpt)
2614 if (vpt->type != TMPL_TYPE_ATTR) return NULL;
2616 node = talloc_zero(ctx, xlat_exp_t);
2617 node->type = XLAT_ATTRIBUTE;
2618 node->fmt = talloc_bstrndup(node, vpt->name, vpt->len);
2619 tmpl_init(&node->attr, TMPL_TYPE_ATTR, node->fmt, talloc_array_length(node->fmt) - 1);
2620 memcpy(&node->attr.data, &vpt->data, sizeof(vpt->data));
2625 ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
2627 return xlat_expand(&out, outlen, request, fmt, escape, ctx);
2630 ssize_t radius_xlat_struct(char *out, size_t outlen, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
2632 return xlat_expand_struct(&out, outlen, request, xlat, escape, ctx);
2635 ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
2638 return xlat_expand(out, 0, request, fmt, escape, ctx);
2641 ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
2644 return xlat_expand_struct(out, 0, request, xlat, escape, ctx);