All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_expr.c
Go to the documentation of this file.
1 /*
2  * This program is 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 (at
5  * 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: b0f34c57fb69956828d32446274517a876d2e4db $
19  * @file rlm_expr.c
20  * @brief Register many xlat expansions including the expr expansion.
21  *
22  * @copyright 2001,2006 The FreeRADIUS server project
23  * @copyright 2002 Alan DeKok <aland@ox.org>
24  */
25 RCSID("$Id: b0f34c57fb69956828d32446274517a876d2e4db $")
27 
28 #include <freeradius-devel/radiusd.h>
29 #include <freeradius-devel/md5.h>
30 #include <freeradius-devel/sha1.h>
31 #include <freeradius-devel/base64.h>
32 #include <freeradius-devel/modules.h>
33 #include <freeradius-devel/rad_assert.h>
34 
35 #ifdef HAVE_OPENSSL_EVP_H
36 # include <openssl/evp.h>
37 #endif
38 
39 #include <ctype.h>
40 
41 #include "rlm_expr.h"
42 
43 /*
44  * Define a structure for our module configuration.
45  */
46 typedef struct rlm_expr_t {
47  char const *xlat_name;
48  char const *allowed_chars;
49 } rlm_expr_t;
50 
51 static const CONF_PARSER module_config[] = {
52  { FR_CONF_OFFSET("safe_characters", PW_TYPE_STRING, rlm_expr_t, allowed_chars), .dflt = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /" },
54 };
55 
56 /*
57  * Lookup tables for randstr char classes
58  */
59 static char randstr_punc[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
60 static char randstr_salt[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz/.";
61 
62 /*
63  * Characters humans rarely confuse. Reduces char set considerably
64  * should only be used for things such as one time passwords.
65  */
66 static char randstr_otp[] = "469ACGHJKLMNPQRUVWXYabdfhijkprstuvwxyz";
67 
68 static char const hextab[] = "0123456789abcdef";
69 
70 /** Calculate powers
71  *
72  * @author Orson Peters
73  * @note Borrowed from the gist here: https://gist.github.com/nightcracker/3551590.
74  *
75  * @param base a 32bit signed integer.
76  * @param exp amount to raise base by.
77  * @return base ^ pow, or 0 on underflow/overflow.
78  */
79 static int64_t fr_pow(int64_t base, int64_t exp)
80 {
81  static const uint8_t highest_bit_set[] = {
82  0, 1, 2, 2, 3, 3, 3, 3,
83  4, 4, 4, 4, 4, 4, 4, 4,
84  5, 5, 5, 5, 5, 5, 5, 5,
85  5, 5, 5, 5, 5, 5, 5, 5,
86  6, 6, 6, 6, 6, 6, 6, 6,
87  6, 6, 6, 6, 6, 6, 6, 6,
88  6, 6, 6, 6, 6, 6, 6, 6,
89  6, 6, 6, 6, 6, 6, 6, 6 // anything past 63 is a guaranteed overflow with base > 1
90  };
91 
92  int64_t result = 1;
93 
94  if (exp > 63) {
95  if (base == 1) {
96  return 1;
97  }
98 
99  if (base == -1) {
100  return 1 - 2 * (exp & 1);
101  }
102  return 0; /* overflow */
103  }
104 
105  switch (highest_bit_set[exp]) {
106  case 6:
107  if (exp & 1) result *= base;
108  exp >>= 1;
109  base *= base;
110  case 5:
111  if (exp & 1) result *= base;
112  exp >>= 1;
113  base *= base;
114  case 4:
115  if (exp & 1) result *= base;
116  exp >>= 1;
117  base *= base;
118  case 3:
119  if (exp & 1) result *= base;
120  exp >>= 1;
121  base *= base;
122  case 2:
123  if (exp & 1) result *= base;
124  exp >>= 1;
125  base *= base;
126  case 1:
127  if (exp & 1) result *= base;
128  default:
129  return result;
130  }
131 }
132 
133 /*
134  * Start of expression calculator.
135  */
136 typedef enum expr_token_t {
139 
142 
145 
148 
152 
155 } expr_token_t;
156 
157 static int precedence[TOKEN_LAST + 1] = {
158  0, 0, 1, 1, /* and or */
159  2, 2, 3, 3, /* shift add */
160  4, 4, 4, 5, /* mul, pow */
161  0
162 };
163 
164 typedef struct expr_map_t {
165  char op;
167 } expr_map_t;
168 
169 static expr_map_t map[] =
170 {
171  {'+', TOKEN_ADD },
172  {'-', TOKEN_SUBTRACT },
173  {'/', TOKEN_DIVIDE },
174  {'*', TOKEN_MULTIPLY },
175  {'%', TOKEN_REMAINDER },
176  {'&', TOKEN_AND },
177  {'|', TOKEN_OR },
178  {'^', TOKEN_POWER },
179  {0, TOKEN_LAST}
180 };
181 
182 static bool get_expression(REQUEST *request, char const **string, int64_t *answer, expr_token_t prev);
183 
184 static bool get_number(REQUEST *request, char const **string, int64_t *answer)
185 {
186  int64_t x;
187  bool invert = false;
188  bool negative = false;
189  char const *p = *string;
190 
191  /*
192  * Look for a number.
193  */
194  while (isspace((int) *p)) p++;
195 
196  /*
197  * ~1 == 0xff...ffe
198  */
199  if (*p == '~') {
200  invert = true;
201  p++;
202  }
203 
204  /*
205  * No algrebraic operator found, the next thing
206  * MUST be a number.
207  *
208  * If it isn't, then we die.
209  */
210  if ((*p == '0') && (p[1] == 'x')) {
211  char *end;
212 
213  x = strtoul(p, &end, 16);
214  p = end;
215  goto done;
216  }
217 
218  if (*p == '-') {
219  negative = true;
220  p++;
221  }
222 
223  /*
224  * Look for an attribute.
225  */
226  if (*p == '&') {
227  ssize_t slen;
228  VALUE_PAIR *vp;
229  vp_tmpl_t vpt;
230 
231  p += 1;
232 
233  slen = tmpl_from_attr_substr(&vpt, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false);
234  if (slen <= 0) {
235  REDEBUG("Failed parsing attribute name '%s': %s", p, fr_strerror());
236  return false;
237  }
238 
239  p += slen;
240 
241  if (tmpl_find_vp(&vp, request, &vpt) < 0) {
242  RWDEBUG("Can't find &%.*s. Using 0 as operand value", (int)vpt.len, vpt.name);
243  x = 0;
244  goto done;
245  }
246 
247  if (vp->da->type != PW_TYPE_INTEGER64) {
248  value_data_t value;
249 
250  if (value_data_cast(vp, &value, PW_TYPE_INTEGER64, NULL, vp->da->type, vp->da, &vp->data) < 0) {
251  REDEBUG("Failed converting &%.*s to an integer value: %s", (int) vpt.len,
252  vpt.name, fr_strerror());
253  return false;
254  }
255  if (value.integer64 > INT64_MAX) {
256  overflow:
257  REDEBUG("Value of &%.*s (%"PRIu64 ") would overflow a signed 64bit integer "
258  "(our internal arithmetic type)", (int)vpt.len, vpt.name, value.integer64);
259  return false;
260  }
261  x = (int64_t)value.integer64;
262 
263  RINDENT();
264  RDEBUG3("&%.*s --> %" PRIu64, (int)vpt.len, vpt.name, x);
265  REXDENT();
266  } else {
267  if (vp->vp_integer64 > INT64_MAX) goto overflow;
268  x = (int64_t)vp->vp_integer64;
269  }
270 
271  goto done;
272  }
273 
274  /*
275  * Do brackets recursively
276  */
277  if (*p == '(') {
278  p++;
279  if (!get_expression(request, &p, &x, TOKEN_NONE)) return false;
280 
281  if (*p != ')') {
282  RDEBUG("No trailing ')'");
283  return false;
284  }
285  p++;
286  goto done;
287  }
288 
289  if ((*p < '0') || (*p > '9')) {
290  RDEBUG2("Not a number at \"%s\"", p);
291  return false;
292  }
293 
294  /*
295  * This is doing it the hard way, but it also allows
296  * us to increment 'p'.
297  */
298  x = 0;
299  while ((*p >= '0') && (*p <= '9')) {
300  x *= 10;
301  x += (*p - '0');
302  p++;
303  }
304 
305 done:
306  if (invert) x = ~x;
307 
308  if (negative) x = -x;
309 
310  *string = p;
311  *answer = x;
312  return true;
313 }
314 
315 static bool calc_result(REQUEST *request, int64_t lhs, expr_token_t op, int64_t rhs, int64_t *answer)
316 {
317  switch (op) {
318  default:
319  case TOKEN_ADD:
320  *answer = lhs + rhs;
321  break;
322 
323  case TOKEN_SUBTRACT:
324  *answer = lhs - rhs;
325  break;
326 
327  case TOKEN_DIVIDE:
328  if (rhs == 0) {
329  RDEBUG("Division by zero!");
330  return false;
331  } else {
332  *answer = lhs / rhs;
333  }
334  break;
335 
336  case TOKEN_REMAINDER:
337  if (rhs == 0) {
338  RDEBUG("Division by zero!");
339  return false;
340  }
341 
342  *answer = lhs % rhs;
343  break;
344 
345  case TOKEN_MULTIPLY:
346  *answer = lhs * rhs;
347  break;
348 
349  case TOKEN_LSHIFT:
350  if (rhs > 63) {
351  RDEBUG("Shift must be less than 63 (was %lld)", (long long int) rhs);
352  return false;
353  }
354 
355  *answer = lhs << rhs;
356  break;
357 
358  case TOKEN_RSHIFT:
359  if (rhs > 63) {
360  RDEBUG("Shift must be less than 63 (was %lld)", (long long int) rhs);
361  return false;
362  }
363 
364  *answer = lhs >> rhs;
365  break;
366 
367  case TOKEN_AND:
368  *answer = lhs & rhs;
369  break;
370 
371  case TOKEN_OR:
372  *answer = lhs | rhs;
373  break;
374 
375  case TOKEN_POWER:
376  if (rhs > 63) {
377  REDEBUG("Exponent must be between 0-63 (was %lld)", (long long int) rhs);
378  return false;
379  }
380 
381  if (lhs > 65535) {
382  REDEBUG("Base must be between 0-65535 (was %lld)", (long long int) lhs);
383  return false;
384  }
385 
386  *answer = fr_pow(lhs, rhs);
387  break;
388  }
389 
390  return true;
391 }
392 
393 static bool get_operator(REQUEST *request, char const **string, expr_token_t *op)
394 {
395  int i;
396  char const *p = *string;
397 
398  /*
399  * All tokens are one character.
400  */
401  for (i = 0; map[i].token != TOKEN_LAST; i++) {
402  if (*p == map[i].op) {
403  *op = map[i].token;
404  *string = p + 1;
405  return true;
406  }
407  }
408 
409  if ((p[0] == '<') && (p[1] == '<')) {
410  *op = TOKEN_LSHIFT;
411  *string = p + 2;
412  return true;
413  }
414 
415  if ((p[0] == '>') && (p[1] == '>')) {
416  *op = TOKEN_RSHIFT;
417  *string = p + 2;
418  return true;
419  }
420 
421  RDEBUG("Expected operator at \"%s\"", p);
422  return false;
423 }
424 
425 
426 static bool get_expression(REQUEST *request, char const **string, int64_t *answer, expr_token_t prev)
427 {
428  int64_t lhs, rhs;
429  char const *p, *op_p;
430  expr_token_t this;
431 
432  p = *string;
433 
434  if (!get_number(request, &p, &lhs)) return false;
435 
436 redo:
437  while (isspace((int) *p)) p++;
438 
439  /*
440  * A number by itself is OK.
441  */
442  if (!*p || (*p == ')')) {
443  *answer = lhs;
444  *string = p;
445  return true;
446  }
447 
448  /*
449  * Peek at the operator.
450  */
451  op_p = p;
452  if (!get_operator(request, &p, &this)) return false;
453 
454  /*
455  * a + b + c ... = (a + b) + c ...
456  * a * b + c ... = (a * b) + c ...
457  *
458  * Feed the current number to the caller, who will take
459  * care of continuing.
460  */
461  if (precedence[this] <= precedence[prev]) {
462  *answer = lhs;
463  *string = op_p;
464  return true;
465  }
466 
467  /*
468  * a + b * c ... = a + (b * c) ...
469  */
470  if (!get_expression(request, &p, &rhs, this)) return false;
471 
472  if (!calc_result(request, lhs, this, rhs, answer)) return false;
473 
474  /*
475  * There may be more to calculate. The answer we
476  * calculated here is now the LHS of the lower priority
477  * operation which follows the current expression. e.g.
478  *
479  * a * b + c ... = (a * b) + c ...
480  * = d + c ...
481  */
482  lhs = *answer;
483  goto redo;
484 }
485 
486 /*
487  * Do xlat of strings!
488  */
489 static ssize_t expr_xlat(char **out, size_t outlen,
490  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
491  REQUEST *request, char const *fmt)
492 {
493  int64_t result;
494  char const *p;
495 
496  p = fmt;
497 
498  if (!get_expression(request, &p, &result, TOKEN_NONE)) {
499  return -1;
500  }
501 
502  if (*p) {
503  RDEBUG("Invalid text after expression: %s", p);
504  return -1;
505  }
506 
507  snprintf(*out, outlen, "%lld", (long long int) result);
508  return strlen(*out);
509 }
510 
511 /** Generate a random integer value
512  *
513  */
514 static ssize_t rand_xlat(char **out, size_t outlen,
515  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
516  UNUSED REQUEST *request, char const *fmt)
517 {
518  int64_t result;
519 
520  result = atoi(fmt);
521 
522  /*
523  * Too small or too big.
524  */
525  if (result <= 0) return -1;
526  if (result >= (1 << 30)) result = (1 << 30);
527 
528  result *= fr_rand(); /* 0..2^32-1 */
529  result >>= 32;
530 
531  snprintf(*out, outlen, "%ld", (long int) result);
532  return strlen(*out);
533 }
534 
535 /** Generate a string of random chars
536  *
537  * Build strings of random chars, useful for generating tokens and passcodes
538  * Format similar to String::Random.
539  */
540 static ssize_t randstr_xlat(char **out, size_t outlen,
541  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
542  UNUSED REQUEST *request, char const *fmt)
543 {
544  char const *p;
545  char *out_p = *out;
546  unsigned int result;
547  unsigned int number;
548  size_t freespace = outlen;
549 
550  if (outlen <= 1) return 0;
551 
552  p = fmt;
553  while (*p && (--freespace > 0)) {
554  number = 0;
555 
556  /*
557  * Modifiers are polite.
558  *
559  * But we limit it to 100, because we don't want
560  * utter stupidity.
561  */
562  while (isdigit((int) *p)) {
563  if (number >= 100) {
564  p++;
565  continue;
566  }
567 
568  number *= 10;
569  number += *p - '0';
570  p++;
571  }
572 
573  redo:
574  result = fr_rand();
575 
576  switch (*p) {
577  /*
578  * Lowercase letters
579  */
580  case 'c':
581  *out_p++ = 'a' + (result % 26);
582  break;
583 
584  /*
585  * Uppercase letters
586  */
587  case 'C':
588  *out_p++ = 'A' + (result % 26);
589  break;
590 
591  /*
592  * Numbers
593  */
594  case 'n':
595  *out_p++ = '0' + (result % 10);
596  break;
597 
598  /*
599  * Alpha numeric
600  */
601  case 'a':
602  *out_p++ = randstr_salt[result % (sizeof(randstr_salt) - 3)];
603  break;
604 
605  /*
606  * Punctuation
607  */
608  case '!':
609  *out_p++ = randstr_punc[result % (sizeof(randstr_punc) - 1)];
610  break;
611 
612  /*
613  * Alpa numeric + punctuation
614  */
615  case '.':
616  *out_p++ = '!' + (result % 95);
617  break;
618 
619  /*
620  * Alpha numeric + salt chars './'
621  */
622  case 's':
623  *out_p++ = randstr_salt[result % (sizeof(randstr_salt) - 1)];
624  break;
625 
626  /*
627  * Chars suitable for One Time Password tokens.
628  * Alpha numeric with easily confused char pairs removed.
629  */
630  case 'o':
631  *out_p++ = randstr_otp[result % (sizeof(randstr_otp) - 1)];
632  break;
633 
634  /*
635  * Binary data as hexits (we don't really support
636  * non printable chars).
637  */
638  case 'h':
639  if (freespace < 2) {
640  break;
641  }
642 
643  snprintf(out_p, 3, "%02x", result % 256);
644 
645  /* Already decremented */
646  freespace -= 1;
647  out_p += 2;
648  break;
649 
650  /*
651  * Binary data with uppercase hexits
652  */
653  case 'H':
654  if (freespace < 2) {
655  break;
656  }
657 
658  snprintf(out_p, 3, "%02X", result % 256);
659 
660  /* Already decremented */
661  freespace -= 1;
662  out_p += 2;
663  break;
664 
665  default:
666  ERROR("rlm_expr: invalid character class '%c'", *p);
667 
668  return -1;
669  }
670 
671  if (number > 0) {
672  number--;
673  goto redo;
674  }
675 
676  p++;
677  }
678 
679  *out_p++ = '\0';
680 
681  return outlen - freespace;
682 }
683 
684 /** URLencode special characters
685  *
686  * Example: "%{urlquote:http://example.org/}" == "http%3A%47%47example.org%47"
687  */
688 static ssize_t urlquote_xlat(char **out, size_t outlen,
689  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
690  UNUSED REQUEST *request, char const *fmt)
691 {
692  char const *p;
693  char *out_p = *out;
694  size_t freespace = outlen;
695 
696  if (outlen <= 1) return 0;
697 
698  p = fmt;
699  while (*p && (--freespace > 0)) {
700  if (isalnum(*p)) {
701  *out_p++ = *p++;
702  continue;
703  }
704 
705  switch (*p) {
706  case '-':
707  case '_':
708  case '.':
709  case '~':
710  *out_p++ = *p++;
711  break;
712 
713  default:
714  if (freespace < 3)
715  break;
716 
717  /* MUST be upper case hex to be compliant */
718  snprintf(out_p, 4, "%%%02X", (uint8_t) *p++); /* %XX */
719 
720  /* Already decremented */
721  freespace -= 2;
722  out_p += 3;
723  }
724  }
725 
726  *out_p = '\0';
727 
728  return outlen - freespace;
729 }
730 
731 /** URLdecode special characters
732  *
733  * Example: "%{urlunquote:http%%3A%%47%%47example.org%%47}" == "http://example.org/"
734  *
735  * Remember to escape % with %% in strings, else xlat will try to parse it.
736  */
737 static ssize_t urlunquote_xlat(char **out, size_t outlen,
738  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
739  REQUEST *request, char const *fmt)
740 {
741  char const *p;
742  char *out_p = *out;
743  char *c1, *c2;
744  size_t freespace = outlen;
745 
746  if (outlen <= 1) return 0;
747 
748  p = fmt;
749  while (*p && (--freespace > 0)) {
750  if (*p != '%') {
751  *out_p++ = *p++;
752  continue;
753  }
754  /* Is a % char */
755 
756  /* Don't need \0 check, as it won't be in the hextab */
757  if (!(c1 = memchr(hextab, tolower(*++p), 16)) ||
758  !(c2 = memchr(hextab, tolower(*++p), 16))) {
759  REMARKER(fmt, p - fmt, "Non-hex char in % sequence");
760  return -1;
761  }
762  p++;
763  *out_p++ = ((c1 - hextab) << 4) + (c2 - hextab);
764  }
765 
766  *out_p = '\0';
767 
768  return outlen - freespace;
769 }
770 
771 /** Equivalent to the old safe_characters functionality in rlm_sql but with utf8 support
772  *
773  * @verbatim Example: "%{escape:<img>foo.jpg</img>}" == "=60img=62foo.jpg=60/img=62" @endverbatim
774  */
775 static ssize_t escape_xlat(char **out, size_t outlen,
776  void const *mod_inst, UNUSED void const *xlat_inst,
777  UNUSED REQUEST *request, char const *fmt)
778 {
779  rlm_expr_t const *inst = mod_inst;
780  char const *p = fmt;
781  char *out_p = *out;
782  size_t freespace = outlen;
783 
784  while (p[0]) {
785  int chr_len = 1;
786  int ret = 1; /* -Werror=uninitialized */
787 
788  if (fr_utf8_strchr(&chr_len, inst->allowed_chars, p) == NULL) {
789  /*
790  * '=' 1 + ([hex]{2}) * chr_len)
791  */
792  if (freespace <= (size_t)(1 + (chr_len * 3))) break;
793 
794  switch (chr_len) {
795  case 4:
796  ret = snprintf(out_p, freespace, "=%02X=%02X=%02X=%02X",
797  (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3]);
798  break;
799 
800  case 3:
801  ret = snprintf(out_p, freespace, "=%02X=%02X=%02X",
802  (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2]);
803  break;
804 
805  case 2:
806  ret = snprintf(out_p, freespace, "=%02X=%02X", (uint8_t)p[0], (uint8_t)p[1]);
807  break;
808 
809  case 1:
810  ret = snprintf(out_p, freespace, "=%02X", (uint8_t)p[0]);
811  break;
812  }
813 
814  p += chr_len;
815  out_p += ret;
816  freespace -= ret;
817  continue;
818  }
819 
820  /*
821  * Only one byte left.
822  */
823  if (freespace <= 1) break;
824 
825  /*
826  * Allowed character (copy whole mb chars at once)
827  */
828  memcpy(out_p, p, chr_len);
829  out_p += chr_len;
830  p += chr_len;
831  freespace -= chr_len;
832  }
833  *out_p = '\0';
834 
835  return outlen - freespace;
836 }
837 
838 /** Equivalent to the old safe_characters functionality in rlm_sql
839  *
840  * @verbatim Example: "%{unescape:=60img=62foo.jpg=60/img=62}" == "<img>foo.jpg</img>" @endverbatim
841  */
842 static ssize_t unescape_xlat(char **out, size_t outlen,
843  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
844  UNUSED REQUEST *request, char const *fmt)
845 {
846  char const *p;
847  char *out_p = *out;
848  char *c1, *c2, c3;
849  size_t freespace = outlen;
850 
851  if (outlen <= 1) return 0;
852 
853  p = fmt;
854  while (*p && (--freespace > 0)) {
855  if (*p != '=') {
856  next:
857 
858  *out_p++ = *p++;
859  continue;
860  }
861 
862  /* Is a = char */
863 
864  if (!(c1 = memchr(hextab, tolower(*(p + 1)), 16)) ||
865  !(c2 = memchr(hextab, tolower(*(p + 2)), 16))) goto next;
866  c3 = ((c1 - hextab) << 4) + (c2 - hextab);
867 
868  *out_p++ = c3;
869  p += 3;
870  }
871 
872  *out_p = '\0';
873 
874  return outlen - freespace;
875 }
876 
877 /** Convert a string to lowercase
878  *
879  * Example: "%{tolower:Bar}" == "bar"
880  *
881  * Probably only works for ASCII
882  */
883 static ssize_t lc_xlat(char **out, size_t outlen,
884  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
885  UNUSED REQUEST *request, char const *fmt)
886 {
887  char *q;
888  char const *p;
889 
890  if (outlen <= 1) return 0;
891 
892  for (p = fmt, q = *out; *p != '\0'; p++, outlen--) {
893  if (outlen <= 1) break;
894 
895  *(q++) = tolower((int) *p);
896  }
897 
898  *q = '\0';
899 
900  return strlen(*out);
901 }
902 
903 /** Convert a string to uppercase
904  *
905  * Example: "%{toupper:Foo}" == "FOO"
906  *
907  * Probably only works for ASCII
908  */
909 static ssize_t uc_xlat(char **out, size_t outlen,
910  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
911  UNUSED REQUEST *request, char const *fmt)
912 {
913  char *q;
914  char const *p;
915 
916  if (outlen <= 1) return 0;
917 
918  for (p = fmt, q = *out; *p != '\0'; p++, outlen--) {
919  if (outlen <= 1) break;
920 
921  *(q++) = toupper((int) *p);
922  }
923 
924  *q = '\0';
925 
926  return strlen(*out);
927 }
928 
929 /** Calculate the MD5 hash of a string or attribute.
930  *
931  * Example: "%{md5:foo}" == "acbd18db4cc2f85cedef654fccc4a4d8"
932  */
933 static ssize_t md5_xlat(char **out, size_t outlen,
934  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
935  REQUEST *request, char const *fmt)
936 {
937  uint8_t digest[16];
938  ssize_t i, len, inlen;
939  uint8_t const *p;
940  FR_MD5_CTX ctx;
941 
942  inlen = xlat_fmt_to_ref(&p, request, fmt);
943  if (inlen < 0) return -1;
944 
945  fr_md5_init(&ctx);
946  fr_md5_update(&ctx, p, inlen);
947  fr_md5_final(digest, &ctx);
948 
949  /*
950  * Each digest octet takes two hex digits, plus one for
951  * the terminating NUL.
952  */
953  len = (outlen / 2) - 1;
954  if (len > 16) len = 16;
955 
956  for (i = 0; i < len; i++) snprintf((*out) + (i * 2), 3, "%02x", digest[i]);
957 
958  return strlen(*out);
959 }
960 
961 /** Calculate the SHA1 hash of a string or attribute.
962  *
963  * Example: "%{sha1:foo}" == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
964  */
965 static ssize_t sha1_xlat(char **out, size_t outlen,
966  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
967  REQUEST *request, char const *fmt)
968 {
969  uint8_t digest[20];
970  ssize_t i, len, inlen;
971  uint8_t const *p;
972  fr_sha1_ctx ctx;
973 
974  inlen = xlat_fmt_to_ref(&p, request, fmt);
975  if (inlen < 0) return -1;
976 
977  fr_sha1_init(&ctx);
978  fr_sha1_update(&ctx, p, inlen);
979  fr_sha1_final(digest, &ctx);
980 
981  /*
982  * Each digest octet takes two hex digits, plus one for
983  * the terminating NUL. SHA1 is 160 bits (20 bytes)
984  */
985  len = (outlen / 2) - 1;
986  if (len > 20) len = 20;
987 
988  for (i = 0; i < len; i++) snprintf((*out) + (i * 2), 3, "%02x", digest[i]);
989 
990  return strlen(*out);
991 }
992 
993 /** Calculate any digest supported by OpenSSL EVP_MD
994  *
995  * Example: "%{sha256:foo}" == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
996  */
997 #ifdef HAVE_OPENSSL_EVP_H
998 static ssize_t evp_md_xlat(char **out, size_t outlen,
999  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
1000  REQUEST *request, char const *fmt, EVP_MD const *md)
1001 {
1002  uint8_t digest[EVP_MAX_MD_SIZE];
1003  unsigned int digestlen, i, len;
1004  ssize_t inlen;
1005  uint8_t const *p;
1006 
1007  EVP_MD_CTX *ctx;
1008 
1009  inlen = xlat_fmt_to_ref(&p, request, fmt);
1010  if (inlen < 0) return -1;
1011 
1012  ctx = EVP_MD_CTX_create();
1013  EVP_DigestInit_ex(ctx, md, NULL);
1014  EVP_DigestUpdate(ctx, p, inlen);
1015  EVP_DigestFinal_ex(ctx, digest, &digestlen);
1016  EVP_MD_CTX_destroy(ctx);
1017 
1018  /*
1019  * Each digest octet takes two hex digits, plus one for
1020  * the terminating NUL.
1021  */
1022  len = (outlen / 2) - 1;
1023  if (len > digestlen) len = digestlen;
1024 
1025  for (i = 0; i < len; i++) snprintf((*out) + (i * 2), 3, "%02x", digest[i]);
1026 
1027  return strlen(*out);
1028 }
1029 
1030 # define EVP_MD_XLAT(_md) \
1031 static ssize_t _md##_xlat(char **out, size_t outlen,\
1032  void const *mod_inst, void const *xlat_inst,\
1033  REQUEST *request, char const *fmt)\
1034 {\
1035  return evp_md_xlat(out, outlen, mod_inst, xlat_inst, request, fmt, EVP_##_md());\
1036 }
1037 
1038 EVP_MD_XLAT(sha256)
1039 EVP_MD_XLAT(sha512)
1040 #endif
1041 
1042 /** Generate the HMAC-MD5 of a string or attribute
1043  *
1044  * Example: "%{hmacmd5:foo bar}" == "Zm9v"
1045  */
1046 static ssize_t hmac_md5_xlat(char **out, size_t outlen,
1047  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
1048  REQUEST *request, char const *fmt)
1049 {
1050  uint8_t const *data, *key;
1051  char const *p;
1052  ssize_t data_len, key_len;
1053  uint8_t digest[MD5_DIGEST_LENGTH];
1054  char data_ref[256];
1055 
1056  if (outlen <= (sizeof(digest) * 2)) {
1057  REDEBUG("Insufficient space to write digest, needed %zu bytes, have %zu bytes",
1058  (sizeof(digest) * 2) + 1, outlen);
1059  return -1;
1060  }
1061 
1062  p = strchr(fmt, ' ');
1063  if (!p) {
1064  REDEBUG("HMAC requires exactly two arguments (&data &key)");
1065  return -1;
1066  }
1067 
1068  if ((size_t)(p - fmt) >= sizeof(data_ref)) {
1069  REDEBUG("Insufficient space to store HMAC input data, needed %zu bytes, have %zu bytes",
1070  (p - fmt) + 1, sizeof(data_ref));
1071 
1072  return -1;
1073  }
1074  strlcpy(data_ref, fmt, (p - fmt) + 1);
1075 
1076  data_len = xlat_fmt_to_ref(&data, request, data_ref);
1077  if (data_len < 0) return -1;
1078 
1079  while (isspace(*p) && p++);
1080 
1081  key_len = xlat_fmt_to_ref(&key, request, p);
1082  if (key_len < 0) return -1;
1083 
1084  fr_hmac_md5(digest, data, data_len, key, key_len);
1085 
1086  return fr_bin2hex(*out, digest, sizeof(digest));
1087 }
1088 
1089 /** Generate the HMAC-SHA1 of a string or attribute
1090  *
1091  * Example: "%{hmacsha1:foo bar}" == "Zm9v"
1092  */
1093 static ssize_t hmac_sha1_xlat(char **out, size_t outlen,
1094  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
1095  REQUEST *request, char const *fmt)
1096 {
1097  uint8_t const *data, *key;
1098  char const *p;
1099  ssize_t data_len, key_len;
1100  uint8_t digest[SHA1_DIGEST_LENGTH];
1101  char data_ref[256];
1102 
1103  if (outlen <= (sizeof(digest) * 2)) {
1104  REDEBUG("Insufficient space to write digest, needed %zu bytes, have %zu bytes",
1105  (sizeof(digest) * 2) + 1, outlen);
1106  return -1;
1107  }
1108 
1109  p = strchr(fmt, ' ');
1110  if (!p) {
1111  REDEBUG("HMAC requires exactly two arguments (&data &key)");
1112  return -1;
1113  }
1114 
1115  if ((size_t)(p - fmt) >= sizeof(data_ref)) {
1116  REDEBUG("Insufficient space to store HMAC input data, needed %zu bytes, have %zu bytes",
1117  (p - fmt) + 1, sizeof(data_ref));
1118 
1119  return -1;
1120  }
1121  strlcpy(data_ref, fmt, (p - fmt) + 1);
1122 
1123  data_len = xlat_fmt_to_ref(&data, request, data_ref);
1124  if (data_len < 0) return -1;
1125 
1126  while (isspace(*p) && p++);
1127 
1128  key_len = xlat_fmt_to_ref(&key, request, p);
1129  if (key_len < 0) return -1;
1130 
1131  fr_hmac_sha1(digest, data, data_len, key, key_len);
1132 
1133  return fr_bin2hex(*out, digest, sizeof(digest));
1134 }
1135 
1136 /** Encode attributes as a series of string attribute/value pairs
1137  *
1138  * This is intended to serialize one or more attributes as a comma
1139  * delimited string.
1140  *
1141  * Example: "%{pairs:request:}" == "User-Name = 'foo', User-Password = 'bar'"
1142  */
1143 static ssize_t pairs_xlat(char **out, size_t outlen,
1144  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
1145  REQUEST *request, char const *fmt)
1146 {
1147  vp_tmpl_t vpt;
1148  vp_cursor_t cursor;
1149  size_t len, freespace = outlen;
1150  char *p = *out;
1151 
1152  VALUE_PAIR *vp;
1153 
1154  if (tmpl_from_attr_str(&vpt, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
1155  REDEBUG("%s", fr_strerror());
1156  return -1;
1157  }
1158 
1159  for (vp = tmpl_cursor_init(NULL, &cursor, request, &vpt);
1160  vp;
1161  vp = tmpl_cursor_next(&cursor, &vpt)) {
1162  FR_TOKEN op = vp->op;
1163 
1164  vp->op = T_OP_EQ;
1165  len = fr_pair_snprint(p, freespace, vp);
1166  vp->op = op;
1167 
1168  if (is_truncated(len, freespace)) {
1169  no_space:
1170  REDEBUG("Insufficient space to store pair string, needed %zu bytes have %zu bytes",
1171  (p - *out) + len, outlen);
1172  return -1;
1173  }
1174  p += len;
1175  freespace -= len;
1176 
1177  if (freespace < 2) {
1178  len = 2;
1179  goto no_space;
1180  }
1181 
1182  *p++ = ',';
1183  *p++ = ' ';
1184  freespace -= 2;
1185  }
1186 
1187  /* Trim the trailing ', ' */
1188  if (p != *out) p -= 2;
1189  *p = '\0';
1190 
1191  return (p - *out);
1192 }
1193 
1194 /** Encode string or attribute as base64
1195  *
1196  * Example: "%{base64:foo}" == "Zm9v"
1197  */
1198 static ssize_t base64_xlat(char **out, size_t outlen,
1199  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
1200  REQUEST *request, char const *fmt)
1201 {
1202  ssize_t inlen;
1203  uint8_t const *p;
1204 
1205  inlen = xlat_fmt_to_ref(&p, request, fmt);
1206  if (inlen < 0) {
1207  return -1;
1208  }
1209 
1210  /*
1211  * We can accurately calculate the length of the output string
1212  * if it's larger than outlen, the output would be useless so abort.
1213  */
1214  if ((inlen < 0) || ((FR_BASE64_ENC_LENGTH(inlen) + 1) > (ssize_t) outlen)) {
1215  REDEBUG("xlat failed");
1216  return -1;
1217  }
1218 
1219  return fr_base64_encode(*out, outlen, p, inlen);
1220 }
1221 
1222 /** Convert base64 to hex
1223  *
1224  * Example: "%{base64tohex:Zm9v}" == "666f6f"
1225  */
1226 static ssize_t base64_to_hex_xlat(char **out, size_t outlen,
1227  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
1228  REQUEST *request, char const *fmt)
1229 {
1230  uint8_t decbuf[1024];
1231 
1232  ssize_t declen;
1233  ssize_t len = strlen(fmt);
1234 
1235  declen = fr_base64_decode(decbuf, sizeof(decbuf), fmt, len);
1236  if (declen < 0) {
1237  REDEBUG("Base64 string invalid");
1238  return -1;
1239  }
1240 
1241  if ((size_t)((declen * 2) + 1) > outlen) {
1242  REDEBUG("Base64 conversion failed, output buffer exhausted, needed %zd bytes, have %zd bytes",
1243  (declen * 2) + 1, outlen);
1244  return -1;
1245  }
1246 
1247  return fr_bin2hex(*out, decbuf, declen);
1248 }
1249 
1250 /** Split an attribute into multiple new attributes based on a delimiter
1251  *
1252  * @todo should support multibyte delimiter for string types.
1253  *
1254  * Example: "%{explode:&ref <delim>}"
1255  */
1256 static ssize_t explode_xlat(char **out, size_t outlen,
1257  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
1258  REQUEST *request, char const *fmt)
1259 {
1260  vp_tmpl_t vpt;
1261  vp_cursor_t cursor, to_merge;
1262  VALUE_PAIR *vp, *head = NULL;
1263  ssize_t slen;
1264  int count = 0;
1265  char const *p = fmt;
1266  char delim;
1267 
1268  /*
1269  * Trim whitespace
1270  */
1271  while (isspace(*p) && p++);
1272 
1273  slen = tmpl_from_attr_substr(&vpt, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false);
1274  if (slen <= 0) {
1275  REDEBUG("%s", fr_strerror());
1276  return -1;
1277  }
1278 
1279  p += slen;
1280 
1281  if (*p++ != ' ') {
1282  arg_error:
1283  REDEBUG("explode needs exactly two arguments: &ref <delim>");
1284  return -1;
1285  }
1286 
1287  if (*p == '\0') goto arg_error;
1288 
1289  delim = *p;
1290 
1291  fr_cursor_init(&to_merge, &head);
1292 
1293  for (vp = tmpl_cursor_init(NULL, &cursor, request, &vpt);
1294  vp;
1295  vp = tmpl_cursor_next(&cursor, &vpt)) {
1296  VALUE_PAIR *new;
1297  char const *end;
1298  char const *q;
1299 
1300  /*
1301  * This can theoretically operate on lists too
1302  * so we need to check the type of each attribute.
1303  */
1304  switch (vp->da->type) {
1305  case PW_TYPE_OCTETS:
1306  case PW_TYPE_STRING:
1307  break;
1308 
1309  default:
1310  continue;
1311  }
1312 
1313  p = vp->data.ptr;
1314  end = p + vp->vp_length;
1315  while (p < end) {
1316  q = memchr(p, delim, end - p);
1317  if (!q) {
1318  /* Delimiter not present in attribute */
1319  if (p == vp->data.ptr) goto next;
1320  q = end;
1321  }
1322 
1323  /* Skip zero length */
1324  if (q == p) {
1325  p = q + 1;
1326  continue;
1327  }
1328 
1329  new = fr_pair_afrom_da(talloc_parent(vp), vp->da);
1330  if (!new) {
1331  fr_pair_list_free(&head);
1332  return -1;
1333  }
1334  new->tag = vp->tag;
1335 
1336  switch (vp->da->type) {
1337  case PW_TYPE_OCTETS:
1338  {
1339  uint8_t *buff;
1340 
1341  buff = talloc_array(new, uint8_t, q - p);
1342  memcpy(buff, p, q - p);
1343  fr_pair_value_memsteal(new, buff);
1344  }
1345  break;
1346 
1347  case PW_TYPE_STRING:
1348  {
1349  char *buff;
1350 
1351  buff = talloc_array(new, char, (q - p) + 1);
1352  memcpy(buff, p, q - p);
1353  buff[q - p] = '\0';
1354  fr_pair_value_strsteal(new, (char *)buff);
1355  }
1356  break;
1357 
1358  default:
1359  rad_assert(0);
1360  }
1361 
1362  fr_cursor_insert(&to_merge, new);
1363 
1364  p = q + 1; /* next */
1365 
1366  count++;
1367  }
1368 
1369  /*
1370  * Remove the unexploded version
1371  */
1372  vp = fr_cursor_remove(&cursor);
1373  talloc_free(vp);
1374 
1375  next:
1376  continue; /* Apparently goto labels aren't allowed at the end of loops? */
1377  }
1378 
1379  fr_cursor_merge(&cursor, head);
1380 
1381  return snprintf(*out, outlen, "%i", count);
1382 }
1383 
1384 /** Calculate number of seconds until the next n hour(s), day(s), week(s), year(s).
1385  *
1386  * For example, if it were 16:18 %{nexttime:1h} would expand to 2520.
1387  *
1388  * The envisaged usage for this function is to limit sessions so that they don't
1389  * cross billing periods. The output of the xlat should be combined with %{rand:} to create
1390  * some jitter, unless the desired effect is every subscriber on the network
1391  * re-authenticating at the same time.
1392  */
1393 static ssize_t next_time_xlat(char **out, size_t outlen,
1394  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
1395  REQUEST *request, char const *fmt)
1396 {
1397  long num;
1398 
1399  char const *p;
1400  char *q;
1401  time_t now;
1402  struct tm *local, local_buff;
1403 
1404  now = time(NULL);
1405  local = localtime_r(&now, &local_buff);
1406 
1407  p = fmt;
1408 
1409  num = strtoul(p, &q, 10);
1410  if (!q || *q == '\0') {
1411  REDEBUG("nexttime: <int> must be followed by period specifier (h|d|w|m|y)");
1412  return -1;
1413  }
1414 
1415  if (p == q) {
1416  num = 1;
1417  } else {
1418  p += q - p;
1419  }
1420 
1421  local->tm_sec = 0;
1422  local->tm_min = 0;
1423 
1424  switch (*p) {
1425  case 'h':
1426  local->tm_hour += num;
1427  break;
1428 
1429  case 'd':
1430  local->tm_hour = 0;
1431  local->tm_mday += num;
1432  break;
1433 
1434  case 'w':
1435  local->tm_hour = 0;
1436  local->tm_mday += (7 - local->tm_wday) + (7 * (num-1));
1437  break;
1438 
1439  case 'm':
1440  local->tm_hour = 0;
1441  local->tm_mday = 1;
1442  local->tm_mon += num;
1443  break;
1444 
1445  case 'y':
1446  local->tm_hour = 0;
1447  local->tm_mday = 1;
1448  local->tm_mon = 0;
1449  local->tm_year += num;
1450  break;
1451 
1452  default:
1453  REDEBUG("nexttime: Invalid period specifier '%c', must be h|d|w|m|y", *p);
1454  return -1;
1455  }
1456 
1457  return snprintf(*out, outlen, "%" PRIu64, (uint64_t)(mktime(local) - now));
1458 }
1459 
1460 
1461 /*
1462  * Parse the 3 arguments to lpad / rpad.
1463  */
1464 static bool parse_pad(REQUEST *request, char const *fmt,
1465  vp_tmpl_t **pvpt, size_t *plength,
1466  char *fill)
1467 {
1468  ssize_t slen;
1469  unsigned long length;
1470  char const *p;
1471  char *end;
1472  vp_tmpl_t *vpt;
1473 
1474  *fill = ' '; /* the default */
1475 
1476  p = fmt;
1477  while (isspace((int) *p)) p++;
1478 
1479  if (*p != '&') {
1480  RDEBUG("First argument must be an attribute reference");
1481  return false;
1482  }
1483 
1484  vpt = talloc(request, vp_tmpl_t);
1485  if (!vpt) return false;
1486 
1487  slen = tmpl_from_attr_substr(vpt, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false);
1488  if (slen <= 0) {
1489  talloc_free(vpt);
1490  RDEBUG("Failed expanding string: %s", fr_strerror());
1491  return false;
1492  }
1493 
1494  p = fmt + slen;
1495 
1496  while (isspace((int) *p)) p++;
1497 
1498  length = strtoul(p, &end, 10);
1499  if ((length == ULONG_MAX) || (length > 8192)) {
1500  talloc_free(vpt);
1501  RDEBUG("Invalid length found at: %s", p);
1502  return false;
1503  }
1504 
1505  p += (end - p);
1506 
1507  /*
1508  * The fill character is optional.
1509  *
1510  * But we must have a space after the previous number,
1511  * and we must have only ONE fill character.
1512  */
1513  if (*p) {
1514  if (!isspace(*p)) {
1515  talloc_free(vpt);
1516  RDEBUG("Invalid text found at: %s", p);
1517  return false;
1518  }
1519 
1520  while (isspace((int) *p)) p++;
1521 
1522  if (p[1] != '\0') {
1523  talloc_free(vpt);
1524  RDEBUG("Invalid text found at: %s", p);
1525  return false;
1526  }
1527 
1528  *fill = *p;
1529  }
1530 
1531  *pvpt = vpt;
1532  *plength = length;
1533 
1534  return true;
1535 }
1536 
1537 
1538 /** left pad a string
1539  *
1540  * %{lpad:&Attribute-Name length 'x'}
1541  */
1542 static ssize_t lpad_xlat(char **out, size_t outlen,
1543  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
1544  REQUEST *request, char const *fmt)
1545 {
1546  char fill;
1547  size_t pad;
1548  ssize_t len;
1549  vp_tmpl_t *vpt;
1550 
1551  if (!parse_pad(request, fmt, &vpt, &pad, &fill)) return 0;
1552 
1553  if (outlen <= pad) {
1554  RWARN("Output is too short! Result will be truncated");
1555  pad = outlen - 1;
1556  }
1557 
1558  /*
1559  * Print the attribute (left justified). If it's too
1560  * big, we're done.
1561  */
1562  len = tmpl_expand(NULL, *out, pad + 1, request, vpt, NULL, NULL);
1563  if (len <= 0) return 0;
1564 
1565  if ((size_t) len >= pad) return pad;
1566 
1567  /*
1568  * We have to shift the string to the right, and pad with
1569  * "fill" characters.
1570  */
1571  memmove((*out) + (pad - len), *out, len + 1);
1572  memset(*out, fill, pad - len);
1573 
1574  return pad;
1575 }
1576 
1577 
1578 /** right pad a string
1579  *
1580  * %{rpad:&Attribute-Name length 'x'}
1581  */
1582 static ssize_t rpad_xlat(char **out, size_t outlen,
1583  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
1584  REQUEST *request, char const *fmt)
1585 {
1586  char fill;
1587  size_t pad;
1588  ssize_t len;
1589  vp_tmpl_t *vpt;
1590 
1591  if (!parse_pad(request, fmt, &vpt, &pad, &fill)) return 0;
1592 
1593  if (outlen <= pad) {
1594  RWARN("Output is too short! Result will be truncated");
1595  pad = outlen - 1;
1596  }
1597 
1598  /*
1599  * Print the attribute (left justified). If it's too
1600  * big, we're done.
1601  */
1602  len = tmpl_expand(NULL, *out, pad + 1, request, vpt, NULL, NULL);
1603  if (len <= 0) return 0;
1604 
1605  if ((size_t) len >= pad) return pad;
1606 
1607  /*
1608  * We have to pad with "fill" characters.
1609  */
1610  memset((*out) + len, fill, pad - len);
1611  (*out)[pad] = '\0';
1612 
1613  return pad;
1614 }
1615 
1616 
1617 /*
1618  * Do any per-module initialization that is separate to each
1619  * configured instance of the module. e.g. set up connections
1620  * to external databases, read configuration files, set up
1621  * dictionary entries, etc.
1622  *
1623  * If configuration information is given in the config section
1624  * that must be referenced in later calls, store a handle to it
1625  * in *instance otherwise put a null pointer there.
1626  */
1627 static int mod_bootstrap(CONF_SECTION *conf, void *instance)
1628 {
1629  rlm_expr_t *inst = instance;
1630 
1631  inst->xlat_name = cf_section_name2(conf);
1632  if (!inst->xlat_name) {
1633  inst->xlat_name = cf_section_name1(conf);
1634  }
1635 
1636  xlat_register(inst, inst->xlat_name, expr_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1637 
1638  xlat_register(inst, "rand", rand_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1639  xlat_register(inst, "randstr", randstr_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1640  xlat_register(inst, "urlquote", urlquote_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1641  xlat_register(inst, "urlunquote", urlunquote_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1642  xlat_register(inst, "escape", escape_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1643  xlat_register(inst, "unescape", unescape_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1644  xlat_register(inst, "tolower", lc_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1645  xlat_register(inst, "toupper", uc_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1646  xlat_register(inst, "md5", md5_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1647  xlat_register(inst, "sha1", sha1_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1648 #ifdef HAVE_OPENSSL_EVP_H
1649  xlat_register(inst, "sha256", sha256_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1650  xlat_register(inst, "sha512", sha512_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1651 #endif
1652  xlat_register(inst, "hmacmd5", hmac_md5_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1653  xlat_register(inst, "hmacsha1", hmac_sha1_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1654  xlat_register(inst, "pairs", pairs_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1655 
1656  xlat_register(inst, "base64", base64_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1657  xlat_register(inst, "base64tohex", base64_to_hex_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1658 
1659  xlat_register(inst, "explode", explode_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1660 
1661  xlat_register(inst, "nexttime", next_time_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1662  xlat_register(inst, "lpad", lpad_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1663  xlat_register(inst, "rpad", rpad_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
1664 
1665  /*
1666  * Initialize various paircompare functions
1667  */
1668  pair_builtincompare_add(instance);
1669  return 0;
1670 }
1671 
1672 /*
1673  * The module name should be the only globally exported symbol.
1674  * That is, everything else should be 'static'.
1675  *
1676  * If the module needs to temporarily modify it's instantiation
1677  * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
1678  * The server will then take care of ensuring that the module
1679  * is single-threaded.
1680  */
1681 extern module_t rlm_expr;
1682 module_t rlm_expr = {
1684  .name = "expr",
1685  .inst_size = sizeof(rlm_expr_t),
1686  .config = module_config,
1687  .bootstrap = mod_bootstrap,
1688 };
void fr_pair_list_free(VALUE_PAIR **)
Free memory used by a valuepair list.
Definition: pair.c:544
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *data, size_t len)
Definition: sha1.c:106
ssize_t tmpl_expand(char const **out, char *buff, size_t outlen, REQUEST *request, vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
Expand a vp_tmpl_t to a string writing the result to a buffer.
Definition: tmpl.c:1479
char op
Definition: rlm_expr.c:165
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:265
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
expr_token_t
Definition: rlm_expr.c:136
Metadata exported by the module.
Definition: modules.h:134
char const * name
Raw string used to create the template.
Definition: tmpl.h:190
#define RWARN(fmt,...)
Definition: log.h:206
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: radius.c:1621
#define SHA1_DIGEST_LENGTH
Definition: sha1.h:18
#define FR_BASE64_ENC_LENGTH(inlen)
Definition: base64.h:38
static ssize_t sha1_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Calculate the SHA1 hash of a string or attribute.
Definition: rlm_expr.c:965
static ssize_t uc_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, UNUSED REQUEST *request, char const *fmt)
Convert a string to uppercase.
Definition: rlm_expr.c:909
#define REMARKER(_m, _i, _e)
Output string with error marker, showing where format error occurred.
Definition: log.h:306
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
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
int8_t tag
Tag value used to group valuepairs.
Definition: pair.h:121
void fr_md5_init(FR_MD5_CTX *ctx)
Initialise a new MD5 context.
Definition: md5.c:84
#define CONF_PARSER_TERMINATOR
Definition: conffile.h:289
static ssize_t urlquote_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, UNUSED REQUEST *request, char const *fmt)
URLencode special characters.
Definition: rlm_expr.c:688
static char randstr_punc[]
Definition: rlm_expr.c:59
char const * xlat_name
Definition: rlm_expr.c:47
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
Definition: cursor.c:60
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
uint8_t length
Definition: proto_bfd.c:203
#define inst
Definition: token.h:46
static expr_map_t map[]
Definition: rlm_expr.c:169
#define XLAT_DEFAULT_BUF_LEN
Definition: xlat.h:89
ssize_t fr_base64_decode(uint8_t *out, size_t outlen, char const *in, size_t inlen)
Definition: base64.c:251
Defines a CONF_PAIR to C data type mapping.
Definition: conffile.h:267
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
static int64_t fr_pow(int64_t base, int64_t exp)
Calculate powers.
Definition: rlm_expr.c:79
void fr_sha1_init(fr_sha1_ctx *context)
Definition: sha1.c:94
static ssize_t hmac_sha1_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Generate the HMAC-SHA1 of a string or attribute.
Definition: rlm_expr.c:1093
static bool parse_pad(REQUEST *request, char const *fmt, vp_tmpl_t **pvpt, size_t *plength, char *fill)
Definition: rlm_expr.c:1464
void fr_md5_update(FR_MD5_CTX *ctx, uint8_t const *in, size_t inlen) CC_BOUNDED(__string__
#define is_truncated(_ret, _max)
Definition: libradius.h:204
void fr_pair_value_strsteal(VALUE_PAIR *vp, char const *src)
Reparent an allocated char buffer to a VALUE_PAIR.
Definition: pair.c:1955
static ssize_t hmac_md5_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Calculate any digest supported by OpenSSL EVP_MD.
Definition: rlm_expr.c:1046
#define rad_assert(expr)
Definition: rad_assert.h:38
static bool get_expression(REQUEST *request, char const **string, int64_t *answer, expr_token_t prev)
Definition: rlm_expr.c:426
static bool get_number(REQUEST *request, char const **string, int64_t *answer)
Definition: rlm_expr.c:184
static ssize_t explode_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Split an attribute into multiple new attributes based on a delimiter.
Definition: rlm_expr.c:1256
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
static ssize_t rpad_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
right pad a string
Definition: rlm_expr.c:1582
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
int tmpl_find_vp(VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt)
Returns the first VP matching a vp_tmpl_t.
Definition: tmpl.c:2224
void fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *text, size_t text_len, uint8_t const *key, size_t key_len) CC_BOUNDED(__minbytes__
void fr_cursor_merge(vp_cursor_t *cursor, VALUE_PAIR *vp)
Merges multiple VALUE_PAIR into the cursor.
Definition: cursor.c:394
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
void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *vp)
Insert a single VALUE_PAIR at the end of the list.
Definition: cursor.c:321
static bool done
Definition: radclient.c:53
static ssize_t lpad_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
left pad a string
Definition: rlm_expr.c:1542
Attributes in incoming or internally proxied request.
Definition: tmpl.h:82
static bool calc_result(REQUEST *request, int64_t lhs, expr_token_t op, int64_t rhs, int64_t *answer)
Definition: rlm_expr.c:315
static ssize_t pairs_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Encode attributes as a series of string attribute/value pairs.
Definition: rlm_expr.c:1143
static ssize_t base64_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Encode string or attribute as base64.
Definition: rlm_expr.c:1198
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
void fr_sha1_final(uint8_t digest[20], fr_sha1_ctx *context)
Definition: sha1.c:132
USES_APPLE_DEPRECATED_API struct rlm_expr_t rlm_expr_t
static ssize_t escape_xlat(char **out, size_t outlen, void const *mod_inst, UNUSED void const *xlat_inst, UNUSED REQUEST *request, char const *fmt)
Equivalent to the old safe_characters functionality in rlm_sql but with utf8 support.
Definition: rlm_expr.c:775
static int precedence[TOKEN_LAST+1]
Definition: rlm_expr.c:157
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:272
The current request.
Definition: tmpl.h:113
FR_TOKEN op
Operator to use when moving or inserting valuepair into a list.
Definition: pair.h:118
static rs_t * conf
Definition: radsniff.c:46
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
64 Bit unsigned integer.
Definition: radius.h:51
char const * cf_section_name1(CONF_SECTION const *cs)
Definition: conffile.c:3592
char const * fr_utf8_strchr(int *chr_len, char const *str, char const *chr)
Return a pointer to the first UTF8 char in a string.
Definition: print.c:140
static ssize_t urlunquote_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
URLdecode special characters.
Definition: rlm_expr.c:737
#define RDEBUG2(fmt,...)
Definition: log.h:244
static ssize_t base64_to_hex_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Convert base64 to hex.
Definition: rlm_expr.c:1226
uint8_t data[]
Definition: eap_pwd.h:625
static ssize_t md5_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Calculate the MD5 hash of a string or attribute.
Definition: rlm_expr.c:933
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
void fr_pair_value_memsteal(VALUE_PAIR *vp, uint8_t const *src)
Reparent an allocated octet buffer to a VALUE_PAIR.
Definition: pair.c:1933
static int mod_bootstrap(CONF_SECTION *conf, void *instance)
Definition: rlm_expr.c:1627
size_t fr_base64_encode(char *out, size_t outlen, uint8_t const *in, size_t inlen)
Base 64 encode binary data.
Definition: base64.c:44
#define FR_CONF_OFFSET(_n, _t, _s, _f)
Definition: conffile.h:168
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
void pair_builtincompare_add(void *instance)
Definition: paircmp.c:245
static ssize_t randstr_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, UNUSED REQUEST *request, char const *fmt)
Generate a string of random chars.
Definition: rlm_expr.c:540
expr_token_t token
Definition: rlm_expr.c:166
static char const hextab[]
Definition: rlm_expr.c:68
static ssize_t rand_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, UNUSED REQUEST *request, char const *fmt)
Generate a random integer value.
Definition: rlm_expr.c:514
static ssize_t lc_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, UNUSED REQUEST *request, char const *fmt)
Convert a string to lowercase.
Definition: rlm_expr.c:883
void fr_hmac_sha1(uint8_t digest[SHA1_DIGEST_LENGTH], uint8_t const *text, size_t text_len, uint8_t const *key, size_t key_len)
Calculate HMAC using SHA1.
Definition: hmacsha1.c:28
#define REDEBUG(fmt,...)
Definition: log.h:254
module_t rlm_expr
Definition: rlm_expr.c:1682
size_t fr_pair_snprint(char *out, size_t outlen, VALUE_PAIR const *vp)
Print one attribute and value to a string.
Definition: pair.c:2189
static char randstr_salt[]
Definition: rlm_expr.c:60
VALUE_PAIR * fr_cursor_remove(vp_cursor_t *cursor)
Remove the current pair.
Definition: cursor.c:433
enum fr_token FR_TOKEN
void void fr_md5_final(uint8_t out[MD5_DIGEST_LENGTH], FR_MD5_CTX *ctx) CC_BOUNDED(__minbytes__
static ssize_t unescape_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, UNUSED REQUEST *request, char const *fmt)
Equivalent to the old safe_characters functionality in rlm_sql.
Definition: rlm_expr.c:842
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
static char randstr_otp[]
Definition: rlm_expr.c:66
void void MD5_DIGEST_LENGTH
Definition: md5.h:65
char const * allowed_chars
Definition: rlm_expr.c:48
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
String of printable characters.
Definition: radius.h:33
#define RWDEBUG(fmt,...)
Definition: log.h:251
PW_TYPE type
Value type.
Definition: dict.h:80
static ssize_t expr_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Definition: rlm_expr.c:489
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
static const CONF_PARSER module_config[]
Definition: rlm_expr.c:51
#define RCSID(id)
Definition: build.h:135
struct expr_map_t expr_map_t
static bool get_operator(REQUEST *request, char const **string, expr_token_t *op)
Definition: rlm_expr.c:393
#define RDEBUG(fmt,...)
Definition: log.h:243
A source or sink of value data.
Definition: tmpl.h:187
static ssize_t next_time_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Calculate number of seconds until the next n hour(s), day(s), week(s), year(s).
Definition: rlm_expr.c:1393
size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
Convert binary data to a hex string.
Definition: misc.c:254
#define ERROR(fmt,...)
Definition: log.h:145
Raw octets.
Definition: radius.h:38
char const * cf_section_name2(CONF_SECTION const *cs)
Definition: conffile.c:3601
#define USES_APPLE_DEPRECATED_API
Definition: build.h:122
#define RDEBUG3(fmt,...)
Definition: log.h:245
value_data_t data
Definition: pair.h:133