The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
regex.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 /** Wrappers around various regular expression libraries
18  *
19  * @file src/lib/util/regex.c
20  *
21  * @copyright 2014 The FreeRADIUS server project
22  * @copyright 2014 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23  */
24 RCSID("$Id: 21091671974cdbd11e5882a48d64b813fb310662 $")
25 
26 #ifdef HAVE_REGEX
27 
28 #include <freeradius-devel/util/regex.h>
29 #include <freeradius-devel/util/atexit.h>
30 
31 #if defined(HAVE_REGEX_PCRE) || (defined(HAVE_REGEX_PCRE2) && defined(PCRE2_CONFIG_JIT))
32 #ifndef FR_PCRE_JIT_STACK_MIN
33 # define FR_PCRE_JIT_STACK_MIN (128 * 1024)
34 #endif
35 #ifndef FR_PCRE_JIT_STACK_MAX
36 # define FR_PCRE_JIT_STACK_MAX (512 * 1024)
37 #endif
38 #endif
39 
40 /*
41  *######################################
42  *# FUNCTIONS FOR LIBPCRE2 #
43  *######################################
44  */
45 #ifdef HAVE_REGEX_PCRE2
46 /*
47  * Wrapper functions for libpcre2. Much more powerful, and guaranteed
48  * to be binary safe for both patterns and subjects but require
49  * libpcre2.
50  */
51 
52 /** Thread local storage for PCRE2
53  *
54  * Not all this storage is thread local, but it simplifies cleanup if
55  * we bind its lifetime to the thread, and lets us get away with not
56  * having specific init/free functions.
57  */
58 typedef struct {
59  TALLOC_CTX *alloc_ctx; //!< Context used for any allocations.
60  pcre2_general_context *gcontext; //!< General context.
61  pcre2_compile_context *ccontext; //!< Compile context.
62  pcre2_match_context *mcontext; //!< Match context.
63 #ifdef PCRE2_CONFIG_JIT
64  pcre2_jit_stack *jit_stack; //!< Jit stack for executing jit'd patterns.
65  bool do_jit; //!< Whether we have runtime JIT support.
66 #endif
67 } fr_pcre2_tls_t;
68 
69 /** Thread local storage for pcre2
70  *
71  */
72 static _Thread_local fr_pcre2_tls_t *fr_pcre2_tls;
73 
74 /** Talloc wrapper for pcre2 memory allocation
75  *
76  * @param[in] to_alloc How many bytes to alloc.
77  * @param[in] uctx UNUSED.
78  */
79 static void *_pcre2_talloc(PCRE2_SIZE to_alloc, UNUSED void *uctx)
80 {
81  return talloc_array(fr_pcre2_tls->alloc_ctx, uint8_t, to_alloc);
82 }
83 
84 /** Talloc wrapper for pcre2 memory freeing
85  *
86  * @param[in] to_free Memory to free.
87  * @param[in] uctx UNUSED.
88  */
89 static void _pcre2_talloc_free(void *to_free, UNUSED void *uctx)
90 {
91  talloc_free(to_free);
92 }
93 
94 /** Free thread local data
95  *
96  * @param[in] tls Thread local data to free.
97  */
98 static int _pcre2_tls_free(fr_pcre2_tls_t *tls)
99 {
100  if (tls->gcontext) pcre2_general_context_free(tls->gcontext);
101  if (tls->ccontext) pcre2_compile_context_free(tls->ccontext);
102  if (tls->mcontext) pcre2_match_context_free(tls->mcontext);
103 #ifdef PCRE2_CONFIG_JIT
104  if (tls->jit_stack) pcre2_jit_stack_free(tls->jit_stack);
105 #endif
106 
107  return 0;
108 }
109 
110 static int _pcre2_tls_free_on_exit(void *arg)
111 {
112  return talloc_free(arg);
113 }
114 
115 /** Thread local init for pcre2
116  *
117  */
118 static int fr_pcre2_tls_init(void)
119 {
120  fr_pcre2_tls_t *tls;
121 
122  if (unlikely(fr_pcre2_tls != NULL)) return 0;
123 
124  fr_pcre2_tls = tls = talloc_zero(NULL, fr_pcre2_tls_t);
125  if (!tls) return -1;
126  talloc_set_destructor(tls, _pcre2_tls_free);
127 
128  tls->gcontext = pcre2_general_context_create(_pcre2_talloc, _pcre2_talloc_free, NULL);
129  if (!tls->gcontext) {
130  fr_strerror_const("Failed allocating general context");
131  return -1;
132  }
133 
134  tls->ccontext = pcre2_compile_context_create(tls->gcontext);
135  if (!tls->ccontext) {
136  fr_strerror_const("Failed allocating compile context");
137  error:
138  fr_pcre2_tls = NULL;
139  _pcre2_tls_free(tls);
140  return -1;
141  }
142 
143  tls->mcontext = pcre2_match_context_create(tls->gcontext);
144  if (!tls->mcontext) {
145  fr_strerror_const("Failed allocating match context");
146  goto error;
147  }
148 
149 #ifdef PCRE2_CONFIG_JIT
150  pcre2_config(PCRE2_CONFIG_JIT, &tls->do_jit);
151  if (tls->do_jit) {
152  tls->jit_stack = pcre2_jit_stack_create(FR_PCRE_JIT_STACK_MIN, FR_PCRE_JIT_STACK_MAX, tls->gcontext);
153  if (!tls->jit_stack) {
154  fr_strerror_const("Failed allocating JIT stack");
155  goto error;
156  }
157  pcre2_jit_stack_assign(tls->mcontext, NULL, tls->jit_stack);
158  }
159 #endif
160 
161  /*
162  * Free on thread exit
163  */
164  fr_atexit_thread_local(fr_pcre2_tls, _pcre2_tls_free_on_exit, tls);
165  fr_pcre2_tls = tls; /* Assign to thread local storage */
166 
167  return 0;
168 }
169 
170 /** Free regex_t structure
171  *
172  * Calls libpcre specific free functions for the expression and study.
173  *
174  * @param preg to free.
175  */
176 static int _regex_free(regex_t *preg)
177 {
178  if (preg->compiled) pcre2_code_free(preg->compiled);
179 
180  return 0;
181 }
182 
183 /** Wrapper around pcre2_compile
184  *
185  * Allows the rest of the code to do compilations using one function signature.
186  *
187  * @note Compiled expression must be freed with talloc_free.
188  *
189  * @param[out] out Where to write out a pointer to the structure containing
190  * the compiled expression.
191  * @param[in] pattern to compile.
192  * @param[in] len of pattern.
193  * @param[in] flags controlling matching. May be NULL.
194  * @param[in] subcaptures Whether to compile the regular expression to store subcapture
195  * data.
196  * @param[in] runtime If false run the pattern through the PCRE JIT (if available)
197  * to convert it to machine code. This trades startup time (longer)
198  * for runtime performance (better).
199  * @return
200  * - >= 1 on success.
201  * - <= 0 on error. Negative value is offset of parse error.
202  */
203 ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **out, char const *pattern, size_t len,
204  fr_regex_flags_t const *flags, bool subcaptures, bool runtime)
205 {
206  int ret;
207  PCRE2_SIZE offset;
208  uint32_t cflags = 0;
209  regex_t *preg;
210 
211  /*
212  * Check inputs
213  */
214  *out = NULL;
215 
216  /*
217  * Thread local initialisation
218  */
219  if (unlikely(!fr_pcre2_tls) && (fr_pcre2_tls_init() < 0)) return -1;
220 
221  if (len == 0) {
222  fr_strerror_const("Empty expression");
223  return 0;
224  }
225 
226  /*
227  * Options
228  */
229  if (flags) {
230  /* flags->global implemented by substitution function */
231  if (flags->ignore_case) cflags |= PCRE2_CASELESS;
232  if (flags->multiline) cflags |= PCRE2_MULTILINE;
233  if (flags->dot_all) cflags |= PCRE2_DOTALL;
234  if (flags->unicode) cflags |= PCRE2_UTF;
235  if (flags->extended) cflags |= PCRE2_EXTENDED;
236  }
237 
238  if (!subcaptures) cflags |= PCRE2_NO_AUTO_CAPTURE;
239 
240  preg = talloc_zero(ctx, regex_t);
241  talloc_set_destructor(preg, _regex_free);
242 
243  preg->compiled = pcre2_compile((PCRE2_SPTR8)pattern, len,
244  cflags, &ret, &offset, fr_pcre2_tls->ccontext);
245  if (!preg->compiled) {
246  PCRE2_UCHAR errbuff[128];
247 
248  pcre2_get_error_message(ret, errbuff, sizeof(errbuff));
249  fr_strerror_printf("%s", (char *)errbuff);
250  talloc_free(preg);
251 
252  return -(ssize_t)offset;
253  }
254 
255  if (!runtime) {
256  preg->precompiled = true;
257 
258 #ifdef PCRE2_CONFIG_JIT
259  /*
260  * This is expensive, so only do it for
261  * expressions that are going to be
262  * evaluated repeatedly.
263  */
264  if (fr_pcre2_tls->do_jit) {
265  ret = pcre2_jit_compile(preg->compiled, PCRE2_JIT_COMPLETE);
266  if (ret < 0) {
267  PCRE2_UCHAR errbuff[128];
268 
269  pcre2_get_error_message(ret, errbuff, sizeof(errbuff));
270  fr_strerror_printf("Pattern JIT failed: %s", (char *)errbuff);
271  talloc_free(preg);
272 
273  return 0;
274  }
275  preg->jitd = true;
276  }
277 #endif
278  }
279 
280  *out = preg;
281 
282  return len;
283 }
284 
285 /** Wrapper around pcre2_exec
286  *
287  * @param[in] preg The compiled expression.
288  * @param[in] subject to match.
289  * @param[in] len Length of subject.
290  * @param[in] regmatch Array of match pointers.
291  * @return
292  * - -1 on failure.
293  * - 0 on no match.
294  * - 1 on match.
295  */
296 int regex_exec(regex_t *preg, char const *subject, size_t len, fr_regmatch_t *regmatch)
297 {
298  int ret;
299  uint32_t options = 0;
300 
301  char *our_subject = NULL;
302  bool dup_subject = true;
303  pcre2_match_data *match_data;
304 
305  /*
306  * Thread local initialisation
307  */
308  if (unlikely(!fr_pcre2_tls) && (fr_pcre2_tls_init() < 0)) return -1;
309 
310  if (regmatch) {
311 #ifdef PCRE2_COPY_MATCHED_SUBJECT
312  /*
313  * This is apparently only supported for pcre2_match
314  * NOT pcre2_jit_match.
315  */
316 # ifdef PCRE2_CONFIG_JIT
317  if (!preg->jitd) {
318 # endif
319  dup_subject = false;
320 
321  /*
322  * If PCRE2_COPY_MATCHED_SUBJECT is available
323  * and set as an options flag, pcre2_match will
324  * strdup the subject string if pcre2_match is
325  * successful and store a pointer to it in the
326  * regmatch struct.
327  *
328  * The lifetime of the string memory will be
329  * bound to the regmatch struct. This is more
330  * efficient that doing it ourselves, as the
331  * strdup only occurs if the subject matches.
332  */
333  options |= PCRE2_COPY_MATCHED_SUBJECT;
334 # ifdef PCRE2_CONFIG_JIT
335  }
336 # endif
337 #endif
338  if (dup_subject) {
339  /*
340  * We have to dup and operate on the duplicate
341  * of the subject, because pcre2_jit_match and
342  * pcre2_match store a pointer to the subject
343  * in the regmatch structure.
344  */
345  subject = our_subject = talloc_bstrndup(regmatch, subject, len);
346  if (!subject) {
347  fr_strerror_const("Out of memory");
348  return -1;
349  }
350 #ifndef NDEBUG
351  regmatch->subject = subject; /* Stored only for tracking memory issues */
352 #endif
353  }
354  }
355 
356  /*
357  * If we weren't given match data we
358  * need to alloc it else pcre2_match
359  * fails when passed NULL match data.
360  */
361  if (!regmatch) {
362  match_data = pcre2_match_data_create_from_pattern(preg->compiled, fr_pcre2_tls->gcontext);
363  if (!match_data) {
364  fr_strerror_const("Failed allocating temporary match data");
365  return -1;
366  }
367  } else {
368  match_data = regmatch->match_data;
369  }
370 
371 #ifdef PCRE2_CONFIG_JIT
372  if (preg->jitd) {
373  ret = pcre2_jit_match(preg->compiled, (PCRE2_SPTR8)subject, len, 0, options,
374  match_data, fr_pcre2_tls->mcontext);
375  } else
376 #endif
377  {
378  ret = pcre2_match(preg->compiled, (PCRE2_SPTR8)subject, len, 0, options,
379  match_data, fr_pcre2_tls->mcontext);
380  }
381  if (!regmatch) pcre2_match_data_free(match_data);
382  if (ret < 0) {
383  PCRE2_UCHAR errbuff[128];
384 
385  if (dup_subject) talloc_free(our_subject);
386 
387  if (ret == PCRE2_ERROR_NOMATCH) {
388  if (regmatch) regmatch->used = 0;
389  return 0;
390  }
391 
392  pcre2_get_error_message(ret, errbuff, sizeof(errbuff));
393  fr_strerror_printf("regex evaluation failed with code (%i): %s", ret, errbuff);
394 
395  return -1;
396  }
397 
398  if (regmatch) regmatch->used = ret;
399 
400  return 1;
401 }
402 
403 /** Wrapper around pcre2_substitute
404  *
405  * @param[in] ctx to allocate output string in.
406  * @param[out] out Output string with replacements performed.
407  * @param[in] max_out Maximum length of output buffer. If this is 0 then
408  * the output length is unlimited.
409  * @param[in] preg The compiled expression.
410  * @param[in] flags that affect matching.
411  * @param[in] subject to perform replacements on.
412  * @param[in] subject_len the length of the subject.
413  * @param[in] replacement replacement string containing substitution
414  * markers.
415  * @param[in] replacement_len Length of the replacement string.
416  * @param[in] regmatch Array of match pointers.
417  * @return
418  * - >= 0 the length of the output string.
419  * - < 0 on error.
420  */
421 int regex_substitute(TALLOC_CTX *ctx, char **out, size_t max_out, regex_t *preg, fr_regex_flags_t const *flags,
422  char const *subject, size_t subject_len,
423  char const *replacement, size_t replacement_len,
424  fr_regmatch_t *regmatch)
425 {
426  int ret;
427  uint32_t options = 0;
428  size_t buff_len, actual_len;
429  char *buff;
430 
431 #ifndef PCRE2_COPY_MATCHED_SUBJECT
432  char *our_subject = NULL;
433 #endif
434 
435  /*
436  * Thread local initialisation
437  */
438  if (unlikely(!fr_pcre2_tls) && (fr_pcre2_tls_init() < 0)) return -1;
439 
440  /*
441  * Internally pcre2_substitute just calls pcre2_match to
442  * generate the match data, so the same hack as the
443  * regex_exec function above is required.
444  */
445  if (regmatch) {
446 #ifndef PCRE2_COPY_MATCHED_SUBJECT
447  /*
448  * We have to dup and operate on the duplicate
449  * of the subject, because pcre2_jit_match and
450  * pcre2_match store a pointer to the subject
451  * in the regmatch structure.
452  */
453  subject = our_subject = talloc_bstrndup(regmatch, subject, subject_len);
454  if (!subject) {
455  fr_strerror_const("Out of memory");
456  return -1;
457  }
458 #else
459  /*
460  * If PCRE2_COPY_MATCHED_SUBJECT is available
461  * and set as an options flag, pcre2_match will
462  * strdup the subject string if pcre2_match is
463  * successful and store a pointer to it in the
464  * regmatch struct.
465  *
466  * The lifetime of the string memory will be
467  * bound to the regmatch struct. This is more
468  * efficient that doing it ourselves, as the
469  * strdup only occurs if the subject matches.
470  */
471  options |= PCRE2_COPY_MATCHED_SUBJECT;
472 #endif
473  }
474 
475  /*
476  * Guess (badly) what the length of the output buffer should be
477  */
478  actual_len = buff_len = subject_len + 1; /* +1 for the \0 */
479  buff = talloc_array(ctx, char, buff_len);
480  if (!buff) {
481 #ifndef PCRE2_COPY_MATCHED_SUBJECT
482  talloc_free(our_subject);
483 #endif
484  fr_strerror_const("Out of memory");
485  return -1;
486  }
487 
488  options |= PCRE2_SUBSTITUTE_OVERFLOW_LENGTH;
489  if (flags->global) options |= PCRE2_SUBSTITUTE_GLOBAL;
490 
491 again:
492  /*
493  * actual_len input value should be the size of the
494  * buffer including space for '\0'.
495  * If input buffer is too small, then actual_len will be set
496  * to the buffer space needed including space for '\0'.
497  * If input buffer is the correct size, then actual_len
498  * will be set to the size of the string written to buff
499  * without the terminating '\0'.
500  */
501  ret = pcre2_substitute(preg->compiled,
502  (PCRE2_SPTR8)subject, (PCRE2_SIZE)subject_len, 0,
503  options, NULL, fr_pcre2_tls->mcontext,
504  (PCRE2_UCHAR const *)replacement, replacement_len, (PCRE2_UCHAR *)buff, &actual_len);
505 
506  if (ret < 0) {
507  PCRE2_UCHAR errbuff[128];
508 
509 #ifndef PCRE2_COPY_MATCHED_SUBJECT
510  talloc_free(our_subject);
511 #endif
512  talloc_free(buff);
513 
514  if (ret == PCRE2_ERROR_NOMEMORY) {
515  if ((max_out > 0) && (actual_len > max_out)) {
516  fr_strerror_printf("String length with substitutions (%zu) "
517  "exceeds max string length (%zu)", actual_len - 1, max_out - 1);
518  return -1;
519  }
520 
521  /*
522  * Check that actual_len != buff_len as that'd be
523  * an actual error.
524  */
525  if (actual_len == buff_len) {
526  fr_strerror_const("libpcre2 out of memory");
527  return -1;
528  }
529  buff_len = actual_len; /* The length we get passed back includes the \0 */
530  buff = talloc_array(ctx, char, buff_len);
531  goto again;
532  }
533 
534  if (ret == PCRE2_ERROR_NOMATCH) {
535  if (regmatch) regmatch->used = 0;
536  return 0;
537  }
538 
539  pcre2_get_error_message(ret, errbuff, sizeof(errbuff));
540  fr_strerror_printf("regex evaluation failed with code (%i): %s", ret, errbuff);
541  return -1;
542  }
543 
544  /*
545  * Trim the replacement buffer to the correct length
546  *
547  * buff_len includes \0.
548  * ...and as pcre2_substitute just succeeded actual_len does not include \0.
549  */
550  if (actual_len < (buff_len - 1)) {
551  buff = talloc_bstr_realloc(ctx, buff, actual_len);
552  if (!buff) {
553  fr_strerror_const("reallocing pcre2_substitute result buffer failed");
554  return -1;
555  }
556  }
557 
558  if (regmatch) regmatch->used = ret;
559  *out = buff;
560 
561  return 1;
562 }
563 
564 
565 /** Returns the number of subcapture groups
566  *
567  * @return
568  * - >0 The number of subcaptures contained within the pattern
569  * - 0 if the number of subcaptures can't be determined.
570  */
571 uint32_t regex_subcapture_count(regex_t const *preg)
572 {
573  uint32_t count;
574 
575  if (pcre2_pattern_info(preg->compiled, PCRE2_INFO_CAPTURECOUNT, &count) != 0) {
576  fr_strerror_const("Error determining subcapture group count");
577  return 0;
578  }
579 
580  return count + 1;
581 }
582 
583 /** Free libpcre2's matchdata
584  *
585  * @note Don't call directly, will be called if talloc_free is called on a #regmatch_t.
586  */
587 static int _pcre2_match_data_free(fr_regmatch_t *regmatch)
588 {
589  pcre2_match_data_free(regmatch->match_data);
590  return 0;
591 }
592 
593 /** Allocate vectors to fill with match data
594  *
595  * @param[in] ctx to allocate match vectors in.
596  * @param[in] count The number of vectors to allocate.
597  * @return
598  * - NULL on error.
599  * - Array of match vectors.
600  */
601 fr_regmatch_t *regex_match_data_alloc(TALLOC_CTX *ctx, uint32_t count)
602 {
603  fr_regmatch_t *regmatch;
604 
605  /*
606  * Thread local initialisation
607  */
608  if (unlikely(!fr_pcre2_tls) && (fr_pcre2_tls_init() < 0)) return NULL;
609 
610  regmatch = talloc(ctx, fr_regmatch_t);
611  if (!regmatch) {
612  oom:
613  fr_strerror_const("Out of memory");
614  return NULL;
615  }
616 
617  regmatch->match_data = pcre2_match_data_create(count, fr_pcre2_tls->gcontext);
618  if (!regmatch->match_data) {
619  talloc_free(regmatch);
620  goto oom;
621  }
622  talloc_set_type(regmatch->match_data, pcre2_match_data);
623 
624  talloc_set_destructor(regmatch, _pcre2_match_data_free);
625 
626  return regmatch;
627 }
628 /*
629  *######################################
630  *# FUNCTIONS FOR LIBPCRE #
631  *######################################
632  */
633 #elif defined(HAVE_REGEX_PCRE)
634 /*
635  * Wrapper functions for libpcre. Much more powerful, and guaranteed
636  * to be binary safe but require libpcre.
637  */
638 #if (PCRE_MAJOR >= 8) && (PCRE_MINOR >= 32) && defined(PCRE_CONFIG_JIT)
639 # define HAVE_PCRE_JIT_EXEC 1
640 #endif
641 
642 /** Thread local storage for PCRE
643  *
644  */
645 typedef struct {
646  TALLOC_CTX *alloc_ctx; //!< Context used for any allocations.
647 #ifdef HAVE_PCRE_JIT_EXEC
648  pcre_jit_stack *jit_stack;
649 #endif
650 } fr_pcre_tls_t;
651 
652 static _Thread_local fr_pcre_tls_t *fr_pcre_tls;
653 static bool fr_pcre_study_flags;
654 
655 /*
656  * Replace the libpcre memory allocation and freeing functions
657  * with talloc wrappers. This allows us to use the subcapture copy
658  * functions and just reparent the memory allocated.
659  */
660 static void *_pcre_talloc(size_t to_alloc)
661 {
662  return talloc_array(fr_pcre_tls->alloc_ctx, uint8_t, to_alloc);
663 }
664 
665 static void _pcre_talloc_free(void *to_free)
666 {
667  talloc_free(to_free);
668 }
669 
670 static int _pcre_globals_reset(UNUSED void *uctx)
671 {
672  pcre_malloc = NULL;
673  pcre_free = NULL;
674  return 0;
675 }
676 
677 static int _pcre_globals_configure(UNUSED void *uctx)
678 {
679 #ifdef PCRE_CONFIG_JIT
680  int *do_jit = 0;
681 
682  /*
683  * If the headers are from >= 8.20
684  * check at runtime to see if this version
685  * of the libpcre library was compiled with
686  * JIT support.
687  */
688  pcre_config(PCRE_CONFIG_JIT, &do_jit);
689 
690  if (do_jit) fr_pcre_study_flags |= PCRE_STUDY_JIT_COMPILE;
691 #endif
692  pcre_malloc = _pcre_talloc; /* pcre_malloc is a global provided by libpcre */
693  pcre_free = _pcre_talloc_free; /* pcre_free is a global provided by libpcre */
694 
695  return 0;
696 }
697 
698 /** Free thread local data
699  *
700  * @param[in] tls Thread local data to free.
701  */
702 static int _pcre_tls_free(fr_pcre_tls_t *tls)
703 {
704 #ifdef HAVE_PCRE_JIT_EXEC
705  if (tls->jit_stack) pcre_jit_stack_free(tls->jit_stack);
706 #endif
707  return 0;
708 }
709 
710 static int _pcre_tls_free_on_exit(void *arg)
711 {
712  return talloc_free(arg);
713 }
714 
715 /** Performs thread local storage initialisation for libpcre
716  *
717  */
718 static inline CC_HINT(always_inline) int pcre_tls_init(void)
719 {
720  fr_pcre_tls_t *tls;
721 
722  if (fr_pcre_tls) return 0;
723 
724  tls = talloc_zero(NULL, fr_pcre_tls_t);
725  if (unlikely(!tls)) return -1;
726  talloc_set_destructor(tls, _pcre_tls_free);
727 
728  /*
729  * Need to set this first so that the alloc
730  * functions can access alloc_ctx.
731  */
732  fr_atexit_thread_local(fr_pcre_tls, _pcre_tls_free_on_exit, tls);
733 
734 #ifdef HAVE_PCRE_JIT_EXEC
735  /*
736  * Starts at 128K, max is 512K per thread.
737  */
738  tls->jit_stack = pcre_jit_stack_alloc(FR_PCRE_JIT_STACK_MIN, FR_PCRE_JIT_STACK_MAX);
739 #endif
740 
741  return 0;
742 }
743 
744 /** Free regex_t structure
745  *
746  * Calls libpcre specific free functions for the expression and study.
747  *
748  * @param preg to free.
749  */
750 static int _regex_free(regex_t *preg)
751 {
752  if (preg->compiled) pcre_free(preg->compiled);
753 #ifdef PCRE_CONFIG_JIT
754  if (preg->extra) pcre_free_study(preg->extra);
755 #else
756  if (preg->extra) pcre_free(preg->extra);
757 #endif
758 
759  return 0;
760 }
761 
762 /** Wrapper around pcre_compile
763  *
764  * Allows the rest of the code to do compilations using one function signature.
765  *
766  * @note Compiled expression must be freed with talloc_free.
767  *
768  * @param[out] out Where to write out a pointer to the structure containing
769  * the compiled expression.
770  * @param[in] pattern to compile.
771  * @param[in] len of pattern.
772  * @param[in] flags controlling matching. May be NULL.
773  * @param[in] subcaptures Whether to compile the regular expression to store subcapture
774  * data.
775  * @param[in] runtime If false run the pattern through the PCRE JIT to convert it
776  * to machine code. This trades startup time (longer) for
777  * runtime performance (better).
778  * @return
779  * - >= 1 on success.
780  * - <= 0 on error. Negative value is offset of parse error.
781  */
782 ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **out, char const *pattern, size_t len,
783  fr_regex_flags_t const *flags, bool subcaptures, bool runtime)
784 {
785  char const *error;
786  int offset;
787  int cflags = 0;
788  int ret;
789  regex_t *preg;
790 
791  fr_atexit_global_once_ret(&ret, _pcre_globals_configure, _pcre_globals_reset, NULL);
792  if (unlikely(ret < 0)) return -1;
793 
794 
795  if (unlikely(pcre_tls_init() < 0)) return -1;
796 
797  /*
798  * Check inputs
799  */
800  *out = NULL;
801 
802  if (len == 0) {
803  fr_strerror_const("Empty expression");
804  return 0;
805  }
806 
807  /*
808  * Options
809  */
810  if (flags) {
811  if (flags->global) {
812  fr_strerror_const("g - Global matching/substitution not supported with libpcre");
813  return 0;
814  }
815  if (flags->ignore_case) cflags |= PCRE_CASELESS;
816  if (flags->multiline) cflags |= PCRE_MULTILINE;
817  if (flags->dot_all) cflags |= PCRE_DOTALL;
818  if (flags->unicode) cflags |= PCRE_UTF8;
819  if (flags->extended) cflags |= PCRE_EXTENDED;
820  }
821 
822  if (!subcaptures) cflags |= PCRE_NO_AUTO_CAPTURE;
823 
824  preg = talloc_zero(ctx, regex_t);
825  if (unlikely(preg == NULL)) {
826  fr_strerror_const("Out of memory");
827  return 0;
828  }
829  talloc_set_destructor(preg, _regex_free);
830 
831  preg->compiled = pcre_compile(pattern, cflags, &error, &offset, NULL);
832  if (!preg->compiled) {
833  fr_strerror_printf("%s", error);
834  talloc_free(preg);
835 
836  return -(ssize_t)offset;
837  }
838 
839  if (!runtime) {
840  preg->precompiled = true;
841  preg->extra = pcre_study(preg->compiled, fr_pcre_study_flags, &error);
842  if (error) {
843  fr_strerror_printf("Pattern study failed: %s", error);
844  talloc_free(preg);
845 
846  return 0;
847  }
848 
849 #ifdef PCRE_INFO_JIT
850  /*
851  * Check to see if the JIT was successful.
852  *
853  * Not all platforms have JIT support, the pattern
854  * may not be jitable, or JIT support may have been
855  * disabled.
856  */
857  if (fr_pcre_study_flags & PCRE_STUDY_JIT_COMPILE) {
858  int jitd = 0;
859 
860  pcre_fullinfo(preg->compiled, preg->extra, PCRE_INFO_JIT, &jitd);
861  if (jitd) preg->jitd = true;
862  }
863 #endif
864  }
865 
866  *out = preg;
867 
868  return len;
869 }
870 
871 static fr_table_num_ordered_t const regex_pcre_error_str[] = {
872  { L("PCRE_ERROR_NOMATCH"), PCRE_ERROR_NOMATCH },
873  { L("PCRE_ERROR_NULL"), PCRE_ERROR_NULL },
874  { L("PCRE_ERROR_BADOPTION"), PCRE_ERROR_BADOPTION },
875  { L("PCRE_ERROR_BADMAGIC"), PCRE_ERROR_BADMAGIC },
876  { L("PCRE_ERROR_UNKNOWN_OPCODE"), PCRE_ERROR_UNKNOWN_OPCODE },
877  { L("PCRE_ERROR_NOMEMORY"), PCRE_ERROR_NOMEMORY },
878  { L("PCRE_ERROR_NOSUBSTRING"), PCRE_ERROR_NOSUBSTRING },
879  { L("PCRE_ERROR_MATCHLIMIT"), PCRE_ERROR_MATCHLIMIT },
880  { L("PCRE_ERROR_CALLOUT"), PCRE_ERROR_CALLOUT },
881  { L("PCRE_ERROR_BADUTF8"), PCRE_ERROR_BADUTF8 },
882  { L("PCRE_ERROR_BADUTF8_OFFSET"), PCRE_ERROR_BADUTF8_OFFSET },
883  { L("PCRE_ERROR_PARTIAL"), PCRE_ERROR_PARTIAL },
884  { L("PCRE_ERROR_BADPARTIAL"), PCRE_ERROR_BADPARTIAL },
885  { L("PCRE_ERROR_INTERNAL"), PCRE_ERROR_INTERNAL },
886  { L("PCRE_ERROR_BADCOUNT"), PCRE_ERROR_BADCOUNT },
887  { L("PCRE_ERROR_DFA_UITEM"), PCRE_ERROR_DFA_UITEM },
888  { L("PCRE_ERROR_DFA_UCOND"), PCRE_ERROR_DFA_UCOND },
889  { L("PCRE_ERROR_DFA_UMLIMIT"), PCRE_ERROR_DFA_UMLIMIT },
890  { L("PCRE_ERROR_DFA_WSSIZE"), PCRE_ERROR_DFA_WSSIZE },
891  { L("PCRE_ERROR_DFA_RECURSE"), PCRE_ERROR_DFA_RECURSE },
892  { L("PCRE_ERROR_RECURSIONLIMIT"), PCRE_ERROR_RECURSIONLIMIT },
893  { L("PCRE_ERROR_NULLWSLIMIT"), PCRE_ERROR_NULLWSLIMIT },
894  { L("PCRE_ERROR_BADNEWLINE"), PCRE_ERROR_BADNEWLINE },
895  { L("PCRE_ERROR_BADOFFSET"), PCRE_ERROR_BADOFFSET },
896  { L("PCRE_ERROR_SHORTUTF8"), PCRE_ERROR_SHORTUTF8 },
897  { L("PCRE_ERROR_RECURSELOOP"), PCRE_ERROR_RECURSELOOP },
898  { L("PCRE_ERROR_JIT_STACKLIMIT"), PCRE_ERROR_JIT_STACKLIMIT },
899  { L("PCRE_ERROR_BADMODE"), PCRE_ERROR_BADMODE },
900  { L("PCRE_ERROR_BADENDIANNESS"), PCRE_ERROR_BADENDIANNESS },
901  { L("PCRE_ERROR_DFA_BADRESTART"), PCRE_ERROR_DFA_BADRESTART },
902  { L("PCRE_ERROR_JIT_BADOPTION"), PCRE_ERROR_JIT_BADOPTION },
903  { L("PCRE_ERROR_BADLENGTH"), PCRE_ERROR_BADLENGTH },
904 #ifdef PCRE_ERROR_UNSET
905  { L("PCRE_ERROR_UNSET"), PCRE_ERROR_UNSET },
906 #endif
907 };
908 static size_t regex_pcre_error_str_len = NUM_ELEMENTS(regex_pcre_error_str);
909 
910 /** Wrapper around pcre_exec
911  *
912  * @param[in] preg The compiled expression.
913  * @param[in] subject to match.
914  * @param[in] len Length of subject.
915  * @param[in] regmatch Match result structure.
916  * @return
917  * - -1 on failure.
918  * - 0 on no match.
919  * - 1 on match.
920  */
921 int regex_exec(regex_t *preg, char const *subject, size_t len, fr_regmatch_t *regmatch)
922 {
923  int ret;
924  size_t matches;
925 
926  if (unlikely(pcre_tls_init() < 0)) return -1;
927 
928  /*
929  * Disable capturing
930  */
931  if (!regmatch) {
932  matches = 0;
933  } else {
934  matches = regmatch->allocd;
935 
936  /*
937  * Reset the match result structure
938  */
939  memset(regmatch->match_data, 0, sizeof(regmatch->match_data[0]) * matches);
940  regmatch->used = 0;
941  }
942 
943 #ifdef HAVE_PCRE_JIT_EXEC
944  if (preg->jitd) {
945  ret = pcre_jit_exec(preg->compiled, preg->extra, subject, len, 0, 0,
946  regmatch ? (int *)regmatch->match_data : NULL, matches * 3, fr_pcre_tls->jit_stack);
947  } else
948 #endif
949  {
950  ret = pcre_exec(preg->compiled, preg->extra, subject, len, 0, 0,
951  regmatch ? (int *)regmatch->match_data : NULL, matches * 3);
952  }
953  if (ret < 0) {
954  if (ret == PCRE_ERROR_NOMATCH) return 0;
955 
956  fr_strerror_printf("regex evaluation failed with code (%i): %s", ret,
957  fr_table_str_by_value(regex_pcre_error_str, ret, "<INVALID>"));
958  return -1;
959  }
960 
961  /*
962  * 0 signifies more offsets than we provided space for,
963  * so don't touch nmatches.
964  */
965  if (regmatch && (ret > 0)) {
966  regmatch->used = ret;
967 
968  if (regmatch->subject) talloc_const_free(regmatch->subject);
969  regmatch->subject = talloc_bstrndup(regmatch, subject, len);
970  if (!regmatch->subject) {
971  fr_strerror_const("Out of memory");
972  return -1;
973  }
974  }
975 
976  return 1;
977 }
978 
979 /** Returns the number of subcapture groups
980  *
981  * @return
982  * - >0 The number of subcaptures contained within the pattern
983  * - 0 if the number of subcaptures can't be determined.
984  */
985 uint32_t regex_subcapture_count(regex_t const *preg)
986 {
987  int count;
988 
989  if (pcre_fullinfo(preg->compiled, preg->extra, PCRE_INFO_CAPTURECOUNT, &count) != 0) {
990  fr_strerror_const("Error determining subcapture group count");
991  return 0;
992  }
993 
994  return (uint32_t)count + 1;
995 }
996 /*
997  *######################################
998  *# FUNCTIONS FOR POSIX-REGEX #
999  *######################################
1000  */
1001 # else
1002 /*
1003  * Wrapper functions for POSIX like, and extended regular
1004  * expressions. These use the system regex library.
1005  */
1006 
1007 /** Free heap allocated regex_t structure
1008  *
1009  * Heap allocation of regex_t is needed so regex_compile has the same signature with
1010  * POSIX or libpcre.
1011  *
1012  * @param preg to free.
1013  */
1014 static int _regex_free(regex_t *preg)
1015 {
1016  regfree(preg);
1017 
1018  return 0;
1019 }
1020 
1021 /** Binary safe wrapper around regcomp
1022  *
1023  * If we have the BSD extensions we don't need to do any special work
1024  * if we don't have the BSD extensions we need to check to see if the
1025  * regular expression contains any \0 bytes.
1026  *
1027  * If it does we fail and print the appropriate error message.
1028  *
1029  * @note Compiled expression must be freed with talloc_free.
1030  *
1031  * @param[in] ctx To allocate memory in.
1032  * @param[out] out Where to write out a pointer
1033  * to the structure containing the compiled expression.
1034  * @param[in] pattern to compile.
1035  * @param[in] len of pattern.
1036  * @param[in] flags controlling matching. May be NULL.
1037  * @param[in] subcaptures Whether to compile the regular expression
1038  * to store subcapture data.
1039  * @param[in] runtime Whether the compilation is being done at runtime.
1040  * @return
1041  * - >= 1 on success.
1042  * - <= 0 on error. Negative value is offset of parse error.
1043  * With POSIX regex we only give the correct offset for embedded \0 errors.
1044  */
1045 ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **out, char const *pattern, size_t len,
1046  fr_regex_flags_t const *flags, bool subcaptures, UNUSED bool runtime)
1047 {
1048  int ret;
1049  int cflags = REG_EXTENDED;
1050  regex_t *preg;
1051 
1052  if (len == 0) {
1053  fr_strerror_const("Empty expression");
1054  return 0;
1055  }
1056 
1057  /*
1058  * Options
1059  */
1060  if (flags) {
1061  if (flags->global) {
1062  fr_strerror_const("g - Global matching/substitution not supported with posix-regex");
1063  return 0;
1064  }
1065  if (flags->dot_all) {
1066  fr_strerror_const("s - Single line matching is not supported with posix-regex");
1067  return 0;
1068  }
1069  if (flags->unicode) {
1070  fr_strerror_const("u - Unicode matching not supported with posix-regex");
1071  return 0;
1072  }
1073  if (flags->extended) {
1074  fr_strerror_const("x - Whitespace and comments not supported with posix-regex");
1075  return 0;
1076  }
1077 
1078  if (flags->ignore_case) cflags |= REG_ICASE;
1079  if (flags->multiline) cflags |= REG_NEWLINE;
1080  }
1081 
1082 
1083  if (!subcaptures) cflags |= REG_NOSUB;
1084 
1085 #ifndef HAVE_REGNCOMP
1086  {
1087  char const *p;
1088 
1089  p = pattern;
1090  p += strlen(pattern);
1091 
1092  if ((size_t)(p - pattern) != len) {
1093  fr_strerror_printf("Found null in pattern at offset %zu. Pattern unsafe for compilation",
1094  (p - pattern));
1095  return -(p - pattern);
1096  }
1097 
1098  preg = talloc_zero(ctx, regex_t);
1099  if (!preg) return 0;
1100 
1101  ret = regcomp(preg, pattern, cflags);
1102  }
1103 #else
1104  preg = talloc_zero(ctx, regex_t);
1105  if (!preg) return 0;
1106  ret = regncomp(preg, pattern, len, cflags);
1107 #endif
1108  if (ret != 0) {
1109  char errbuf[128];
1110 
1111  regerror(ret, preg, errbuf, sizeof(errbuf));
1112  fr_strerror_printf("%s", errbuf);
1113 
1114  talloc_free(preg);
1115 
1116  return 0; /* POSIX expressions don't give us the failure offset */
1117  }
1118 
1119  talloc_set_destructor(preg, _regex_free);
1120  *out = preg;
1121 
1122  return len;
1123 }
1124 
1125 /** Binary safe wrapper around regexec
1126  *
1127  * If we have the BSD extensions we don't need to do any special work
1128  * If we don't have the BSD extensions we need to check to see if the
1129  * value to be compared contains any \0 bytes.
1130  *
1131  * If it does, we fail and print the appropriate error message.
1132  *
1133  * @param[in] preg The compiled expression.
1134  * @param[in] subject to match.
1135  * @param[in] regmatch Match result structure.
1136  * @return
1137  * - -1 on failure.
1138  * - 0 on no match.
1139  * - 1 on match.
1140  */
1141 int regex_exec(regex_t *preg, char const *subject, size_t len, fr_regmatch_t *regmatch)
1142 {
1143  int ret;
1144  size_t matches;
1145 
1146  /*
1147  * Disable capturing
1148  */
1149  if (!regmatch) {
1150  matches = 0;
1151  } else {
1152  matches = regmatch->allocd;
1153 
1154  /*
1155  * Reset the match result structure
1156  */
1157  memset(regmatch->match_data, 0, sizeof(regmatch->match_data[0]) * matches);
1158  regmatch->used = 0;
1159  }
1160 
1161 #ifndef HAVE_REGNEXEC
1162  {
1163  char const *p;
1164 
1165  p = subject;
1166  p += strlen(subject);
1167 
1168  if ((size_t)(p - subject) != len) {
1169  fr_strerror_printf("Found null in subject at offset %zu. String unsafe for evaluation",
1170  (p - subject));
1171  if (regmatch) regmatch->used = 0;
1172  return -1;
1173  }
1174  ret = regexec(preg, subject, matches, regmatch ? regmatch->match_data : NULL, 0);
1175  }
1176 #else
1177  ret = regnexec(preg, subject, len, matches, regmatch ? regmatch->match_data : NULL, 0);
1178 #endif
1179  if (ret != 0) {
1180  if (ret != REG_NOMATCH) {
1181  char errbuf[128];
1182 
1183  regerror(ret, preg, errbuf, sizeof(errbuf));
1184 
1185  fr_strerror_printf("regex evaluation failed: %s", errbuf);
1186  return -1;
1187  }
1188  return 0;
1189  }
1190 
1191  /*
1192  * Update regmatch->count to be the maximum number of
1193  * groups that *could* have been populated as we don't
1194  * have the number of matches.
1195  */
1196  if (regmatch) {
1197  regmatch->used = preg->re_nsub + 1;
1198 
1199  if (regmatch->subject) talloc_const_free(regmatch->subject);
1200  regmatch->subject = talloc_bstrndup(regmatch, subject, len);
1201  if (!regmatch->subject) {
1202  fr_strerror_const("Out of memory");
1203  return -1;
1204  }
1205  }
1206  return 1;
1207 }
1208 
1209 /** Returns the number of subcapture groups
1210  *
1211  * @return
1212  * - 0 we can't determine this for POSIX regular expressions.
1213  */
1214 uint32_t regex_subcapture_count(UNUSED regex_t const *preg)
1215 {
1216  return 0;
1217 }
1218 # endif
1219 
1220 # if defined(HAVE_REGEX_POSIX) || defined(HAVE_REGEX_PCRE)
1221 /** Allocate vectors to fill with match data
1222  *
1223  * @param[in] ctx to allocate match vectors in.
1224  * @param[in] count The number of vectors to allocate.
1225  * @return
1226  * - NULL on error.
1227  * - Array of match vectors.
1228  */
1229 fr_regmatch_t *regex_match_data_alloc(TALLOC_CTX *ctx, uint32_t count)
1230 {
1231  fr_regmatch_t *regmatch;
1232 
1233  /*
1234  * Pre-allocate space for the match structure
1235  * and for a 128b subject string.
1236  */
1237  regmatch = talloc_zero_pooled_object(ctx, fr_regmatch_t, 2, (sizeof(regmatch_t) * count) + 128);
1238  if (unlikely(!regmatch)) {
1239  error:
1240  fr_strerror_const("Out of memory");
1241  talloc_free(regmatch);
1242  return NULL;
1243  }
1244  regmatch->match_data = talloc_array(regmatch, regmatch_t, count);
1245  if (unlikely(!regmatch->match_data)) goto error;
1246 
1247  regmatch->allocd = count;
1248  regmatch->used = 0;
1249  regmatch->subject = NULL;
1250 
1251  return regmatch;
1252 }
1253 # endif
1254 
1255 /*
1256  *########################################
1257  *# UNIVERSAL FUNCTIONS #
1258  *########################################
1259  */
1260 
1261 /** Parse a string containing one or more regex flags
1262  *
1263  * @param[out] err May be NULL. If not NULL will be set to:
1264  * - 0 on success.
1265  * - -1 on unknown flag.
1266  * - -2 on duplicate.
1267  * @param[out] out Flag structure to populate. Must be initialised to zero
1268  * if this is the first call to regex_flags_parse.
1269  * @param[in] in Flag string to parse.
1270  * @param[in] terminals Terminal characters. If parsing ends before the buffer
1271  * is exhausted, and is pointing to one of these chars
1272  * it's not considered an error.
1273  * @param[in] err_on_dup Error if the flag is already set.
1274  * @return
1275  * - > 0 on success. The number of flag bytes parsed.
1276  * - <= 0 on failure. Negative offset of first unrecognised flag.
1277  */
1278 fr_slen_t regex_flags_parse(int *err, fr_regex_flags_t *out, fr_sbuff_t *in,
1279  fr_sbuff_term_t const *terminals, bool err_on_dup)
1280 {
1281  fr_sbuff_t our_in = FR_SBUFF(in);
1282 
1283  if (err) *err = 0;
1284 
1285  while (fr_sbuff_extend(&our_in)) {
1286  switch (*our_in.p) {
1287 #define DO_REGEX_FLAG(_f, _c) \
1288  case _c: \
1289  if (err_on_dup && out->_f) { \
1290  fr_strerror_printf("Duplicate regex flag '%c'", *our_in.p); \
1291  if (err) *err = -2; \
1292  FR_SBUFF_ERROR_RETURN(&our_in); \
1293  } \
1294  out->_f = 1; \
1295  break
1296 
1297  DO_REGEX_FLAG(global, 'g');
1298  DO_REGEX_FLAG(ignore_case, 'i');
1299  DO_REGEX_FLAG(multiline, 'm');
1300  DO_REGEX_FLAG(dot_all, 's');
1301  DO_REGEX_FLAG(unicode, 'u');
1302  DO_REGEX_FLAG(extended, 'x');
1303 #undef DO_REGEX_FLAG
1304 
1305  default:
1306  if (fr_sbuff_is_terminal(&our_in, terminals)) FR_SBUFF_SET_RETURN(in, &our_in);
1307 
1308  fr_strerror_printf("Unsupported regex flag '%c'", *our_in.p);
1309  if (err) *err = -1;
1310  FR_SBUFF_ERROR_RETURN(&our_in);
1311  }
1312  fr_sbuff_advance(&our_in, 1);
1313  }
1314  FR_SBUFF_SET_RETURN(in, &our_in);
1315 }
1316 
1317 /** Print the flags
1318  *
1319  * @param[out] sbuff where to write flags.
1320  * @param[in] flags to print.
1321  * @return
1322  * - The number of bytes written to the out buffer.
1323  * - A number >= outlen if truncation has occurred.
1324  */
1325 ssize_t regex_flags_print(fr_sbuff_t *sbuff, fr_regex_flags_t const *flags)
1326 {
1327  fr_sbuff_t our_sbuff = FR_SBUFF(sbuff);
1328 
1329 #define DO_REGEX_FLAG(_f, _c) \
1330  if (flags->_f) FR_SBUFF_IN_CHAR_RETURN(&our_sbuff, _c)
1331 
1332  DO_REGEX_FLAG(global, 'g');
1333  DO_REGEX_FLAG(ignore_case, 'i');
1334  DO_REGEX_FLAG(multiline, 'm');
1335  DO_REGEX_FLAG(dot_all, 's');
1336  DO_REGEX_FLAG(unicode, 'u');
1337  DO_REGEX_FLAG(extended, 'x');
1338 #undef DO_REGEX_FLAG
1339 
1340  FR_SBUFF_SET_RETURN(sbuff, &our_sbuff);
1341 }
1342 #endif
1343 
1344 /** Compare two boxes using an operator
1345  *
1346  * @todo - allow /foo/i on the RHS
1347  *
1348  * However, this involves allocating intermediate sbuffs for the
1349  * unescaped RHS, and all kinds of extra work. It's not overly hard,
1350  * but it's something we wish to avoid for now.
1351  *
1352  * @param[in] op to use in comparison. MUST be T_OP_REG_EQ or T_OP_REG_NE
1353  * @param[in] a Value to compare, MUST be FR_TYPE_STRING
1354  * @param[in] b uncompiled regex as FR_TYPE_STRING
1355  * @return
1356  * - 1 if true
1357  * - 0 if false
1358  * - -1 on failure.
1359  */
1361 {
1362  int rcode;
1363  TALLOC_CTX *ctx = NULL;
1364  size_t lhs_len;
1365  char const *lhs;
1366  regex_t *regex = NULL;
1367 
1368  if (!((op == T_OP_REG_EQ) || (op == T_OP_REG_NE))) {
1369  fr_strerror_const("Invalid operator for regex comparison");
1370  return -1;
1371  }
1372 
1373  if (b->type != FR_TYPE_STRING) {
1374  fr_strerror_const("RHS must be regular expression");
1375  return -1;
1376  }
1377 
1378  ctx = talloc_init_const("regex_cmp_op");
1379  if (!ctx) return -1;
1380 
1381  if ((a->type != FR_TYPE_STRING) && (a->type != FR_TYPE_OCTETS)) {
1382  fr_slen_t slen;
1383  char *p;
1384 
1385  slen = fr_value_box_aprint(ctx, &p, a, NULL); /* no escaping */
1386  if (slen < 0) return slen;
1387 
1388  lhs = p;
1389  lhs_len = slen;
1390 
1391  } else {
1392  lhs = a->vb_strvalue;
1393  lhs_len = a->vb_length;
1394  }
1395 
1396  if (regex_compile(ctx, &regex, b->vb_strvalue, b->vb_length, NULL, false, true) < 0) {
1397  talloc_free(ctx);
1398  return -1;
1399  }
1400 
1401 #ifdef STATIC_ANALYZER
1402  if (!regex) {
1403  talloc_free(ctx);
1404  return -1;
1405  }
1406 #endif
1407 
1408  rcode = regex_exec(regex, lhs, lhs_len, NULL);
1409  talloc_free(ctx);
1410  if (rcode < 0) return rcode;
1411 
1412  /*
1413  * Invert the sense of the rcode for !~
1414  */
1415  if (op == T_OP_REG_NE) rcode = (rcode == 0);
1416 
1417  return rcode;
1418 }
#define fr_atexit_thread_local(_name, _free, _uctx)
Definition: atexit.h:221
#define RCSID(id)
Definition: build.h:481
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define unlikely(_x)
Definition: build.h:379
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
fr_dcursor_eval_t void const * uctx
Definition: dcursor.h:546
static fr_slen_t err
Definition: dict.h:821
static fr_slen_t in
Definition: dict.h:821
talloc_free(reap)
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
char * p
Definition: merged_model.c:38
unsigned char uint8_t
Definition: merged_model.c:30
ssize_t fr_slen_t
Definition: merged_model.c:35
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
Definition: sbuff.c:2130
#define fr_sbuff_extend(_sbuff_or_marker)
#define FR_SBUFF_ERROR_RETURN(_sbuff_or_marker)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
Set of terminal elements.
Definition: merged_model.c:161
static char buff[sizeof("18446744073709551615")+3]
Definition: size_tests.c:41
return count
Definition: module.c:163
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition: table.h:772
An element in an arbitrarily ordered array of name to num mappings.
Definition: table.h:57
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition: talloc.c:564
char * talloc_bstr_realloc(TALLOC_CTX *ctx, char *in, size_t inlen)
Trim a bstr (char) buffer.
Definition: talloc.c:628
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition: talloc.h:177
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition: talloc.h:224
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
Definition: talloc.h:112
enum fr_token fr_token_t
@ T_OP_REG_EQ
Definition: token.h:102
@ T_OP_REG_NE
Definition: token.h:103
int fr_regex_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b)
Compare two boxes using an operator.
Definition: regex.c:1360
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const(_msg)
Definition: strerror.h:223
FR_SBUFF_SET_RETURN(sbuff, &our_sbuff)
static fr_slen_t fr_value_box_aprint(TALLOC_CTX *ctx, char **out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules) 1(fr_value_box_print
static size_t char ** out
Definition: value.h:997