The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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 */
24RCSID("$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 */
58typedef 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 */
72static _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 */
79static 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 */
89static 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 */
98static 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
110static int _pcre2_tls_free_on_exit(void *arg)
111{
112 return talloc_free(arg);
113}
114
115/** Thread local init for pcre2
116 *
117 */
118static 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 */
176static 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 */
203ssize_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 */
296int 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 */
421int 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
491again:
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
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 */
571uint32_t regex_subcapture_count(regex_t const *preg)
572{
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 */
587static 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 */
601fr_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 */
645typedef 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
652static _Thread_local fr_pcre_tls_t *fr_pcre_tls;
653static 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 */
660static void *_pcre_talloc(size_t to_alloc)
661{
662 return talloc_array(fr_pcre_tls->alloc_ctx, uint8_t, to_alloc);
663}
664
665static void _pcre_talloc_free(void *to_free)
666{
667 talloc_free(to_free);
668}
669
670static int _pcre_globals_reset(UNUSED void *uctx)
671{
672 pcre_malloc = NULL;
673 pcre_free = NULL;
674 return 0;
675}
676
677static 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 */
702static 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
710static 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 */
718static 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 */
750static 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 */
782ssize_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
871static 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};
908static 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 */
921int 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 */
985uint32_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 */
1014static 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 */
1045ssize_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 */
1141int 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 */
1214uint32_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 */
1229fr_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 */
1278fr_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 */
1325ssize_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:483
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
#define NUM_ELEMENTS(_t)
Definition build.h:337
static fr_slen_t err
Definition dict.h:824
static fr_slen_t in
Definition dict.h:824
talloc_free(reap)
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_OCTETS
Raw octets.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
ssize_t fr_slen_t
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
Definition sbuff.c:2152
#define fr_sbuff_extend(_sbuff_or_marker)
#define FR_SBUFF_ERROR_RETURN(_sbuff_or_marker)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
Set of terminal elements.
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_bstr_realloc(TALLOC_CTX *ctx, char *in, size_t inlen)
Trim a bstr (char) buffer.
Definition talloc.c:628
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:564
#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
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