All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
xlat.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: e4d9329085e75c7006d7c4311a6e5b82913c4fac $
19  *
20  * @file xlat.c
21  * @brief String expansion ("translation"). Implements %Attribute -> value
22  *
23  * @copyright 2000,2006 The FreeRADIUS server project
24  * @copyright 2000 Alan DeKok <aland@ox.org>
25  */
26 
27 RCSID("$Id: e4d9329085e75c7006d7c4311a6e5b82913c4fac $")
28 
29 #include <freeradius-devel/radiusd.h>
30 #include <freeradius-devel/parser.h>
31 #include <freeradius-devel/rad_assert.h>
32 #include <freeradius-devel/base64.h>
33 
34 #include <ctype.h>
35 
36 typedef struct xlat_t {
37  char name[MAX_STRING_LEN]; //!< Name of the xlat expansion.
38  int length; //!< Length of name.
39  void *mod_inst; //!< 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  xlat_instantiate_t instantiate; //!< Instantiation function.
43  size_t inst_size; //!< Length of instance data to pre-allocate.
44  size_t buf_len; //!< Length of output buffer to pre-allocate.
45  bool internal; //!< If true, cannot be redefined.
46 } xlat_t;
47 
48 typedef enum {
49  XLAT_LITERAL, //!< Literal string
50  XLAT_PERCENT, //!< Literal string with %v
51  XLAT_MODULE, //!< xlat module
52  XLAT_VIRTUAL, //!< virtual attribute
53  XLAT_ATTRIBUTE, //!< xlat attribute
54 #ifdef HAVE_REGEX
55  XLAT_REGEX, //!< regex reference
56 #endif
57  XLAT_ALTERNATE //!< xlat conditional syntax :-
58 } xlat_state_t;
59 
60 struct xlat_exp {
61  char const *fmt; //!< The format string.
62  size_t len; //!< Length of the format string.
63 
64  xlat_state_t type; //!< type of this expansion.
65  xlat_exp_t *next; //!< Next in the list.
66 
67  xlat_exp_t *child; //!< Nested expansion.
68  xlat_exp_t *alternate; //!< Alternative expansion if this one expanded to a zero length string.
69 
70  vp_tmpl_t attr; //!< An attribute template.
71  xlat_t const *xlat; //!< The xlat expansion to expand format with.
72 };
73 
74 typedef struct xlat_out {
75  char const *out; //!< Output data.
76  size_t len; //!< Length of the output string.
77 } xlat_out_t;
78 
79 static rbtree_t *xlat_root = NULL;
80 
81 #ifdef WITH_UNLANG
82 static char const * const xlat_foreach_names[] = {"Foreach-Variable-0",
83  "Foreach-Variable-1",
84  "Foreach-Variable-2",
85  "Foreach-Variable-3",
86  "Foreach-Variable-4",
87  "Foreach-Variable-5",
88  "Foreach-Variable-6",
89  "Foreach-Variable-7",
90  "Foreach-Variable-8",
91  "Foreach-Variable-9",
92  NULL};
93 #endif
94 
95 
96 static int xlat_foreach_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; /* up to 10 for foreach */
97 
98 /** Print length of its RHS.
99  *
100  */
101 static ssize_t xlat_strlen(char **out, size_t outlen,
102  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
103  UNUSED REQUEST *request, char const *fmt)
104 {
105  snprintf(*out, outlen, "%u", (unsigned int) strlen(fmt));
106  return strlen(*out);
107 }
108 
109 /** Print the size of the attribute in bytes.
110  *
111  */
112 static ssize_t xlat_length(char **out, size_t outlen,
113  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
114  REQUEST *request, char const *fmt)
115 {
116  VALUE_PAIR *vp;
117 
118  while (isspace((int) *fmt)) fmt++;
119 
120  if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) return 0;
121 
122  snprintf(*out, outlen, "%zu", vp->vp_length);
123  return strlen(*out);
124 }
125 
126 /** Print data as integer, not as VALUE.
127  *
128  */
129 static ssize_t xlat_integer(char **out, size_t outlen,
130  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
131  REQUEST *request, char const *fmt)
132 {
133  VALUE_PAIR *vp;
134 
135  uint64_t int64 = 0; /* Needs to be initialised to zero */
136  uint32_t int32 = 0; /* Needs to be initialised to zero */
137 
138  while (isspace((int) *fmt)) fmt++;
139 
140  if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) return 0;
141 
142  switch (vp->da->type) {
143  case PW_TYPE_OCTETS:
144  case PW_TYPE_STRING:
145  if (vp->vp_length > 8) {
146  break;
147  }
148 
149  if (vp->vp_length > 4) {
150  memcpy(&int64, vp->vp_octets, vp->vp_length);
151  return snprintf(*out, outlen, "%" PRIu64, htonll(int64));
152  }
153 
154  memcpy(&int32, vp->vp_octets, vp->vp_length);
155  return snprintf(*out, outlen, "%i", htonl(int32));
156 
157  case PW_TYPE_INTEGER64:
158  return snprintf(*out, outlen, "%" PRIu64, vp->vp_integer64);
159 
160  /*
161  * IP addresses are treated specially, as parsing functions assume the value
162  * is bigendian and will convert it for us.
163  */
164  case PW_TYPE_IPV4_ADDR:
165  return snprintf(*out, outlen, "%u", htonl(vp->vp_ipaddr));
166 
167  case PW_TYPE_IPV4_PREFIX:
168  return snprintf(*out, outlen, "%u", htonl((*(uint32_t *)(vp->vp_ipv4prefix + 2))));
169 
170  case PW_TYPE_INTEGER:
171  return snprintf(*out, outlen, "%u", vp->vp_integer);
172 
173  case PW_TYPE_DATE:
174  return snprintf(*out, outlen, "%u", vp->vp_date);
175 
176  case PW_TYPE_BYTE:
177  return snprintf(*out, outlen, "%u", (unsigned int) vp->vp_byte);
178 
179  case PW_TYPE_SHORT:
180  return snprintf(*out, outlen, "%u", (unsigned int) vp->vp_short);
181 
182  /*
183  * Ethernet is weird... It's network related, so we assume to it should be
184  * bigendian.
185  */
186  case PW_TYPE_ETHERNET:
187  memcpy(&int64, vp->vp_ether, vp->vp_length);
188  return snprintf(*out, outlen, "%" PRIu64, htonll(int64));
189 
190  case PW_TYPE_SIGNED:
191  return snprintf(*out, outlen, "%i", vp->vp_signed);
192 
193  case PW_TYPE_IPV6_ADDR:
194  return fr_snprint_uint128(*out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6addr));
195 
196  case PW_TYPE_IPV6_PREFIX:
197  return fr_snprint_uint128(*out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6prefix[2]));
198 
199  default:
200  break;
201  }
202 
203  REDEBUG("Type '%s' of length %zu cannot be converted to integer",
204  fr_int2str(dict_attr_types, vp->da->type, "???"), vp->vp_length);
205 
206  return -1;
207 }
208 
209 /** Print data as hex, not as VALUE.
210  *
211  */
212 static ssize_t xlat_hex(char **out, size_t outlen,
213  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
214  REQUEST *request, char const *fmt)
215 {
216  size_t i;
217  VALUE_PAIR *vp;
218  uint8_t const *p;
219  size_t len;
220  value_data_t dst;
221  uint8_t const *buff = NULL;
222 
223  while (isspace((int) *fmt)) fmt++;
224 
225  if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
226  error:
227  return -1;
228  }
229 
230  /*
231  * The easy case.
232  */
233  if (vp->da->type == PW_TYPE_OCTETS) {
234  p = vp->vp_octets;
235  len = vp->vp_length;
236  /*
237  * Cast the value_data_t of the VP to an octets string and
238  * print that as hex.
239  */
240  } else {
241  if (value_data_cast(request, &dst, PW_TYPE_OCTETS, NULL, vp->da->type, NULL, &vp->data) < 0) {
242  REDEBUG("%s", fr_strerror());
243  goto error;
244  }
245  len = (size_t)dst.length;
246  p = buff = dst.octets;
247  }
248 
249  rad_assert(p);
250 
251  /*
252  * Don't truncate the data.
253  */
254  if (outlen < (len * 2)) {
255  rad_const_free(buff);
256  goto error;
257  }
258 
259  for (i = 0; i < len; i++) {
260  snprintf((*out) + (2 * i), 3, "%02x", p[i]);
261  }
262  rad_const_free(buff);
263 
264  return len * 2;
265 }
266 
267 /** Return the tag of an attribute reference
268  *
269  */
270 static ssize_t xlat_tag(char **out, size_t outlen,
271  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
272  REQUEST *request, char const *fmt)
273 {
274  VALUE_PAIR *vp;
275 
276  while (isspace((int) *fmt)) fmt++;
277 
278  if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) return 0;
279 
280  if (!vp->da->flags.has_tag || !TAG_VALID(vp->tag)) return 0;
281 
282  return snprintf(*out, outlen, "%u", vp->tag);
283 }
284 
285 /** Return the vendor of an attribute reference
286  *
287  */
288 static ssize_t xlat_vendor(char **out, size_t outlen,
289  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
290  REQUEST *request, char const *fmt)
291 {
292  VALUE_PAIR *vp;
293  fr_dict_vendor_t const *dv;
294 
295  while (isspace((int) *fmt)) fmt++;
296 
297  if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) return 0;
298 
299  dv = fr_dict_vendor_by_num(NULL, vp->da->vendor);
300  if (!dv) return 0;
301  strlcpy(*out, dv->name, outlen);
302 
303  return dv->length;
304 }
305 
306 /** Return the vendor number of an attribute reference
307  *
308  */
309 static ssize_t xlat_vendor_num(char **out, size_t outlen,
310  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
311  REQUEST *request, char const *fmt)
312 {
313  VALUE_PAIR *vp;
314 
315  while (isspace((int) *fmt)) fmt++;
316 
317  if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) return 0;
318 
319  return snprintf(*out, outlen, "%i", vp->da->vendor);
320 }
321 
322 /** Return the attribute name of an attribute reference
323  *
324  */
325 static ssize_t xlat_attr(char **out, size_t outlen,
326  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
327  REQUEST *request, char const *fmt)
328 {
329  VALUE_PAIR *vp;
330 
331  while (isspace((int) *fmt)) fmt++;
332 
333  if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) return 0;
334  strlcpy(*out, vp->da->name, outlen);
335 
336  return strlen(vp->da->name);
337 }
338 
339 /** Return the attribute number of an attribute reference
340  *
341  */
342 static ssize_t xlat_attr_num(char **out, size_t outlen,
343  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
344  REQUEST *request, char const *fmt)
345 {
346  VALUE_PAIR *vp;
347 
348  while (isspace((int) *fmt)) fmt++;
349 
350  if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) return 0;
351 
352  return snprintf(*out, outlen, "%i", vp->da->attr);
353 }
354 
355 /** Print out attribute info
356  *
357  * Prints out all instances of a current attribute, or all attributes in a list.
358  *
359  * At higher debugging levels, also prints out alternative decodings of the same
360  * value. This is helpful to determine types for unknown attributes of long
361  * passed vendors, or just crazy/broken NAS.
362  *
363  * This expands to a zero length string.
364  */
365 static ssize_t xlat_debug_attr(UNUSED char **out, UNUSED size_t outlen,
366  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
367  REQUEST *request, char const *fmt)
368 {
369  VALUE_PAIR *vp;
370  vp_cursor_t cursor;
371 
372  vp_tmpl_t vpt;
373 
374  if (!RDEBUG_ENABLED2) return -1;
375 
376  while (isspace((int) *fmt)) fmt++;
377 
378  if (tmpl_from_attr_str(&vpt, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
379  RDEBUG("%s", fr_strerror());
380  return -1;
381  }
382 
383  RIDEBUG("Attributes matching \"%s\"", fmt);
384 
385  RINDENT();
386  for (vp = tmpl_cursor_init(NULL, &cursor, request, &vpt);
387  vp;
388  vp = tmpl_cursor_next(&cursor, &vpt)) {
389  FR_NAME_NUMBER const *type;
390  char *value;
391 
392  value = fr_pair_value_asprint(vp, vp, '\'');
393  if (vp->da->flags.has_tag) {
394  RIDEBUG2("&%s:%s:%i %s %s",
395  fr_int2str(pair_lists, vpt.tmpl_list, "<INVALID>"),
396  vp->da->name,
397  vp->tag,
398  fr_int2str(fr_tokens_table, vp->op, "<INVALID>"),
399  value);
400  } else {
401  RIDEBUG2("&%s:%s %s %s",
402  fr_int2str(pair_lists, vpt.tmpl_list, "<INVALID>"),
403  vp->da->name,
404  fr_int2str(fr_tokens_table, vp->op, "<INVALID>"),
405  value);
406  }
407  talloc_free(value);
408 
409  if (!RDEBUG_ENABLED3) continue;
410 
411  if (vp->da->vendor) {
412  fr_dict_vendor_t const *dv;
413 
414  dv = fr_dict_vendor_by_num(NULL, vp->da->vendor);
415  RIDEBUG2("Vendor : %i (%s)", vp->da->vendor, dv ? dv->name : "unknown");
416  }
417  RIDEBUG2("Type : %s", fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"));
418  RIDEBUG2("Length : %zu", vp->vp_length);
419 
420  if (!RDEBUG_ENABLED4) continue;
421 
422  type = dict_attr_types;
423  while (type->name) {
424  int pad;
425 
426  value_data_t *dst = NULL;
427 
428  if ((PW_TYPE) type->number == vp->da->type) {
429  goto next_type;
430  }
431 
432  switch (type->number) {
433  case PW_TYPE_INVALID: /* Not real type */
434  case PW_TYPE_MAX: /* Not real type */
435  case PW_TYPE_EXTENDED: /* Not safe/appropriate */
436  case PW_TYPE_LONG_EXTENDED: /* Not safe/appropriate */
437  case PW_TYPE_TLV: /* Not safe/appropriate */
438  case PW_TYPE_EVS: /* Not safe/appropriate */
439  case PW_TYPE_VSA: /* @fixme We need special behaviour for these */
440  case PW_TYPE_COMBO_IP_ADDR: /* Covered by IPv4 address IPv6 address */
441  case PW_TYPE_COMBO_IP_PREFIX: /* Covered by IPv4 address IPv6 address */
442  case PW_TYPE_TIMEVAL: /* Not a VALUE_PAIR type */
443  goto next_type;
444 
445  default:
446  break;
447  }
448 
449  dst = talloc_zero(vp, value_data_t);
450  /* We expect some to fail */
451  if (value_data_cast(dst, dst, type->number, NULL, vp->da->type, vp->da, &vp->data) < 0) {
452  goto next_type;
453  }
454 
455  value = value_data_asprint(dst, type->number, NULL, dst, '\'');
456  if (!value) goto next_type;
457 
458  if ((pad = (11 - strlen(type->name))) < 0) {
459  pad = 0;
460  }
461 
462  RINDENT();
463  RDEBUG2("as %s%*s: %s", type->name, pad, " ", value);
464  REXDENT();
465 
466  next_type:
467  talloc_free(dst);
468  type++;
469  }
470  }
471  return 0;
472 }
473 
474 /** Processes fmt as a map string and applies it to the current request
475  *
476  * e.g. "%{map:&User-Name := 'foo'}"
477  *
478  * Allows sets of modifications to be cached and then applied.
479  * Useful for processing generic attributes from LDAP.
480  */
481 static ssize_t xlat_map(char **out, size_t outlen,
482  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
483  REQUEST *request, char const *fmt)
484 {
485  vp_map_t *map = NULL;
486  int ret;
487 
488  if (map_afrom_attr_str(request, &map, fmt,
491  REDEBUG("Failed parsing \"%s\" as map: %s", fmt, fr_strerror());
492  return -1;
493  }
494 
495  RINDENT();
496  ret = map_to_request(request, map, map_to_vp, NULL);
497  REXDENT();
498  talloc_free(map);
499  if (ret < 0) return strlcpy(*out, "0", outlen);
500 
501  return strlcpy(*out, "1", outlen);
502 }
503 
504 /** Prints the current module processing the request
505  *
506  */
507 static ssize_t xlat_module(char **out, size_t outlen,
508  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
509  REQUEST *request, UNUSED char const *fmt)
510 {
511  strlcpy(*out, request->module, outlen);
512 
513  return strlen(*out);
514 }
515 
516 #if defined(HAVE_REGEX) && defined(HAVE_PCRE)
517 static ssize_t xlat_regex(char **out, size_t outlen,
518  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
519  REQUEST *request, char const *fmt)
520 {
521  char *p;
522  size_t len;
523 
524  if (regex_request_to_sub_named(request, &p, request, fmt) < 0) return 0;
525 
526  len = talloc_array_length(p);
527  if (len > outlen) {
528  RDEBUG("Insufficient buffer space to write subcapture value, needed %zu bytes, have %zu bytes",
529  len, outlen);
530  return -1;
531  }
532  strlcpy(*out, p, outlen);
533 
534  return len - 1; /* - \0 */
535 }
536 #endif
537 
538 #ifdef WITH_UNLANG
539 /** Implements the Foreach-Variable-X
540  *
541  * @see modcall()
542  */
543 static ssize_t xlat_foreach(char **out, size_t outlen,
544  void const *mod_inst, UNUSED void const *xlat_inst,
545  REQUEST *request, UNUSED char const *fmt)
546 {
547  VALUE_PAIR **pvp;
548  size_t len;
549 
550  /*
551  * See modcall, "FOREACH" for how this works.
552  */
553  pvp = (VALUE_PAIR **) request_data_reference(request, (void *)radius_get_vp, *(int const *) mod_inst);
554  if (!pvp || !*pvp) return 0;
555 
556  len = fr_pair_value_snprint(*out, outlen, *pvp, 0);
557  if (is_truncated(len, outlen)) {
558  RDEBUG("Insufficient buffer space to write foreach value");
559  return -1;
560  }
561 
562  return len;
563 }
564 #endif
565 
566 /** Print data as string, if possible.
567  *
568  * If attribute "Foo" is defined as "octets" it will normally
569  * be printed as 0x0a0a0a. The xlat "%{string:Foo}" will instead
570  * expand to "\n\n\n"
571  */
572 static ssize_t xlat_string(char **out, size_t outlen,
573  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
574  REQUEST *request, char const *fmt)
575 {
576  size_t len;
577  ssize_t ret;
578  VALUE_PAIR *vp;
579  uint8_t const *p;
580 
581  while (isspace((int) *fmt)) fmt++;
582 
583  if (outlen < 3) {
584  nothing:
585  return 0;
586  }
587 
588  if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
589 
590  ret = fr_radius_encode_value_hton(&p, vp);
591  if (ret < 0) {
592  return ret;
593  }
594 
595  switch (vp->da->type) {
596  case PW_TYPE_OCTETS:
597  len = fr_snprint(*out, outlen, (char const *) p, vp->vp_length, '"');
598  break;
599 
600  /*
601  * Note that "%{string:...}" is NOT binary safe!
602  * It is explicitly used to get rid of embedded zeros.
603  */
604  case PW_TYPE_STRING:
605  len = strlcpy(*out, vp->vp_strvalue, outlen);
606  break;
607 
608  default:
609  len = fr_snprint(*out, outlen, (char const *) p, ret, '\0');
610  break;
611  }
612 
613  return len;
614 }
615 
616 /** xlat expand string attribute value
617  *
618  */
619 static ssize_t xlat_xlat(char **out, size_t outlen,
620  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
621  REQUEST *request, char const *fmt)
622 {
623  VALUE_PAIR *vp;
624 
625  while (isspace((int) *fmt)) fmt++;
626 
627  if (outlen < 3) {
628  nothing:
629  return 0;
630  }
631 
632  if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
633 
634  return radius_xlat(*out, outlen, request, vp->vp_strvalue, NULL, NULL);
635 }
636 
637 /** Dynamically change the debugging level for the current request
638  *
639  * Example %{debug:3}
640  */
641 static ssize_t xlat_debug(char **out, size_t outlen,
642  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
643  REQUEST *request, char const *fmt)
644 {
645  int level = 0;
646 
647  /*
648  * Expand to previous (or current) level
649  */
650  snprintf(*out, outlen, "%d", request->log.lvl);
651 
652  /*
653  * Assume we just want to get the current value and NOT set it to 0
654  */
655  if (!*fmt)
656  goto done;
657 
658  level = atoi(fmt);
659  if (level == 0) {
660  request->log.lvl = RAD_REQUEST_LVL_NONE;
661  request->log.func = NULL;
662  } else {
663  if (level > 4) level = 4;
664 
665  request->log.lvl = level;
666  request->log.func = vradlog_request;
667  }
668 
669  done:
670  return strlen(*out);
671 }
672 
673 /*
674  * Compare two xlat_t structs, based ONLY on the module name.
675  */
676 static int xlat_cmp(void const *one, void const *two)
677 {
678  xlat_t const *a = one;
679  xlat_t const *b = two;
680 
681  if (a->length != b->length) {
682  return a->length - b->length;
683  }
684 
685  return memcmp(a->name, b->name, a->length);
686 }
687 
688 
689 /*
690  * find the appropriate registered xlat function.
691  */
692 static xlat_t *xlat_find(char const *name)
693 {
694  xlat_t my_xlat;
695 
696  strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
697  my_xlat.length = strlen(my_xlat.name);
698 
699  return rbtree_finddata(xlat_root, &my_xlat);
700 }
701 
702 
703 /** Register an xlat function.
704  *
705  * @param[in] mod_inst Instance of module that's registering the xlat function.
706  * @param[in] name xlat name.
707  * @param[in] func xlat function to be called.
708  * @param[in] escape function to sanitize any sub expansions passed to the xlat function.
709  * @param[in] instantiate function to pre-parse any xlat specific data.
710  * @param[in] inst_size sizeof() this xlat's instance data.
711  * @param[in] buf_len Size of the output buffer to allocate when calling the function.
712  * May be 0 if the function allocates its own buffer.
713  * @return
714  * - 0 on success.
715  * - -1 on failure.
716  */
717 int xlat_register(void *mod_inst, char const *name,
718  xlat_func_t func, xlat_escape_t escape,
719  xlat_instantiate_t instantiate, size_t inst_size,
720  size_t buf_len)
721 {
722  xlat_t *c;
723  xlat_t my_xlat;
724  rbnode_t *node;
725 
726  if (!name || !*name) {
727  DEBUG("xlat_register: Invalid xlat name");
728  return -1;
729  }
730 
731  /*
732  * First time around, build up the tree...
733  *
734  * FIXME: This code should be hoisted out of this function,
735  * and into a global "initialization". But it isn't critical...
736  */
737  if (!xlat_root) {
738 #ifdef WITH_UNLANG
739  int i;
740 #endif
741 
742  xlat_root = rbtree_create(NULL, xlat_cmp, NULL, RBTREE_FLAG_REPLACE);
743  if (!xlat_root) {
744  DEBUG("xlat_register: Failed to create tree");
745  return -1;
746  }
747 
748 #ifdef WITH_UNLANG
749  for (i = 0; xlat_foreach_names[i] != NULL; i++) {
750  xlat_register(&xlat_foreach_inst[i], xlat_foreach_names[i], xlat_foreach, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
751  c = xlat_find(xlat_foreach_names[i]);
752  rad_assert(c != NULL);
753  c->internal = true;
754  }
755 #endif
756 
757 #define XLAT_REGISTER(_x) xlat_register(NULL, STRINGIFY(_x), xlat_ ## _x, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN); \
758  c = xlat_find(STRINGIFY(_x)); \
759  rad_assert(c != NULL); \
760  c->internal = true
761 
762  XLAT_REGISTER(integer);
763  XLAT_REGISTER(strlen);
766  XLAT_REGISTER(tag);
767  XLAT_REGISTER(vendor);
768  XLAT_REGISTER(vendor_num);
769  XLAT_REGISTER(attr);
770  XLAT_REGISTER(attr_num);
771  XLAT_REGISTER(string);
772  XLAT_REGISTER(xlat);
774  XLAT_REGISTER(module);
775  XLAT_REGISTER(debug_attr);
776 #if defined(HAVE_REGEX) && defined(HAVE_PCRE)
777  XLAT_REGISTER(regex);
778 #endif
779 
780  xlat_register(&xlat_foreach_inst[0], "debug", xlat_debug, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
781  c = xlat_find("debug");
782  rad_assert(c != NULL);
783  c->internal = true;
784  }
785 
786  /*
787  * If it already exists, replace the instance.
788  */
789  strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
790  my_xlat.length = strlen(my_xlat.name);
791  c = rbtree_finddata(xlat_root, &my_xlat);
792  if (c) {
793  if (c->internal) {
794  DEBUG("xlat_register: Cannot re-define internal xlat");
795  return -1;
796  }
797 
798  c->func = func;
799  c->buf_len = buf_len;
800  c->escape = escape;
801  c->mod_inst = mod_inst;
802  c->instantiate = instantiate;
803  c->inst_size = inst_size;
804  return 0;
805  }
806 
807  /*
808  * Doesn't exist. Create it.
809  */
810  c = talloc_zero(xlat_root, xlat_t);
811 
812  c->func = func;
813  c->buf_len = buf_len;
814  c->escape = escape;
815  strlcpy(c->name, name, sizeof(c->name));
816  c->length = strlen(c->name);
817  c->mod_inst = mod_inst;
818  c->instantiate = instantiate;
819  c->inst_size = inst_size;
820 
821  DEBUG3("xlat_register: %s", c->name);
822 
823  node = rbtree_insert_node(xlat_root, c);
824  if (!node) {
825  talloc_free(c);
826  return -1;
827  }
828 
829  /*
830  * Ensure that the data is deleted when the node is
831  * deleted.
832  *
833  * @todo: Maybe this should be the other way around...
834  * when a thing IN the tree is deleted, it's automatically
835  * removed from the tree. But for now, this works.
836  */
837  (void) talloc_steal(node, c);
838  return 0;
839 }
840 
841 /** Unregister an xlat function
842  *
843  * We can only have one function to call per name, so the passing of "func"
844  * here is extraneous.
845  *
846  * @param[in] mod_inst data.
847  * @param[in] name xlat to unregister.
848  * @param[in] func unused.
849  */
850 void xlat_unregister(void *mod_inst, char const *name, UNUSED xlat_func_t func)
851 {
852  xlat_t *c;
853  xlat_t my_xlat;
854 
855  if (!name || !xlat_root) return;
856 
857  strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
858  my_xlat.length = strlen(my_xlat.name);
859 
860  c = rbtree_finddata(xlat_root, &my_xlat);
861  if (!c) return;
862 
863  if (c->mod_inst != mod_inst) return;
864 
865  rbtree_deletebydata(xlat_root, c);
866 }
867 
868 static int xlat_unregister_callback(void *mod_inst, void *data)
869 {
870  xlat_t *c = (xlat_t *) data;
871 
872  if (c->mod_inst != mod_inst) return 0; /* keep walking */
873 
874  return 2; /* delete it */
875 }
876 
877 void xlat_unregister_module(void *instance)
878 {
880 }
881 
882 /*
883  * Internal redundant handler for xlats
884  */
885 typedef enum xlat_redundant_type_t {
891 
892 typedef struct xlat_redundant_t {
894  uint32_t count;
897 
898 
899 static ssize_t xlat_redundant(char **out, size_t outlen,
900  void const *mod_inst, UNUSED void const *xlat_inst,
901  REQUEST *request, char const *fmt)
902 {
903  xlat_redundant_t const *xr = mod_inst;
904  CONF_ITEM *ci;
905  char const *name;
906  xlat_t *xlat;
907 
908  rad_assert((*out == NULL) && (outlen == 0)); /* Caller must not have allocated buf */
910 
911  /*
912  * Pick the first xlat which succeeds
913  */
914  for (ci = cf_item_find_next(xr->cs, NULL);
915  ci != NULL;
916  ci = cf_item_find_next(xr->cs, ci)) {
917  ssize_t rcode;
918 
919  if (!cf_item_is_pair(ci)) continue;
920 
921  name = cf_pair_attr(cf_item_to_pair(ci));
922  rad_assert(name != NULL);
923 
924  xlat = xlat_find(name);
925  if (!xlat) continue;
926 
927  if (xlat->buf_len > 0) {
928  *out = talloc_array(request, char, xlat->buf_len);
929  **out = '\0'; /* Be sure the string is \0 terminated */
930  } else {
931  *out = NULL;
932  }
933 
934  rcode = xlat->func(out, xlat->buf_len, xlat->mod_inst, NULL, request, fmt);
935  if (rcode <= 0) {
936  TALLOC_FREE(*out);
937  continue;
938  }
939  return rcode;
940  }
941 
942  /*
943  * Everything failed. Oh well.
944  */
945  *out = NULL;
946  return 0;
947 }
948 
949 
950 static ssize_t xlat_load_balance(char **out, size_t outlen,
951  void const *mod_inst, UNUSED void const *xlat_inst,
952  REQUEST *request, char const *fmt)
953 {
954  uint32_t count = 0;
955  xlat_redundant_t const *xr = mod_inst;
956  CONF_ITEM *ci;
957  CONF_ITEM *found = NULL;
958  char const *name;
959  xlat_t *xlat;
960 
961  rad_assert((*out == NULL) && (outlen == 0)); /* Caller must not have allocated buf */
962 
963  /*
964  * Choose a child at random.
965  */
966  for (ci = cf_item_find_next(xr->cs, NULL);
967  ci != NULL;
968  ci = cf_item_find_next(xr->cs, ci)) {
969  if (!cf_item_is_pair(ci)) continue;
970  count++;
971 
972  /*
973  * Replace the previously found one with a random
974  * new one.
975  */
976  if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
977  found = ci;
978  }
979  }
980 
981  /*
982  * Plain load balancing: do one child, and only one child.
983  */
984  if (xr->type == XLAT_LOAD_BALANCE) {
985  ssize_t slen;
986  name = cf_pair_attr(cf_item_to_pair(found));
987  rad_assert(name != NULL);
988 
989  xlat = xlat_find(name);
990  if (!xlat) return -1;
991 
992  if (xlat->buf_len > 0) {
993  *out = talloc_array(request, char, xlat->buf_len);
994  **out = '\0'; /* Be sure the string is \0 terminated */
995  } else {
996  *out = NULL;
997  }
998  slen = xlat->func(out, xlat->buf_len, xlat->mod_inst, NULL, request, fmt);
999  if (slen <= 0) TALLOC_FREE(*out);
1000 
1001  return slen;
1002  }
1003 
1005 
1006  /*
1007  * Try the random one we found. If it fails, keep going
1008  * through the rest of the children.
1009  */
1010  ci = found;
1011  do {
1012  name = cf_pair_attr(cf_item_to_pair(ci));
1013  rad_assert(name != NULL);
1014 
1015  xlat = xlat_find(name);
1016  if (xlat) {
1017  ssize_t rcode;
1018 
1019  if (xlat->buf_len > 0) {
1020  *out = talloc_array(request, char, xlat->buf_len);
1021  **out = '\0'; /* Be sure the string is \0 terminated */
1022  } else {
1023  *out = NULL;
1024  }
1025  rcode = xlat->func(out, xlat->buf_len, xlat->mod_inst, NULL, request, fmt);
1026  if (rcode > 0) return rcode;
1027  TALLOC_FREE(*out);
1028  }
1029 
1030  /*
1031  * Go to the next one, wrapping around at the end.
1032  */
1033  ci = cf_item_find_next(xr->cs, ci);
1034  if (!ci) ci = cf_item_find_next(xr->cs, NULL);
1035  } while (ci != found);
1036 
1037  return -1;
1038 }
1039 
1040 
1042 {
1043  char const *name1, *name2;
1044  xlat_redundant_t *xr;
1045 
1046  name1 = cf_section_name1(cs);
1047  name2 = cf_section_name2(cs);
1048 
1049  if (xlat_find(name2)) {
1050  cf_log_err_cs(cs, "An expansion is already registered for this name");
1051  return false;
1052  }
1053 
1054  xr = talloc_zero(cs, xlat_redundant_t);
1055  if (!xr) return false;
1056 
1057  if (strcmp(name1, "redundant") == 0) {
1058  xr->type = XLAT_REDUNDANT;
1059 
1060  } else if (strcmp(name1, "redundant-load-balance") == 0) {
1062 
1063  } else if (strcmp(name1, "load-balance") == 0) {
1064  xr->type = XLAT_LOAD_BALANCE;
1065 
1066  } else {
1067  return false;
1068  }
1069 
1070  xr->cs = cs;
1071 
1072  /*
1073  * Get the number of children for load balancing.
1074  */
1075  if (xr->type == XLAT_REDUNDANT) {
1076  if (xlat_register(xr, name2, xlat_redundant, NULL, NULL, 0, 0) < 0) {
1077  talloc_free(xr);
1078  return false;
1079  }
1080 
1081  } else {
1082  CONF_ITEM *ci;
1083 
1084  for (ci = cf_item_find_next(cs, NULL);
1085  ci != NULL;
1086  ci = cf_item_find_next(cs, ci)) {
1087  if (!cf_item_is_pair(ci)) continue;
1088 
1089  if (!xlat_find(cf_pair_attr(cf_item_to_pair(ci)))) {
1090  talloc_free(xr);
1091  return false;
1092  }
1093 
1094  xr->count++;
1095  }
1096 
1097  if (xlat_register(xr, name2, xlat_load_balance, NULL, NULL, 0, 0) < 0) {
1098  talloc_free(xr);
1099  return false;
1100  }
1101  }
1102 
1103  return true;
1104 }
1105 
1106 
1107 /** Crappy temporary function to add attribute ref support to xlats
1108  *
1109  * This needs to die, and hopefully will die, when xlat functions accept
1110  * xlat node structures.
1111  *
1112  * Provides either a pointer to a buffer which contains the value of the reference VALUE_PAIR
1113  * in an architecture independent format. Or a pointer to the start of the fmt string.
1114  *
1115  * The pointer is only guaranteed to be valid between calls to xlat_fmt_to_ref,
1116  * and so long as the source VALUE_PAIR is not freed.
1117  *
1118  * @param out where to write a pointer to the buffer to the data the xlat function needs to work on.
1119  * @param request current request.
1120  * @param fmt string.
1121  * @returns
1122  * - The length of the data.
1123  * - -1 on failure.
1124  */
1125 ssize_t xlat_fmt_to_ref(uint8_t const **out, REQUEST *request, char const *fmt)
1126 {
1127  VALUE_PAIR *vp;
1128 
1129  while (isspace((int) *fmt)) fmt++;
1130 
1131  if (fmt[0] == '&') {
1132  if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
1133  *out = NULL;
1134  return -1;
1135  }
1136 
1137  return fr_radius_encode_value_hton(out, vp);
1138  }
1139 
1140  *out = (uint8_t const *)fmt;
1141  return strlen(fmt);
1142 }
1143 
1144 /** De-register all xlat functions, used mainly for debugging.
1145  *
1146  */
1147 void xlat_free(void)
1148 {
1149  rbtree_free(xlat_root);
1150 }
1151 
1152 #ifdef DEBUG_XLAT
1153 # define XLAT_DEBUG DEBUG3
1154 #else
1155 # define XLAT_DEBUG(...)
1156 #endif
1157 
1158 static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1159  char const **error);
1160 static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1161  bool brace, char const **error);
1162 static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const * const head,
1163  xlat_escape_t escape, void *escape_ctx);
1164 
1165 static ssize_t xlat_tokenize_alternation(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1166  char const **error)
1167 {
1168  ssize_t slen;
1169  char *p;
1170  xlat_exp_t *node;
1171 
1172  rad_assert(fmt[0] == '%');
1173  rad_assert(fmt[1] == '{');
1174  rad_assert(fmt[2] == '%');
1175  rad_assert(fmt[3] == '{');
1176 
1177  XLAT_DEBUG("ALTERNATE <-- %s", fmt);
1178 
1179  node = talloc_zero(ctx, xlat_exp_t);
1180  node->type = XLAT_ALTERNATE;
1181 
1182  p = fmt + 2;
1183  slen = xlat_tokenize_expansion(node, p, &node->child, error);
1184  if (slen <= 0) {
1185  talloc_free(node);
1186  return slen - (p - fmt);
1187  }
1188  p += slen;
1189 
1190  if (p[0] != ':') {
1191  talloc_free(node);
1192  *error = "Expected ':' after first expansion";
1193  return -(p - fmt);
1194  }
1195  p++;
1196 
1197  if (p[0] != '-') {
1198  talloc_free(node);
1199  *error = "Expected '-' after ':'";
1200  return -(p - fmt);
1201  }
1202  p++;
1203 
1204  /*
1205  * Allow the RHS to be empty as a special case.
1206  */
1207  if (*p == '}') {
1208  /*
1209  * Hack up an empty string.
1210  */
1211  node->alternate = talloc_zero(node, xlat_exp_t);
1212  node->alternate->type = XLAT_LITERAL;
1213  node->alternate->fmt = talloc_typed_strdup(node->alternate, "");
1214  *(p++) = '\0';
1215 
1216  } else {
1217  slen = xlat_tokenize_literal(node, p, &node->alternate, true, error);
1218  if (slen <= 0) {
1219  talloc_free(node);
1220  return slen - (p - fmt);
1221  }
1222 
1223  if (!node->alternate) {
1224  talloc_free(node);
1225  *error = "Empty expansion is invalid";
1226  return -(p - fmt);
1227  }
1228  p += slen;
1229  }
1230 
1231  *head = node;
1232  return p - fmt;
1233 }
1234 
1235 static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1236  char const **error)
1237 {
1238  ssize_t slen;
1239  char *p, *q;
1240  xlat_exp_t *node;
1241  long num;
1242 
1243  rad_assert(fmt[0] == '%');
1244  rad_assert(fmt[1] == '{');
1245 
1246  /*
1247  * %{%{...}:-bar}
1248  */
1249  if ((fmt[2] == '%') && (fmt[3] == '{')) return xlat_tokenize_alternation(ctx, fmt, head, error);
1250 
1251  XLAT_DEBUG("EXPANSION <-- %s", fmt);
1252  node = talloc_zero(ctx, xlat_exp_t);
1253  node->fmt = fmt + 2;
1254  node->len = 0;
1255 
1256 #ifdef HAVE_REGEX
1257  /*
1258  * Handle regex's specially.
1259  */
1260  p = fmt + 2;
1261  num = strtol(p, &q, 10);
1262  if (p != q && (*q == '}')) {
1263  XLAT_DEBUG("REGEX <-- %s", fmt);
1264  *q = '\0';
1265 
1266  if ((num > REQUEST_MAX_REGEX) || (num < 0)) {
1267  talloc_free(node);
1268  *error = "Invalid regex reference. Must be in range 0-" STRINGIFY(REQUEST_MAX_REGEX);
1269  return -2;
1270  }
1271  node->attr.tmpl_num = num;
1272 
1273  node->type = XLAT_REGEX;
1274  *head = node;
1275 
1276  return (q - fmt) + 1;
1277  }
1278 #endif /* HAVE_REGEX */
1279 
1280  /*
1281  * %{Attr-Name}
1282  * %{Attr-Name[#]}
1283  * %{Tunnel-Password:1}
1284  * %{Tunnel-Password:1[#]}
1285  * %{request:Attr-Name}
1286  * %{request:Tunnel-Password:1}
1287  * %{request:Tunnel-Password:1[#]}
1288  * %{mod:foo}
1289  */
1290 
1291  /*
1292  * This is for efficiency, so we don't search for an xlat,
1293  * when what's being referenced is obviously an attribute.
1294  */
1295  p = fmt + 2;
1296  for (q = p; *q != '\0'; q++) {
1297  if (*q == ':') break;
1298 
1299  if (isspace((int) *q)) break;
1300 
1301  if (*q == '[') continue;
1302 
1303  if (*q == '}') break;
1304  }
1305 
1306  /*
1307  * Check for empty expressions %{}
1308  */
1309  if ((*q == '}') && (q == p)) {
1310  talloc_free(node);
1311  *error = "Empty expression is invalid";
1312  return -(p - fmt);
1313  }
1314 
1315  /*
1316  * Might be a module name reference.
1317  *
1318  * If it's not, it's an attribute or parse error.
1319  */
1320  if (*q == ':') {
1321  *q = '\0';
1322  node->xlat = xlat_find(node->fmt);
1323  if (node->xlat) {
1324  /*
1325  * %{mod:foo}
1326  */
1327  node->type = XLAT_MODULE;
1328 
1329  p = q + 1;
1330  XLAT_DEBUG("MOD <-- %s ... %s", node->fmt, p);
1331 
1332  slen = xlat_tokenize_literal(node, p, &node->child, true, error);
1333  if (slen < 0) {
1334  talloc_free(node);
1335  return slen - (p - fmt);
1336  }
1337  p += slen;
1338 
1339  *head = node;
1340  rad_assert(node->next == NULL);
1341 
1342  return p - fmt;
1343  }
1344  *q = ':'; /* Avoids a strdup */
1345  }
1346 
1347  /*
1348  * The first token ends with:
1349  * - '[' - Which is an attribute index, so it must be an attribute.
1350  * - '}' - The end of the expansion, which means it was a bareword.
1351  */
1352  slen = tmpl_from_attr_substr(&node->attr, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, true, true);
1353  if (slen <= 0) {
1354  /*
1355  * If the parse error occurred before the ':'
1356  * then the error is changed to 'Unknown module',
1357  * as it was more likely to be a bad module name,
1358  * than a request qualifier.
1359  */
1360  if ((*q == ':') && ((p + (slen * -1)) < q)) {
1361  *error = "Unknown module";
1362  } else {
1363  *error = fr_strerror();
1364  }
1365 
1366  talloc_free(node);
1367  return slen - (p - fmt);
1368  }
1369 
1370  /*
1371  * Might be a virtual XLAT attribute
1372  */
1373  if (node->attr.type == TMPL_TYPE_ATTR_UNDEFINED) {
1374  node->xlat = xlat_find(node->attr.tmpl_unknown_name);
1375  if (node->xlat && node->xlat->mod_inst && !node->xlat->internal) {
1376  talloc_free(node);
1377  *error = "Missing content in expansion";
1378  return -(p - fmt) - slen;
1379  }
1380 
1381  if (node->xlat) {
1382  node->type = XLAT_VIRTUAL;
1383  node->fmt = node->attr.tmpl_unknown_name;
1384 
1385  XLAT_DEBUG("VIRTUAL <-- %s", node->fmt);
1386  *head = node;
1387  rad_assert(node->next == NULL);
1388  q++;
1389  return q - fmt;
1390  }
1391 
1392  talloc_free(node);
1393  *error = "Unknown attribute";
1394  return -(p - fmt);
1395  }
1396 
1397  node->type = XLAT_ATTRIBUTE;
1398  p += slen;
1399 
1400  if (*p != '}') {
1401  talloc_free(node);
1402  *error = "No matching closing brace";
1403  return -1; /* second character of format string */
1404  }
1405  *p++ = '\0';
1406  *head = node;
1407  rad_assert(node->next == NULL);
1408 
1409  return p - fmt;
1410 }
1411 
1412 
1413 static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1414  bool brace, char const **error)
1415 {
1416  char *p;
1417  xlat_exp_t *node;
1418 
1419  if (!*fmt) return 0;
1420 
1421  XLAT_DEBUG("LITERAL <-- %s", fmt);
1422 
1423  node = talloc_zero(ctx, xlat_exp_t);
1424  node->fmt = fmt;
1425  node->len = 0;
1426  node->type = XLAT_LITERAL;
1427 
1428  p = fmt;
1429 
1430  while (*p) {
1431  if (*p == '\\') {
1432  if (!p[1]) {
1433  talloc_free(node);
1434  *error = "Invalid escape at end of string";
1435  return -(p - fmt);
1436  }
1437 
1438  p += 2;
1439  node->len += 2;
1440  continue;
1441  }
1442 
1443  /*
1444  * Process the expansion.
1445  */
1446  if ((p[0] == '%') && (p[1] == '{')) {
1447  ssize_t slen;
1448 
1449  XLAT_DEBUG("EXPANSION-2 <-- %s", node->fmt);
1450 
1451  slen = xlat_tokenize_expansion(node, p, &node->next, error);
1452  if (slen <= 0) {
1453  talloc_free(node);
1454  return slen - (p - fmt);
1455  }
1456  *p = '\0'; /* end the literal */
1457  p += slen;
1458 
1459  rad_assert(node->next != NULL);
1460 
1461  /*
1462  * Short-circuit the recursive call.
1463  * This saves another function call and
1464  * memory allocation.
1465  */
1466  if (!*p) break;
1467 
1468  /*
1469  * "foo %{User-Name} bar"
1470  * LITERAL "foo "
1471  * EXPANSION User-Name
1472  * LITERAL " bar"
1473  */
1474  slen = xlat_tokenize_literal(node->next, p, &(node->next->next), brace, error);
1475  rad_assert(slen != 0);
1476  if (slen < 0) {
1477  talloc_free(node);
1478  return slen - (p - fmt);
1479  }
1480 
1481  brace = false; /* it was found above, or else the above code errored out */
1482  p += slen;
1483  break; /* stop processing the string */
1484  }
1485 
1486  /*
1487  * Check for valid single-character expansions.
1488  */
1489  if (p[0] == '%') {
1490  ssize_t slen;
1491  xlat_exp_t *next;
1492 
1493  if (!p[1] || !strchr("%}dlmntDGHISTYv", p[1])) {
1494  talloc_free(node);
1495  *error = "Invalid variable expansion";
1496  p++;
1497  return - (p - fmt);
1498  }
1499 
1500  next = talloc_zero(node, xlat_exp_t);
1501  next->len = 1;
1502 
1503  switch (p[1]) {
1504  case '%':
1505  case '}':
1506  next->fmt = talloc_strndup(next, p + 1, 1);
1507 
1508  XLAT_DEBUG("LITERAL-ESCAPED <-- %s", next->fmt);
1509  next->type = XLAT_LITERAL;
1510  break;
1511 
1512  default:
1513  next->fmt = p + 1;
1514 
1515  XLAT_DEBUG("PERCENT <-- %c", *next->fmt);
1516  next->type = XLAT_PERCENT;
1517  break;
1518  }
1519 
1520  node->next = next;
1521  *p = '\0';
1522  p += 2;
1523 
1524  if (!*p) break;
1525 
1526  /*
1527  * And recurse.
1528  */
1529  slen = xlat_tokenize_literal(node->next, p, &(node->next->next), brace, error);
1530  rad_assert(slen != 0);
1531  if (slen < 0) {
1532  talloc_free(node);
1533  return slen - (p - fmt);
1534  }
1535 
1536  brace = false; /* it was found above, or else the above code errored out */
1537  p += slen;
1538  break; /* stop processing the string */
1539  }
1540 
1541  /*
1542  * If required, eat the brace.
1543  */
1544  if (brace && (*p == '}')) {
1545  brace = false;
1546  *p = '\0';
1547  p++;
1548  break;
1549  }
1550 
1551  p++;
1552  node->len++;
1553  }
1554 
1555  /*
1556  * We were told to look for a brace, but we ran off of
1557  * the end of the string before we found one.
1558  */
1559  if (brace) {
1560  *error = "Missing closing brace at end of string";
1561  return -(p - fmt);
1562  }
1563 
1564  /*
1565  * Squash zero-width literals
1566  */
1567  if (node->len > 0) {
1568  *head = node;
1569 
1570  } else {
1571  (void) talloc_steal(ctx, node->next);
1572  *head = node->next;
1573  talloc_free(node);
1574  }
1575 
1576  return p - fmt;
1577 }
1578 
1579 
1580 static char const xlat_tabs[] = " ";
1581 
1582 static void xlat_tokenize_debug(xlat_exp_t const *node, int lvl)
1583 {
1584  rad_assert(node != NULL);
1585 
1586  if (lvl >= (int) sizeof(xlat_tabs)) lvl = sizeof(xlat_tabs);
1587 
1588  while (node) {
1589  switch (node->type) {
1590  case XLAT_LITERAL:
1591  DEBUG("%.*sliteral --> %s", lvl, xlat_tabs, node->fmt);
1592  break;
1593 
1594  case XLAT_PERCENT:
1595  DEBUG("%.*spercent --> %c", lvl, xlat_tabs, node->fmt[0]);
1596  break;
1597 
1598  case XLAT_ATTRIBUTE:
1599  rad_assert(node->attr.tmpl_da != NULL);
1600  DEBUG("%.*sattribute --> %s", lvl, xlat_tabs, node->attr.tmpl_da->name);
1601  rad_assert(node->child == NULL);
1602  if ((node->attr.tmpl_tag != TAG_ANY) || (node->attr.tmpl_num != NUM_ANY)) {
1603  DEBUG("%.*s{", lvl, xlat_tabs);
1604 
1605  DEBUG("%.*sref %d", lvl + 1, xlat_tabs, node->attr.tmpl_request);
1606  DEBUG("%.*slist %d", lvl + 1, xlat_tabs, node->attr.tmpl_list);
1607 
1608  if (node->attr.tmpl_tag != TAG_ANY) {
1609  DEBUG("%.*stag %d", lvl + 1, xlat_tabs, node->attr.tmpl_tag);
1610  }
1611  if (node->attr.tmpl_num != NUM_ANY) {
1612  if (node->attr.tmpl_num == NUM_COUNT) {
1613  DEBUG("%.*s[#]", lvl + 1, xlat_tabs);
1614  } else if (node->attr.tmpl_num == NUM_ALL) {
1615  DEBUG("%.*s[*]", lvl + 1, xlat_tabs);
1616  } else {
1617  DEBUG("%.*s[%d]", lvl + 1, xlat_tabs, node->attr.tmpl_num);
1618  }
1619  }
1620 
1621  DEBUG("%.*s}", lvl, xlat_tabs);
1622  }
1623  break;
1624 
1625  case XLAT_VIRTUAL:
1626  rad_assert(node->fmt != NULL);
1627  DEBUG("%.*svirtual --> %s", lvl, xlat_tabs, node->fmt);
1628  break;
1629 
1630  case XLAT_MODULE:
1631  rad_assert(node->xlat != NULL);
1632  DEBUG("%.*sxlat --> %s", lvl, xlat_tabs, node->xlat->name);
1633  if (node->child) {
1634  DEBUG("%.*s{", lvl, xlat_tabs);
1635  xlat_tokenize_debug(node->child, lvl + 1);
1636  DEBUG("%.*s}", lvl, xlat_tabs);
1637  }
1638  break;
1639 
1640 #ifdef HAVE_REGEX
1641  case XLAT_REGEX:
1642  DEBUG("%.*sregex-var --> %d", lvl, xlat_tabs, node->attr.tmpl_num);
1643  break;
1644 #endif
1645 
1646  case XLAT_ALTERNATE:
1647  DEBUG("%.*sif {", lvl, xlat_tabs);
1648  xlat_tokenize_debug(node->child, lvl + 1);
1649  DEBUG("%.*s}", lvl, xlat_tabs);
1650  DEBUG("%.*selse {", lvl, xlat_tabs);
1651  xlat_tokenize_debug(node->alternate, lvl + 1);
1652  DEBUG("%.*s}", lvl, xlat_tabs);
1653  break;
1654  }
1655  node = node->next;
1656  }
1657 }
1658 
1659 size_t xlat_snprint(char *buffer, size_t bufsize, xlat_exp_t const *node)
1660 {
1661  size_t len;
1662  char *p, *end;
1663 
1664  if (!node) {
1665  *buffer = '\0';
1666  return 0;
1667  }
1668 
1669  p = buffer;
1670  end = buffer + bufsize;
1671 
1672  while (node) {
1673  switch (node->type) {
1674  case XLAT_LITERAL:
1675  strlcpy(p, node->fmt, end - p);
1676  p += strlen(p);
1677  break;
1678 
1679  case XLAT_PERCENT:
1680  p[0] = '%';
1681  p[1] = node->fmt[0];
1682  p += 2;
1683  break;
1684 
1685  case XLAT_ATTRIBUTE:
1686  *(p++) = '%';
1687  *(p++) = '{';
1688 
1689  if (node->attr.tmpl_request != REQUEST_CURRENT) {
1690  strlcpy(p, fr_int2str(request_refs, node->attr.tmpl_request, "??"), end - p);
1691  p += strlen(p);
1692  *(p++) = '.';
1693  }
1694 
1695  if ((node->attr.tmpl_request != REQUEST_CURRENT) ||
1696  (node->attr.tmpl_list != PAIR_LIST_REQUEST)) {
1697  strlcpy(p, fr_int2str(pair_lists, node->attr.tmpl_list, "??"), end - p);
1698  p += strlen(p);
1699  *(p++) = ':';
1700  }
1701 
1702  strlcpy(p, node->attr.tmpl_da->name, end - p);
1703  p += strlen(p);
1704 
1705  if (node->attr.tmpl_tag != TAG_ANY) {
1706  *(p++) = ':';
1707  snprintf(p, end - p, "%u", node->attr.tmpl_tag);
1708  p += strlen(p);
1709  }
1710 
1711  if (node->attr.tmpl_num != NUM_ANY) {
1712  *(p++) = '[';
1713  switch (node->attr.tmpl_num) {
1714  case NUM_COUNT:
1715  *(p++) = '#';
1716  break;
1717 
1718  case NUM_ALL:
1719  *(p++) = '*';
1720  break;
1721 
1722  default:
1723  snprintf(p, end - p, "%i", node->attr.tmpl_num);
1724  p += strlen(p);
1725  }
1726  *(p++) = ']';
1727  }
1728  *(p++) = '}';
1729  break;
1730 #ifdef HAVE_REGEX
1731  case XLAT_REGEX:
1732  snprintf(p, end - p, "%%{%i}", node->attr.tmpl_num);
1733  p += strlen(p);
1734  break;
1735 #endif
1736  case XLAT_VIRTUAL:
1737  *(p++) = '%';
1738  *(p++) = '{';
1739  strlcpy(p, node->fmt, end - p);
1740  p += strlen(p);
1741  *(p++) = '}';
1742  break;
1743 
1744  case XLAT_MODULE:
1745  *(p++) = '%';
1746  *(p++) = '{';
1747  strlcpy(p, node->xlat->name, end - p);
1748  p += strlen(p);
1749  *(p++) = ':';
1750  rad_assert(node->child != NULL);
1751  len = xlat_snprint(p, end - p, node->child);
1752  p += len;
1753  *(p++) = '}';
1754  break;
1755 
1756  case XLAT_ALTERNATE:
1757  *(p++) = '%';
1758  *(p++) = '{';
1759 
1760  len = xlat_snprint(p, end - p, node->child);
1761  p += len;
1762 
1763  *(p++) = ':';
1764  *(p++) = '-';
1765 
1766  len = xlat_snprint(p, end - p, node->alternate);
1767  p += len;
1768 
1769  *(p++) = '}';
1770  break;
1771  }
1772 
1773 
1774  if (p == end) break;
1775 
1776  node = node->next;
1777  }
1778 
1779  *p = '\0';
1780 
1781  return p - buffer;
1782 }
1783 
1784 ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
1785  char const **error)
1786 {
1787  return xlat_tokenize_literal(ctx, fmt, head, false, error);
1788 }
1789 
1790 
1791 /** Tokenize an xlat expansion
1792  *
1793  * @param[in] request the input request. Memory will be attached here.
1794  * @param[in] fmt the format string to expand
1795  * @param[out] head the head of the xlat list / tree structure.
1796  */
1797 static ssize_t xlat_tokenize_request(REQUEST *request, char const *fmt, xlat_exp_t **head)
1798 {
1799  ssize_t slen;
1800  char *tokens;
1801  char const *error = NULL;
1802 
1803  *head = NULL;
1804 
1805  /*
1806  * Copy the original format string to a buffer so that
1807  * the later functions can mangle it in-place, which is
1808  * much faster.
1809  */
1810  tokens = talloc_typed_strdup(request, fmt);
1811  if (!tokens) return -1;
1812 
1813  slen = xlat_tokenize_literal(request, tokens, head, false, &error);
1814 
1815  /*
1816  * Zero length expansion, return a zero length node.
1817  */
1818  if (slen == 0) {
1819  *head = talloc_zero(request, xlat_exp_t);
1820  }
1821 
1822  /*
1823  * Output something like:
1824  *
1825  * "format string"
1826  * " ^ error was here"
1827  */
1828  if (slen < 0) {
1829  talloc_free(tokens);
1830  rad_assert(error != NULL);
1831 
1832  REMARKER(fmt, -slen, error);
1833  return slen;
1834  }
1835 
1836  if (*head && (rad_debug_lvl > 2)) {
1837  DEBUG("%s", fmt);
1838  DEBUG("Parsed xlat tree:");
1839  xlat_tokenize_debug(*head, 0);
1840  }
1841 
1842  /*
1843  * All of the nodes point to offsets in the "tokens"
1844  * string. Let's ensure that free'ing head will free
1845  * "tokens", too.
1846  */
1847  (void) talloc_steal(*head, tokens);
1848 
1849  return slen;
1850 }
1851 
1852 
1853 static char *xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, vp_tmpl_t const *vpt,
1854  bool escape, bool return_null)
1855 {
1856  VALUE_PAIR *vp = NULL, *virtual = NULL;
1857  RADIUS_PACKET *packet = NULL;
1858  fr_dict_enum_t *dv;
1859  char *ret = NULL;
1860 
1861  vp_cursor_t cursor;
1862  char quote = escape ? '"' : '\0';
1863 
1864  rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
1865 
1866  /*
1867  * We only support count and concatenate operations on lists.
1868  */
1869  if (vpt->type == TMPL_TYPE_LIST) {
1870  vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
1871  goto do_print;
1872  }
1873 
1874  /*
1875  * See if we're dealing with an attribute in the request
1876  *
1877  * This allows users to manipulate virtual attributes as if
1878  * they were real ones.
1879  */
1880  vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
1881  if (vp) goto do_print;
1882 
1883  /*
1884  * We didn't find the VP in a list.
1885  * If it's not a virtual one, and we're not meant to
1886  * be counting it, return.
1887  */
1888  if (!vpt->tmpl_da->flags.virtual) {
1889  if (vpt->tmpl_num == NUM_COUNT) goto do_print;
1890  return NULL;
1891  }
1892 
1893  /*
1894  * Switch out the request to the one specified by the template
1895  */
1896  if (radius_request(&request, vpt->tmpl_request) < 0) return NULL;
1897 
1898  /*
1899  * Some non-packet expansions
1900  */
1901  switch (vpt->tmpl_da->attr) {
1902  default:
1903  break; /* ignore them */
1904 
1905  case PW_CLIENT_SHORTNAME:
1906  if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
1907  if (request->client && request->client->shortname) {
1908  return talloc_typed_strdup(ctx, request->client->shortname);
1909  }
1910  return talloc_typed_strdup(ctx, "<UNKNOWN-CLIENT>");
1911 
1912  case PW_REQUEST_PROCESSING_STAGE:
1913  if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
1914  if (request->component) {
1915  return talloc_typed_strdup(ctx, request->component);
1916  }
1917  return talloc_typed_strdup(ctx, "server_core");
1918 
1919  case PW_VIRTUAL_SERVER:
1920  if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
1921  if (!request->server) return NULL;
1922  return talloc_typed_strdup(ctx, request->server);
1923 
1924  case PW_MODULE_RETURN_CODE:
1925  if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
1926  if (!request->rcode) return NULL;
1927  return talloc_typed_strdup(ctx, fr_int2str(modreturn_table, request->rcode, ""));
1928  }
1929 
1930  /*
1931  * All of the attributes must now refer to a packet.
1932  * If there's no packet, we can't print any attribute
1933  * referencing it.
1934  */
1935  packet = radius_packet(request, vpt->tmpl_list);
1936  if (!packet) {
1937  if (return_null) return NULL;
1938  return fr_pair_type_snprint(ctx, vpt->tmpl_da->type);
1939  }
1940 
1941  vp = NULL;
1942  switch (vpt->tmpl_da->attr) {
1943  default:
1944  break;
1945 
1946  case PW_PACKET_TYPE:
1947  if (packet->code > 0) {
1948  dv = fr_dict_enum_by_da(NULL, vpt->tmpl_da, packet->code);
1949  if (dv) return talloc_typed_strdup(ctx, dv->name);
1950  return talloc_typed_asprintf(ctx, "%d", packet->code);
1951  }
1952 
1953  /*
1954  * If there's no code set then we return an empty string (not zero).
1955  */
1956  return talloc_strdup(ctx, "");
1957 
1958  case PW_RESPONSE_PACKET_TYPE:
1959  {
1960  int code = 0;
1961 
1962 #ifdef WITH_PROXY
1963  if (request->proxy_reply && (!request->reply || !request->reply->code)) {
1964  code = request->proxy_reply->code;
1965  } else
1966 #endif
1967  if (request->reply) {
1968  code = request->reply->code;
1969  }
1970 
1971  if (code > 0) return talloc_typed_strdup(ctx, fr_packet_codes[code]);
1972 
1973  /*
1974  * If there's no code set then we return an empty string (not zero).
1975  */
1976  return talloc_strdup(ctx, "");
1977  }
1978 
1979  /*
1980  * Virtual attributes which require a temporary VALUE_PAIR
1981  * to be allocated. We can't use stack allocated memory
1982  * because of the talloc checks sprinkled throughout the
1983  * various VP functions.
1984  */
1985  case PW_PACKET_AUTHENTICATION_VECTOR:
1986  virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1987  fr_pair_value_memcpy(virtual, packet->vector, sizeof(packet->vector));
1988  vp = virtual;
1989  break;
1990 
1991  case PW_CLIENT_IP_ADDRESS:
1992  case PW_PACKET_SRC_IP_ADDRESS:
1993  if (packet->src_ipaddr.af == AF_INET) {
1994  virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
1995  virtual->vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
1996  vp = virtual;
1997  }
1998  break;
1999 
2000  case PW_PACKET_DST_IP_ADDRESS:
2001  if (packet->dst_ipaddr.af == AF_INET) {
2002  virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
2003  virtual->vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
2004  vp = virtual;
2005  }
2006  break;
2007 
2008  case PW_PACKET_SRC_IPV6_ADDRESS:
2009  if (packet->src_ipaddr.af == AF_INET6) {
2010  virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
2011  memcpy(&virtual->vp_ipv6addr,
2012  &packet->src_ipaddr.ipaddr.ip6addr,
2013  sizeof(packet->src_ipaddr.ipaddr.ip6addr));
2014  vp = virtual;
2015  }
2016  break;
2017 
2018  case PW_PACKET_DST_IPV6_ADDRESS:
2019  if (packet->dst_ipaddr.af == AF_INET6) {
2020  virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
2021  memcpy(&virtual->vp_ipv6addr,
2022  &packet->dst_ipaddr.ipaddr.ip6addr,
2023  sizeof(packet->dst_ipaddr.ipaddr.ip6addr));
2024  vp = virtual;
2025  }
2026  break;
2027 
2028  case PW_PACKET_SRC_PORT:
2029  virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
2030  virtual->vp_integer = packet->src_port;
2031  vp = virtual;
2032  break;
2033 
2034  case PW_PACKET_DST_PORT:
2035  virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
2036  virtual->vp_integer = packet->dst_port;
2037  vp = virtual;
2038  break;
2039  }
2040 
2041  /*
2042  * Fake various operations for virtual attributes.
2043  */
2044  if (virtual) {
2045  if (vpt->tmpl_num != NUM_ANY) switch (vpt->tmpl_num) {
2046  /*
2047  * [n] is NULL (we only have [0])
2048  */
2049  default:
2050  goto finish;
2051  /*
2052  * [*] means only one.
2053  */
2054  case NUM_ALL:
2055  break;
2056 
2057  /*
2058  * [#] means 1 (as there's only one)
2059  */
2060  case NUM_COUNT:
2061  count_virtual:
2062  ret = talloc_strdup(ctx, "1");
2063  goto finish;
2064 
2065  /*
2066  * [0] is fine (get the first instance)
2067  */
2068  case 0:
2069  break;
2070  }
2071  goto print;
2072  }
2073 
2074 do_print:
2075  switch (vpt->tmpl_num) {
2076  /*
2077  * Return a count of the VPs.
2078  */
2079  case NUM_COUNT:
2080  {
2081  int count = 0;
2082 
2083  for (vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
2084  vp;
2085  vp = tmpl_cursor_next(&cursor, vpt)) count++;
2086 
2087  return talloc_typed_asprintf(ctx, "%d", count);
2088  }
2089 
2090 
2091  /*
2092  * Concatenate all values together,
2093  * separated by commas.
2094  */
2095  case NUM_ALL:
2096  {
2097  char *p, *q;
2098 
2099  if (!fr_cursor_current(&cursor)) return NULL;
2100  p = fr_pair_value_asprint(ctx, vp, quote);
2101  if (!p) return NULL;
2102 
2103  while ((vp = tmpl_cursor_next(&cursor, vpt)) != NULL) {
2104  q = fr_pair_value_asprint(ctx, vp, quote);
2105  if (!q) return NULL;
2106  p = talloc_strdup_append(p, ",");
2107  p = talloc_strdup_append(p, q);
2108  }
2109 
2110  return p;
2111  }
2112 
2113  default:
2114  /*
2115  * The cursor was set to the correct
2116  * position above by tmpl_cursor_init.
2117  */
2118  vp = fr_cursor_current(&cursor);
2119  break;
2120  }
2121 
2122  if (!vp) {
2123  if (return_null) return NULL;
2124  return fr_pair_type_snprint(ctx, vpt->tmpl_da->type);
2125  }
2126 
2127 print:
2128  ret = fr_pair_value_asprint(ctx, vp, quote);
2129 
2130 finish:
2131  talloc_free(virtual);
2132  return ret;
2133 }
2134 
2135 #ifdef DEBUG_XLAT
2136 static const char xlat_spaces[] = " ";
2137 #endif
2138 
2139 static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * const node,
2140  xlat_escape_t escape, void *escape_ctx, int lvl)
2141 {
2142  ssize_t rcode;
2143  char *str = NULL, *child;
2144  char const *p;
2145 
2146  XLAT_DEBUG("%.*sxlat aprint %d %s", lvl, xlat_spaces, node->type, node->fmt);
2147 
2148  switch (node->type) {
2149  /*
2150  * Don't escape this.
2151  */
2152  case XLAT_LITERAL:
2153  XLAT_DEBUG("xlat_aprint LITERAL");
2154  return talloc_typed_strdup(ctx, node->fmt);
2155 
2156  /*
2157  * Do a one-character expansion.
2158  */
2159  case XLAT_PERCENT:
2160  {
2161  char *nl;
2162  size_t freespace = 256;
2163  struct tm ts;
2164  time_t when;
2165 
2166  XLAT_DEBUG("xlat_aprint PERCENT");
2167 
2168  str = talloc_array(ctx, char, freespace); /* @todo do better allocation */
2169  p = node->fmt;
2170 
2171  when = request->timestamp.tv_sec;
2172  if (request->packet) {
2173  when = request->packet->timestamp.tv_sec;
2174  }
2175 
2176  switch (*p) {
2177  case '%':
2178  str[0] = '%';
2179  str[1] = '\0';
2180  break;
2181 
2182  case 'd': /* request day */
2183  if (!localtime_r(&when, &ts)) goto error;
2184  strftime(str, freespace, "%d", &ts);
2185  break;
2186 
2187  case 'l': /* request timestamp */
2188  snprintf(str, freespace, "%lu",
2189  (unsigned long) when);
2190  break;
2191 
2192  case 'm': /* request month */
2193  if (!localtime_r(&when, &ts)) goto error;
2194  strftime(str, freespace, "%m", &ts);
2195  break;
2196 
2197  case 'n': /* Request Number*/
2198  snprintf(str, freespace, "%u", request->number);
2199  break;
2200 
2201  case 't': /* request timestamp */
2202  CTIME_R(&when, str, freespace);
2203  nl = strchr(str, '\n');
2204  if (nl) *nl = '\0';
2205  break;
2206 
2207  case 'D': /* request date */
2208  if (!localtime_r(&when, &ts)) goto error;
2209  strftime(str, freespace, "%Y%m%d", &ts);
2210  break;
2211 
2212  case 'G': /* request minute */
2213  if (!localtime_r(&when, &ts)) goto error;
2214  strftime(str, freespace, "%M", &ts);
2215  break;
2216 
2217  case 'H': /* request hour */
2218  if (!localtime_r(&when, &ts)) goto error;
2219  strftime(str, freespace, "%H", &ts);
2220  break;
2221 
2222  case 'I': /* Request ID */
2223  if (request->packet) {
2224  snprintf(str, freespace, "%i", request->packet->id);
2225  }
2226  break;
2227 
2228  case 'S': /* request timestamp in SQL format*/
2229  if (!localtime_r(&when, &ts)) goto error;
2230  strftime(str, freespace, "%Y-%m-%d %H:%M:%S", &ts);
2231  break;
2232 
2233  case 'T': /* request timestamp */
2234  if (!localtime_r(&when, &ts)) goto error;
2235  strftime(str, freespace, "%Y-%m-%d-%H.%M.%S.000000", &ts);
2236  break;
2237 
2238  case 'Y': /* request year */
2239  if (!localtime_r(&when, &ts)) {
2240  error:
2241  REDEBUG("Failed converting packet timestamp to localtime: %s", fr_syserror(errno));
2242  talloc_free(str);
2243  return NULL;
2244  }
2245  strftime(str, freespace, "%Y", &ts);
2246  break;
2247 
2248  case 'v': /* Version of code */
2249  RWDEBUG("%%v is deprecated and will be removed. Use ${version.freeradius-server}");
2250  snprintf(str, freespace, "%s", radiusd_version_short);
2251  break;
2252 
2253  default:
2254  rad_assert(0 == 1);
2255  break;
2256  }
2257  }
2258  break;
2259 
2260  case XLAT_ATTRIBUTE:
2261  XLAT_DEBUG("xlat_aprint ATTRIBUTE");
2262 
2263  /*
2264  * Some attributes are virtual <sigh>
2265  */
2266  str = xlat_getvp(ctx, request, &node->attr, escape ? false : true, true);
2267  if (str) {
2268  XLAT_DEBUG("EXPAND attr %s", node->attr.tmpl_da->name);
2269  XLAT_DEBUG(" ---> %s", str);
2270  }
2271  break;
2272 
2273  case XLAT_VIRTUAL:
2274  XLAT_DEBUG("xlat_aprint VIRTUAL");
2275 
2276  if (node->xlat->buf_len > 0) {
2277  str = talloc_array(request, char, node->xlat->buf_len);
2278  str[0] = '\0'; /* Be sure the string is \0 terminated */
2279  }
2280  rcode = node->xlat->func(&str, node->xlat->buf_len, node->xlat->mod_inst, NULL, request, NULL);
2281  if (rcode < 0) {
2282  talloc_free(str);
2283  return NULL;
2284  }
2285  RDEBUG2("EXPAND %s", node->xlat->name);
2286  RDEBUG2(" --> %s", str);
2287  break;
2288 
2289  case XLAT_MODULE:
2290  XLAT_DEBUG("xlat_aprint MODULE");
2291 
2292  if (node->child) {
2293  if (xlat_process(&child, request, node->child, node->xlat->escape, node->xlat->mod_inst) == 0) {
2294  return NULL;
2295  }
2296 
2297  XLAT_DEBUG("%.*sEXPAND mod %s %s", lvl, xlat_spaces, node->fmt, node->child->fmt);
2298  } else {
2299  XLAT_DEBUG("%.*sEXPAND mod %s", lvl, xlat_spaces, node->fmt);
2300  child = talloc_typed_strdup(ctx, "");
2301  }
2302 
2303  XLAT_DEBUG("%.*s ---> %s", lvl, xlat_spaces, child);
2304 
2305  /*
2306  * Smash \n --> CR.
2307  *
2308  * The OUTPUT of xlat is a "raw" string. The INPUT is a printable string.
2309  *
2310  * This is really the reverse of fr_snprint().
2311  */
2312  if (*child) {
2313  PW_TYPE type;
2315 
2316  type = PW_TYPE_STRING;
2317  if (value_data_from_str(request, &data, &type, NULL, child, talloc_array_length(child) - 1, '"') < 0) {
2318  talloc_free(child);
2319  return NULL;
2320  }
2321 
2322  talloc_free(child);
2323  child = data.ptr;
2324 
2325  } else {
2326  char *q;
2327 
2328  p = q = child;
2329  while (*p) {
2330  if (*p == '\\') switch (p[1]) {
2331  default:
2332  *(q++) = p[1];
2333  p += 2;
2334  continue;
2335 
2336  case 'n':
2337  *(q++) = '\n';
2338  p += 2;
2339  continue;
2340 
2341  case 't':
2342  *(q++) = '\t';
2343  p += 2;
2344  continue;
2345  }
2346 
2347  *(q++) = *(p++);
2348  }
2349  *q = '\0';
2350  }
2351 
2352  if (node->xlat->buf_len > 0) {
2353  str = talloc_array(request, char, node->xlat->buf_len);
2354  str[0] = '\0'; /* Be sure the string is \0 terminated */
2355  }
2356  rcode = node->xlat->func(&str, node->xlat->buf_len, node->xlat->mod_inst, NULL, request, child);
2357  talloc_free(child);
2358  if (rcode < 0) {
2359  talloc_free(str);
2360  return NULL;
2361  }
2362  break;
2363 
2364 #ifdef HAVE_REGEX
2365  case XLAT_REGEX:
2366  XLAT_DEBUG("xlat_aprint REGEX");
2367  if (regex_request_to_sub(ctx, &str, request, node->attr.tmpl_num) < 0) return NULL;
2368 
2369  break;
2370 #endif
2371 
2372  case XLAT_ALTERNATE:
2373  XLAT_DEBUG("xlat_aprint ALTERNATE");
2374  rad_assert(node->child != NULL);
2375  rad_assert(node->alternate != NULL);
2376 
2377  str = xlat_aprint(ctx, request, node->child, escape, escape_ctx, lvl);
2378  if (str) {
2379  XLAT_DEBUG("ALTERNATE got string: %s", str);
2380  break;
2381  }
2382 
2383  XLAT_DEBUG("ALTERNATE going to alternate");
2384  str = xlat_aprint(ctx, request, node->alternate, escape, escape_ctx, lvl);
2385  break;
2386 
2387  }
2388 
2389  /*
2390  * If there's no data, return that, instead of an empty string.
2391  */
2392  if (str && !str[0]) {
2393  talloc_free(str);
2394  return NULL;
2395  }
2396 
2397  /*
2398  * Escape the non-literals we found above.
2399  */
2400  if (str && escape) {
2401  char *escaped;
2402 
2403  escaped = talloc_array(ctx, char, 2048); /* FIXME: do something intelligent */
2404  escape(request, escaped, 2038, str, escape_ctx);
2405  talloc_free(str);
2406  str = escaped;
2407  }
2408 
2409  return str;
2410 }
2411 
2412 
2413 static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const * const head,
2414  xlat_escape_t escape, void *escape_ctx)
2415 {
2416  int i, list;
2417  size_t total;
2418  char **array, *answer;
2419  xlat_exp_t const *node;
2420 
2421  *out = NULL;
2422 
2423  /*
2424  * There are no nodes to process, so the result is a zero
2425  * length string.
2426  */
2427  if (!head) {
2428  *out = talloc_zero_array(request, char, 1);
2429  return 0;
2430  }
2431 
2432  /*
2433  * Hack for speed. If it's one expansion, just allocate
2434  * that and return, instead of allocating an intermediary
2435  * array.
2436  */
2437  if (!head->next) {
2438  /*
2439  * Pass the MAIN escape function. Recursive
2440  * calls will call node-specific escape
2441  * functions.
2442  */
2443  answer = xlat_aprint(request, request, head, escape, escape_ctx, 0);
2444  if (!answer) {
2445  *out = talloc_zero_array(request, char, 1);
2446  return 0;
2447  }
2448  *out = answer;
2449  return strlen(answer);
2450  }
2451 
2452  list = 0; /* FIXME: calculate this once */
2453  for (node = head; node != NULL; node = node->next) {
2454  list++;
2455  }
2456 
2457  array = talloc_array(request, char *, list);
2458  if (!array) return -1;
2459 
2460  for (node = head, i = 0; node != NULL; node = node->next, i++) {
2461  array[i] = xlat_aprint(array, request, node, escape, escape_ctx, 0); /* may be NULL */
2462  }
2463 
2464  total = 0;
2465  for (i = 0; i < list; i++) {
2466  if (array[i]) total += strlen(array[i]); /* FIXME: calculate strlen once */
2467  }
2468 
2469  if (!total) {
2470  talloc_free(array);
2471  *out = talloc_zero_array(request, char, 1);
2472  return 0;
2473  }
2474 
2475  answer = talloc_array(request, char, total + 1);
2476 
2477  total = 0;
2478  for (i = 0; i < list; i++) {
2479  size_t len;
2480 
2481  if (array[i]) {
2482  len = strlen(array[i]);
2483  memcpy(answer + total, array[i], len);
2484  total += len;
2485  }
2486  }
2487  answer[total] = '\0';
2488  talloc_free(array); /* and child entries */
2489 
2490  *out = answer;
2491  return total;
2492 }
2493 
2494 
2495 /** Replace %whatever in a string.
2496  *
2497  * See 'doc/configuration/variables.rst' for more information.
2498  *
2499  * @param[out] out Where to write pointer to output buffer.
2500  * @param[in] outlen Size of out.
2501  * @param[in] request current request.
2502  * @param[in] node the xlat structure to expand
2503  * @param[in] escape function to escape final value e.g. SQL quoting.
2504  * @param[in] escape_ctx pointer to pass to escape function.
2505  * @return length of string written @bug should really have -1 for failure.
2506  */
2507 static ssize_t xlat_expand_struct(char **out, size_t outlen, REQUEST *request, xlat_exp_t const *node,
2508  xlat_escape_t escape, void *escape_ctx)
2509 {
2510  char *buff;
2511  ssize_t len;
2512 
2513  rad_assert(node != NULL);
2514 
2515  len = xlat_process(&buff, request, node, escape, escape_ctx);
2516  if ((len < 0) || !buff) {
2517  rad_assert(buff == NULL);
2518  if (*out) **out = '\0';
2519  return len;
2520  }
2521 
2522  len = strlen(buff);
2523 
2524  /*
2525  * If out doesn't point to an existing buffer
2526  * copy the pointer to our buffer over.
2527  */
2528  if (!*out) {
2529  *out = buff;
2530  return len;
2531  }
2532 
2533  /*
2534  * Otherwise copy the malloced buffer to the fixed one.
2535  */
2536  strlcpy(*out, buff, outlen);
2537  talloc_free(buff);
2538  return len;
2539 }
2540 
2541 static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
2542  xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull (1, 3, 4));
2543 
2544 /** Replace %whatever in a string.
2545  *
2546  * See 'doc/configuration/variables.rst' for more information.
2547  *
2548  * @param[out] out Where to write pointer to output buffer.
2549  * @param[in] outlen Size of out.
2550  * @param[in] request current request.
2551  * @param[in] fmt string to expand.
2552  * @param[in] escape function to escape final value e.g. SQL quoting.
2553  * @param[in] escape_ctx pointer to pass to escape function.
2554  * @return length of string written @bug should really have -1 for failure.
2555  */
2556 static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
2557  xlat_escape_t escape, void *escape_ctx)
2558 {
2559  ssize_t len;
2560  xlat_exp_t *node;
2561 
2562  /*
2563  * Give better errors than the old code.
2564  */
2565  len = xlat_tokenize_request(request, fmt, &node);
2566  if (len == 0) {
2567  if (*out) {
2568  **out = '\0';
2569  } else {
2570  *out = talloc_zero_array(request, char, 1);
2571  }
2572  return 0;
2573  }
2574 
2575  if (len < 0) {
2576  if (*out) **out = '\0';
2577  return -1;
2578  }
2579 
2580  len = xlat_expand_struct(out, outlen, request, node, escape, escape_ctx);
2581  talloc_free(node);
2582 
2583  RDEBUG2("EXPAND %s", fmt);
2584  RDEBUG2(" --> %s", *out);
2585 
2586  return len;
2587 }
2588 
2589 /** Try to convert an xlat to a tmpl for efficiency
2590  *
2591  * @param ctx to allocate new vp_tmpl_t in.
2592  * @param node to convert.
2593  * @return
2594  * - NULL if unable to convert (not necessarily error).
2595  * - A new #vp_tmpl_t.
2596  */
2597 vp_tmpl_t *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_t *node)
2598 {
2599  vp_tmpl_t *vpt;
2600 
2601  if (node->next || (node->type != XLAT_ATTRIBUTE) || (node->attr.type != TMPL_TYPE_ATTR)) return NULL;
2602 
2603  /*
2604  * Concat means something completely different as an attribute reference
2605  * Count isn't implemented.
2606  */
2607  if ((node->attr.tmpl_num == NUM_COUNT) || (node->attr.tmpl_num == NUM_ALL)) return NULL;
2608 
2609  vpt = tmpl_alloc(ctx, TMPL_TYPE_ATTR, node->fmt, -1, T_BARE_WORD);
2610  if (!vpt) return NULL;
2611  memcpy(&vpt->data, &node->attr.data, sizeof(vpt->data));
2612 
2613  VERIFY_TMPL(vpt);
2614 
2615  return vpt;
2616 }
2617 
2618 /** Try to convert attr tmpl to an xlat for &attr[*] and artificially constructing expansions
2619  *
2620  * @param ctx to allocate new xlat_expt_t in.
2621  * @param vpt to convert.
2622  * @return
2623  * - NULL if unable to convert (not necessarily error).
2624  * - a new #vp_tmpl_t.
2625  */
2627 {
2628  xlat_exp_t *node;
2629 
2630  if (vpt->type != TMPL_TYPE_ATTR) return NULL;
2631 
2632  node = talloc_zero(ctx, xlat_exp_t);
2633  node->type = XLAT_ATTRIBUTE;
2634  node->fmt = talloc_bstrndup(node, vpt->name, vpt->len);
2635  tmpl_init(&node->attr, TMPL_TYPE_ATTR, node->fmt, talloc_array_length(node->fmt) - 1, T_BARE_WORD);
2636  memcpy(&node->attr.data, &vpt->data, sizeof(vpt->data));
2637 
2638  return node;
2639 }
2640 
2641 ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
2642 {
2643  return xlat_expand(&out, outlen, request, fmt, escape, ctx);
2644 }
2645 
2646 ssize_t radius_xlat_struct(char *out, size_t outlen, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
2647 {
2648  return xlat_expand_struct(&out, outlen, request, xlat, escape, ctx);
2649 }
2650 
2651 ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
2652 {
2653  return xlat_expand(out, 0, request, fmt, escape, ctx);
2654 }
2655 
2656 ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
2657 {
2658  return xlat_expand_struct(out, 0, request, xlat, escape, ctx);
2659 }
static ssize_t xlat_integer(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Print data as integer, not as VALUE.
Definition: xlat.c:129
size_t len
Length of the output string.
Definition: xlat.c:76
static ssize_t xlat_tokenize_request(REQUEST *request, char const *fmt, xlat_exp_t **head)
Tokenize an xlat expansion.
Definition: xlat.c:1797
static ssize_t xlat_attr(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Return the attribute name of an attribute reference.
Definition: xlat.c:325
void * mod_inst
Module instance passed to xlat and escape functions.
Definition: xlat.c:39
128 Bit IPv6 Address.
Definition: radius.h:40
#define TAG_VALID(x)
Definition: pair.h:189
int id
Packet ID (used to link requests/responses).
Definition: libradius.h:154
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:265
static char const xlat_tabs[]
Definition: xlat.c:1580
struct timeval timestamp
When we received the packet.
Definition: libradius.h:159
int int map_to_request(REQUEST *request, vp_map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert vp_map_t to VALUE_PAIR (s) and add them to a REQUEST.
Definition: map.c:1019
vp_tmpl_t * xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_t *node)
Try to convert an xlat to a tmpl for efficiency.
Definition: xlat.c:2597
#define DEBUG3(fmt,...)
Definition: log.h:177
void rbtree_free(rbtree_t *tree)
Definition: rbtree.c:84
vp_tmpl_t attr
An attribute template.
Definition: xlat.c:70
static ssize_t xlat_foreach(char **out, size_t outlen, void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, UNUSED char const *fmt)
Implements the Foreach-Variable-X.
Definition: xlat.c:543
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition: log.h:239
Time value (struct timeval), only for config items.
Definition: radius.h:55
Literal string.
Definition: xlat.c:49
ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
Definition: xlat.c:2641
static ssize_t xlat_module(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, UNUSED char const *fmt)
Prints the current module processing the request.
Definition: xlat.c:507
#define NUM_ANY
Definition: pair.h:201
RADIUS_PACKET * proxy_reply
Incoming response from proxy server.
Definition: radiusd.h:238
struct rad_request::@7 log
xlat attribute
Definition: xlat.c:53
uint128_t ntohlll(uint128_t const num)
Swap byte order of 128 bit integer.
Definition: missing.c:354
bool rbtree_deletebydata(rbtree_t *tree, void const *data)
Delete a node from the tree, based on given data, which MUST have come from rbtree_finddata().
Definition: rbtree.c:496
static ssize_t xlat_tag(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Return the tag of an attribute reference.
Definition: xlat.c:270
RADIUS_PACKET * radius_packet(REQUEST *request, pair_lists_t list_name)
Resolve a list to the RADIUS_PACKET holding the HEAD pointer for a VALUE_PAIR list.
Definition: tmpl.c:279
void xlat_free(void)
De-register all xlat functions, used mainly for debugging.
Definition: xlat.c:1147
#define RDEBUG_ENABLED2
True if request debug level 1-2 messages are enabled.
Definition: log.h:238
char const * fr_packet_codes[FR_MAX_PACKET_CODE]
Definition: radius.c:101
char const * name
Raw string used to create the template.
Definition: tmpl.h:190
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: radius.c:1621
#define XLAT_DEBUG(...)
Definition: xlat.c:1155
rbnode_t * rbtree_insert_node(rbtree_t *tree, void *data)
Insert an element into the tree.
Definition: rbtree.c:258
xlat conditional syntax :-
Definition: xlat.c:57
32 Bit signed integer.
Definition: radius.h:45
rlm_rcode_t rcode
Last rcode returned by a module.
Definition: radiusd.h:252
fr_ipaddr_t src_ipaddr
Src IP address of packet.
Definition: libradius.h:149
WiMAX IPv4 or IPv6 address depending on length.
Definition: radius.h:46
Dictionary attribute.
Definition: tmpl.h:133
static char const * name
xlat_exp_t * alternate
Alternative expansion if this one expanded to a zero length string.
Definition: xlat.c:68
size_t length
Length of length data.
Definition: dict.h:105
#define CC_HINT(_x)
Definition: build.h:71
static int xlat_foreach_inst[]
Definition: xlat.c:96
ssize_t(* xlat_func_t)(char **out, size_t outlen, void const *mod_inst, void const *xlat_inst, REQUEST *request, char const *fmt)
xlat callback function
Definition: xlat.h:55
xlat module
Definition: xlat.c:51
char name[1]
Vendor name.
Definition: dict.h:107
#define REMARKER(_m, _i, _e)
Output string with error marker, showing where format error occurred.
Definition: log.h:306
virtual attribute
Definition: xlat.c:52
#define UNUSED
Definition: libradius.h:134
ssize_t tmpl_from_attr_substr(vp_tmpl_t *vpt, char const *name, request_refs_t request_def, pair_lists_t list_def, bool allow_unknown, bool allow_undefined)
Parse a string into a TMPL_TYPE_ATTR_* or TMPL_TYPE_LIST type vp_tmpl_t.
Definition: tmpl.c:661
void xlat_unregister(void *mod_inst, char const *name, UNUSED xlat_func_t func)
Unregister an xlat function.
Definition: xlat.c:850
int8_t tag
Tag value used to group valuepairs.
Definition: pair.h:121
void size_t fr_pair_value_snprint(char *out, size_t outlen, VALUE_PAIR const *vp, char quote)
Print the value of an attribute to a string.
Definition: pair.c:2107
const FR_NAME_NUMBER fr_tokens_table[]
Definition: token.c:30
char name[MAX_STRING_LEN]
Name of the xlat expansion.
Definition: xlat.c:37
void * request_data_reference(REQUEST *request, void *unique_ptr, int unique_int)
Get opaque data from a request without removing it.
Definition: request.c:484
IPv6 Prefix.
Definition: radius.h:41
static ssize_t xlat_map(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Processes fmt as a map string and applies it to the current request.
Definition: xlat.c:481
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
Number of defined data types.
Definition: radius.h:59
#define RBTREE_FLAG_REPLACE
Definition: libradius.h:526
uint8_t length
Definition: proto_bfd.c:203
Long extended attribute space attribute.
Definition: radius.h:49
void * rbtree_finddata(rbtree_t *tree, void const *data)
Find the user data.
Definition: rbtree.c:537
static expr_map_t map[]
Definition: rlm_expr.c:169
size_t len
Length of the format string.
Definition: xlat.c:62
unsigned int number
Monotonically increasing request number. Reset on server restart.
Definition: radiusd.h:213
size_t(* xlat_escape_t)(REQUEST *request, char *out, size_t outlen, char const *in, void *arg)
Definition: xlat.h:36
#define XLAT_DEFAULT_BUF_LEN
Definition: xlat.h:89
int number
Definition: token.h:70
uint16_t dst_port
DST Port of packet.
Definition: libradius.h:152
uint16_t src_port
Src port of packet.
Definition: libradius.h:151
fr_ipaddr_t dst_ipaddr
Dst IP address of packet.
Definition: libradius.h:150
static char const *const xlat_foreach_names[]
Definition: xlat.c:82
ssize_t fr_radius_encode_value_hton(uint8_t const **out, VALUE_PAIR const *vp)
Converts vp_data to network byte order.
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
fr_dict_attr_flags_t flags
Flags.
Definition: dict.h:88
fr_dict_vendor_t const * fr_dict_vendor_by_num(fr_dict_t *dict, int vendor)
Look up a vendor by its PEN.
Definition: dict.c:3412
const FR_NAME_NUMBER modreturn_table[]
Definition: evaluate.c:40
size_t fr_snprint(char *out, size_t outlen, char const *in, ssize_t inlen, char quote)
Escape any non printable or non-UTF8 characters in the input string.
Definition: print.c:179
void vradlog_request(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, va_list ap) CC_HINT(format(printf
WiMAX IPv4 or IPv6 address prefix depending on length.
Definition: radius.h:57
char * fr_pair_value_asprint(TALLOC_CTX *ctx, VALUE_PAIR const *vp, char quote)
Print one attribute value to a string.
Definition: pair.c:2123
static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull(1
Replace whatever in a string.
Definition: xlat.c:2556
int(* xlat_instantiate_t)(void *xlat_inst, void *mod_inst, char const *fmt)
Allocate new instance data for an xlat instance.
Definition: xlat.h:68
#define is_truncated(_ret, _max)
Definition: libradius.h:204
pair_lists
Definition: tmpl.h:80
int af
Address family.
Definition: inet.h:42
Attribute not found in the global dictionary.
Definition: tmpl.h:134
#define rad_assert(expr)
Definition: rad_assert.h:38
Definition: xlat.c:60
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
char const * name
Definition: token.h:69
const FR_NAME_NUMBER request_refs[]
Map keywords to request_refs_t values.
Definition: tmpl.c:74
VALUE_PAIR * tmpl_cursor_init(int *err, vp_cursor_t *cursor, REQUEST *request, vp_tmpl_t const *vpt)
Initialise a vp_cursor_t to the VALUE_PAIR specified by a vp_tmpl_t.
Definition: tmpl.c:1990
8 Bit unsigned integer.
Definition: radius.h:42
static ssize_t xlat_string(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Print data as string, if possible.
Definition: xlat.c:572
int value_data_cast(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv, PW_TYPE src_type, fr_dict_attr_t const *src_enumv, value_data_t const *src)
Convert one type of value_data_t to another.
Definition: value.c:1073
char const * cf_pair_attr(CONF_PAIR const *pair)
Definition: conffile.c:3497
#define DEBUG(fmt,...)
Definition: log.h:175
rbtree_t * rbtree_create(TALLOC_CTX *ctx, rb_comparator_t compare, rb_free_t node_free, int flags)
Create a new RED-BLACK tree.
Definition: rbtree.c:112
static ssize_t xlat_debug(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Dynamically change the debugging level for the current request.
Definition: xlat.c:641
char const * component
Section the request is in.
Definition: radiusd.h:254
ssize_t tmpl_from_attr_str(vp_tmpl_t *vpt, char const *name, request_refs_t request_def, pair_lists_t list_def, bool allow_unknown, bool allow_undefined)
Parse a string into a TMPL_TYPE_ATTR_* or TMPL_TYPE_LIST type vp_tmpl_t.
Definition: tmpl.c:877
static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const *const head, xlat_escape_t escape, void *escape_ctx)
Definition: xlat.c:2413
const FR_NAME_NUMBER dict_attr_types[]
Map data types to names representing those types.
Definition: dict.c:85
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *item)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: conffile.c:181
#define STRINGIFY(x)
Definition: build.h:34
xlat_redundant_type_t
Definition: xlat.c:885
unsigned int attr
Attribute number.
Definition: dict.h:79
static bool done
Definition: radclient.c:53
union fr_ipaddr_t::@1 ipaddr
Attributes in incoming or internally proxied request.
Definition: tmpl.h:82
xlat_func_t func
xlat function.
Definition: xlat.c:40
int radius_request(REQUEST **request, request_refs_t name)
Resolve a request_refs_t to a REQUEST.
Definition: tmpl.c:451
#define RDEBUG_ENABLED4
True if request debug level 1-4 messages are enabled.
Definition: log.h:240
unsigned int code
Packet code (type).
Definition: libradius.h:155
int rbtree_walk(rbtree_t *tree, rb_order_t order, rb_walker_t compare, void *context)
Definition: rbtree.c:693
char * fr_pair_type_snprint(TALLOC_CTX *ctx, PW_TYPE type)
Definition: pair.c:2130
Attribute list.
Definition: tmpl.h:135
unsigned int vendor
Vendor that defines this attribute.
Definition: dict.h:78
void void int radius_get_vp(VALUE_PAIR **out, REQUEST *request, char const *name)
Return a VP from the specified request.
Definition: pair.c:815
static ssize_t xlat_hex(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Print data as hex, not as VALUE.
Definition: xlat.c:212
static rbtree_t * xlat_root
Definition: xlat.c:79
static xlat_t * xlat_find(char const *name)
Definition: xlat.c:692
struct xlat_t xlat_t
48 Bit Mac-Address.
Definition: radius.h:44
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
void rad_const_free(void const *ptr)
Definition: util.c:424
VALUE_PAIR * fr_cursor_current(vp_cursor_t *cursor)
Return the VALUE_PAIR the cursor current points to.
Definition: cursor.c:304
RADIUS_PACKET * reply
Outgoing response.
Definition: radiusd.h:225
char * talloc_typed_asprintf(void const *t, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: missing.c:611
ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, char const **error)
Definition: xlat.c:1784
bool internal
If true, cannot be redefined.
Definition: xlat.c:45
void void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
xlat_exp_t * child
Nested expansion.
Definition: xlat.c:67
ssize_t xlat_fmt_to_ref(uint8_t const **out, REQUEST *request, char const *fmt)
Crappy temporary function to add attribute ref support to xlats.
Definition: xlat.c:1125
bool cf_item_is_pair(CONF_ITEM const *item)
Definition: conffile.c:3928
static ssize_t xlat_vendor_num(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Return the vendor number of an attribute reference.
Definition: xlat.c:309
Invalid (uninitialised) attribute type.
Definition: radius.h:32
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:272
The current request.
Definition: tmpl.h:113
ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
Definition: xlat.c:2651
FR_TOKEN op
Operator to use when moving or inserting valuepair into a list.
Definition: pair.h:118
32 Bit unsigned integer.
Definition: radius.h:34
#define VERIFY_TMPL(_x)
Definition: tmpl.h:266
tmpl_type_t type
What type of value tmpl refers to.
Definition: tmpl.h:188
xlat_state_t
Definition: xlat.c:48
uint8_t vector[AUTH_VECTOR_LEN]
RADIUS authentication vector.
Definition: libradius.h:157
int length
Length of name.
Definition: xlat.c:38
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
size_t len
Length of the raw string used to create the template.
Definition: tmpl.h:191
xlat_exp_t * xlat_from_tmpl_attr(TALLOC_CTX *ctx, vp_tmpl_t *vpt)
Try to convert attr tmpl to an xlat for &attr[*] and artificially constructing expansions.
Definition: xlat.c:2626
Private enterprise.
Definition: dict.h:102
char name[1]
Enum name.
Definition: dict.h:97
64 Bit unsigned integer.
Definition: radius.h:51
char const * cf_section_name1(CONF_SECTION const *cs)
Definition: conffile.c:3592
vp_tmpl_t * tmpl_init(vp_tmpl_t *vpt, tmpl_type_t type, char const *name, ssize_t len, FR_TOKEN quote)
Initialise stack allocated vp_tmpl_t.
Definition: tmpl.c:497
#define RDEBUG2(fmt,...)
Definition: log.h:244
Definition: xlat.c:74
CONF_SECTION * cs
Definition: xlat.c:895
Vendor-Specific, for RADIUS attribute 26.
Definition: radius.h:53
uint32_t count
Definition: xlat.c:894
#define NUM_ALL
Definition: pair.h:202
char name[1]
Attribute name.
Definition: dict.h:89
uint8_t data[]
Definition: eap_pwd.h:625
static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, char const **error)
Definition: xlat.c:1235
#define RIDEBUG(fmt,...)
Definition: log.h:248
size_t length
Length of value data.
Definition: pair.h:87
char * talloc_bstrndup(void const *t, char const *in, size_t inlen)
Binary safe strndup function.
Definition: missing.c:632
size_t buf_len
Length of output buffer to pre-allocate.
Definition: xlat.c:44
static ssize_t xlat_expand_struct(char **out, size_t outlen, REQUEST *request, xlat_exp_t const *node, xlat_escape_t escape, void *escape_ctx)
Replace whatever in a string.
Definition: xlat.c:2507
#define RIDEBUG2(fmt,...)
Definition: log.h:249
#define TAG_ANY
Definition: pair.h:191
32 Bit Unix timestamp.
Definition: radius.h:36
int int map_afrom_attr_str(TALLOC_CTX *ctx, vp_map_t **out, char const *raw, request_refs_t dst_request_def, pair_lists_t dst_list_def, request_refs_t src_request_def, pair_lists_t src_list_def)
Convert a value pair string to valuepair map.
Definition: map.c:487
size_t xlat_snprint(char *buffer, size_t bufsize, xlat_exp_t const *node)
Definition: xlat.c:1659
Literal string with v.
Definition: xlat.c:50
Extended attribute space attribute.
Definition: radius.h:48
struct timeval timestamp
When we started processing the request.
Definition: radiusd.h:214
log_lvl_t rad_debug_lvl
Global debugging level.
Definition: log.c:49
static ssize_t xlat_attr_num(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Return the attribute number of an attribute reference.
Definition: xlat.c:342
static ssize_t xlat_load_balance(char **out, size_t outlen, void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Definition: xlat.c:950
struct xlat_redundant_t xlat_redundant_t
char const * out
Output data.
Definition: xlat.c:75
xlat_state_t type
type of this expansion.
Definition: xlat.c:64
static char * xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, vp_tmpl_t const *vpt, bool escape, bool return_null)
Definition: xlat.c:1853
int value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE *src_type, fr_dict_attr_t const *src_enumv, char const *src, ssize_t src_len, char quote)
Convert string value to a value_data_t type.
Definition: value.c:455
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
static ssize_t xlat_vendor(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Return the vendor of an attribute reference.
Definition: xlat.c:288
static char * xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const *const node, xlat_escape_t escape, void *escape_ctx, int lvl)
Definition: xlat.c:2139
fr_dict_enum_t * fr_dict_enum_by_da(fr_dict_t *dict, fr_dict_attr_t const *da, int value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
Definition: dict.c:3654
static ssize_t xlat_tokenize_alternation(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, char const **error)
Definition: xlat.c:1165
#define REDEBUG(fmt,...)
Definition: log.h:254
static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, bool brace, char const **error)
Definition: xlat.c:1413
bool xlat_register_redundant(CONF_SECTION *cs)
Definition: xlat.c:1041
unsigned int has_tag
Tagged attribute.
Definition: dict.h:46
Definition: xlat.c:36
static void xlat_tokenize_debug(xlat_exp_t const *node, int lvl)
Definition: xlat.c:1582
CONF_ITEM * cf_item_find_next(CONF_SECTION const *section, CONF_ITEM const *item)
Return the next item after a CONF_ITEM.
Definition: conffile.c:3850
int map_to_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx) CC_HINT(nonnull(2
xlat_instantiate_t instantiate
Instantiation function.
Definition: xlat.c:42
static ssize_t xlat_strlen(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, UNUSED REQUEST *request, char const *fmt)
Print length of its RHS.
Definition: xlat.c:101
struct xlat_out xlat_out_t
static ssize_t xlat_redundant(char **out, size_t outlen, void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Definition: xlat.c:899
#define XLAT_REGISTER(_x)
#define RAD_REQUEST_LVL_NONE
No debug messages should be printed.
Definition: radiusd.h:313
static ssize_t xlat_debug_attr(UNUSED char **out, UNUSED size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Print out attribute info.
Definition: xlat.c:365
ssize_t radius_xlat_struct(char *out, size_t outlen, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
Definition: xlat.c:2646
IPv4 Prefix.
Definition: radius.h:52
char const * fmt
The format string.
Definition: xlat.c:61
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
VALUE_PAIR * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute.
Definition: pair.c:58
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
#define NUM_COUNT
Definition: pair.h:203
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
void xlat_unregister_module(void *instance)
Definition: xlat.c:877
size_t inst_size
Length of instance data to pre-allocate.
Definition: xlat.c:43
static ssize_t xlat_length(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Print the size of the attribute in bytes.
Definition: xlat.c:112
#define MAX_STRING_LEN
Definition: libradius.h:120
static char const hex[]
Definition: smbencrypt.c:34
String of printable characters.
Definition: radius.h:33
Contains nested attributes.
Definition: radius.h:47
#define RWDEBUG(fmt,...)
Definition: log.h:251
PW_TYPE type
Value type.
Definition: dict.h:80
size_t fr_snprint_uint128(char *out, size_t outlen, uint128_t const num)
Write 128bit unsigned integer to buffer.
Definition: misc.c:633
RADCLIENT * client
The client that originally sent us the request.
Definition: radiusd.h:219
char const * radiusd_version_short
Definition: version.c:31
VALUE_PAIR * tmpl_cursor_next(vp_cursor_t *cursor, vp_tmpl_t const *vpt)
Returns the next VALUE_PAIR specified by vpt.
Definition: tmpl.c:2128
struct tm * localtime_r(time_t const *l_clock, struct tm *result)
Definition: missing.c:152
xlat_redundant_type_t type
Definition: xlat.c:893
#define RCSID(id)
Definition: build.h:135
xlat_t const * xlat
The xlat expansion to expand format with.
Definition: xlat.c:71
static int xlat_unregister_callback(void *mod_inst, void *data)
Definition: xlat.c:868
static ssize_t xlat_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
xlat expand string attribute value
Definition: xlat.c:619
char * talloc_typed_strdup(void const *t, char const *p)
Call talloc strdup, setting the type on the new chunk correctly.
Definition: missing.c:588
ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
Definition: xlat.c:2656
32 Bit IPv4 Address.
Definition: radius.h:35
char const * module
Module the request is currently being processed by.
Definition: radiusd.h:253
Value pair map.
Definition: map.h:46
union vp_tmpl_t::@11 data
int xlat_register(void *mod_inst, char const *name, xlat_func_t func, xlat_escape_t escape, xlat_instantiate_t instantiate, size_t inst_size, size_t buf_len)
Register an xlat function.
Definition: xlat.c:717
xlat_exp_t * next
Next in the list.
Definition: xlat.c:65
static int xlat_cmp(void const *one, void const *two)
Definition: xlat.c:676
#define RDEBUG(fmt,...)
Definition: log.h:243
A source or sink of value data.
Definition: tmpl.h:187
char * value_data_asprint(TALLOC_CTX *ctx, PW_TYPE type, fr_dict_attr_t const *enumv, value_data_t const *data, char quote)
Print one attribute value to a string.
Definition: value.c:1543
Value of an enumerated attribute.
Definition: dict.h:94
16 Bit unsigned integer.
Definition: radius.h:43
Raw octets.
Definition: radius.h:38
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
Definition: pair.c:1905
vp_tmpl_t * tmpl_alloc(TALLOC_CTX *ctx, tmpl_type_t type, char const *name, ssize_t len, FR_TOKEN quote)
Create a new heap allocated vp_tmpl_t.
Definition: tmpl.c:526
char const * server
Definition: radiusd.h:289
char const * cf_section_name2(CONF_SECTION const *cs)
Definition: conffile.c:3601
xlat_escape_t escape
Escape function to apply to dynamic input to func.
Definition: xlat.c:41
char const * shortname
Client nickname.
Definition: clients.h:41
PW_TYPE
Internal data types used within libfreeradius.
Definition: radius.h:31
Extended attribute, vendor specific.
Definition: radius.h:50
value_data_t data
Definition: pair.h:133