The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
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: a35167f856c5ceb8744a2cd3cdbf7a523950a57a $")
25
26#ifdef HAVE_REGEX
27
28#include <freeradius-devel/util/regex.h>
29
30#if defined(HAVE_REGEX_PCRE2) && defined(PCRE2_CONFIG_JIT)
31#ifndef FR_PCRE_JIT_STACK_MIN
32# define FR_PCRE_JIT_STACK_MIN (128 * 1024)
33#endif
34#ifndef FR_PCRE_JIT_STACK_MAX
35# define FR_PCRE_JIT_STACK_MAX (512 * 1024)
36#endif
37#endif
38
39/*
40 * pcre2_set_max_pattern_compiled_length() arrived in PCRE2 10.41.
41 */
42#if defined(HAVE_REGEX_PCRE2) && defined(PCRE2_MAJOR) && \
43 ((PCRE2_MAJOR > 10) || ((PCRE2_MAJOR == 10) && (PCRE2_MINOR >= 41)))
44# define FR_PCRE2_HAVE_MAX_PATTERN_LENGTH 1
45
46/*
47 * The largest a single pattern may compile to.
48 *
49 * A bounded repeat is expanded by the engine, and nesting them
50 * multiplies: "((((a){40}){40}){40}){40}" is 25 characters, and expands
51 * to around 40^4 nodes. With no limit, a pattern of a few dozen bytes
52 * compiles to gigabytes. That matters because regex_compile() runs at
53 * runtime as well as at config time, see xlat_func_regex_search().
54 *
55 * Hand-written patterns compile to a few KB at most, so this bound is
56 * orders of magnitude above anything legitimate, and only fires on
57 * patterns built to exhaust memory.
58 */
59# ifndef FR_PCRE2_MAX_PATTERN_LENGTH
60# define FR_PCRE2_MAX_PATTERN_LENGTH (1024 * 1024)
61# endif
62#endif
63
64const fr_sbuff_escape_rules_t regex_escape_rules = {
65 .name = "regex",
66 .chr = '\\',
67 .subs = {
68 ['$'] = '$',
69 ['*'] = '*',
70 ['+'] = '+',
71 ['.'] = '.',
72 ['/'] = '/',
73 ['?'] = '?',
74 ['('] = '(',
75 [')'] = ')',
76 ['['] = '[',
77 [']'] = ']',
78 ['{'] = '{',
79 ['}'] = '}',
80 ['\\'] = '\\',
81 ['^'] = '^',
82 ['`'] = '`',
83 ['|'] = '|',
84 ['\a'] = 'a',
85 ['\b'] = 'b',
86 ['\n'] = 'n',
87 ['\r'] = 'r',
88 ['\t'] = 't',
89 ['\v'] = 'v'
90 },
91 .esc = {
94 },
95 .do_utf8 = true,
96 .do_oct = true
97};
98
99
100/*
101 *######################################
102 *# FUNCTIONS FOR LIBPCRE2 #
103 *######################################
104 */
105#ifdef HAVE_REGEX_PCRE2
106/*
107 * Wrapper functions for libpcre2. Much more powerful, and guaranteed
108 * to be binary safe for both patterns and subjects but require
109 * libpcre2.
110 */
111
112/** Thread local storage for PCRE2
113 *
114 * Not all this storage is thread local, but it simplifies cleanup if
115 * we bind its lifetime to the thread, and lets us get away with not
116 * having specific init/free functions.
117 */
118typedef struct {
119 TALLOC_CTX *alloc_ctx; //!< Context used for any allocations.
120 pcre2_general_context *gcontext; //!< General context.
121 pcre2_compile_context *ccontext; //!< Compile context.
122 pcre2_match_context *mcontext; //!< Match context.
123#ifdef PCRE2_CONFIG_JIT
124 pcre2_jit_stack *jit_stack; //!< Jit stack for executing jit'd patterns.
125 bool do_jit; //!< Whether we have runtime JIT support.
126#endif
127} fr_pcre2_tls_t;
128
129/** Thread local storage for pcre2
130 *
131 */
132static _Thread_local fr_pcre2_tls_t *fr_pcre2_tls;
133
134/** Talloc wrapper for pcre2 memory allocation
135 *
136 * @param[in] to_alloc How many bytes to alloc.
137 * @param[in] uctx UNUSED.
138 */
139static void *_pcre2_talloc(PCRE2_SIZE to_alloc, UNUSED void *uctx)
140{
141 return talloc_array(fr_pcre2_tls->alloc_ctx, uint8_t, to_alloc);
142}
143
144/** Talloc wrapper for pcre2 memory freeing
145 *
146 * @param[in] to_free Memory to free.
147 * @param[in] uctx UNUSED.
148 */
149static void _pcre2_talloc_free(void *to_free, UNUSED void *uctx)
150{
151 talloc_free(to_free);
152}
153
154/** Free thread local data
155 *
156 * @param[in] tls Thread local data to free.
157 */
158static int _pcre2_tls_free(fr_pcre2_tls_t *tls)
159{
160 if (tls->gcontext) pcre2_general_context_free(tls->gcontext);
161 if (tls->ccontext) pcre2_compile_context_free(tls->ccontext);
162 if (tls->mcontext) pcre2_match_context_free(tls->mcontext);
163#ifdef PCRE2_CONFIG_JIT
164 if (tls->jit_stack) pcre2_jit_stack_free(tls->jit_stack);
165#endif
166
167 return 0;
168}
169
170static int _pcre2_tls_free_on_exit(void *arg)
171{
172 return talloc_free(arg);
173}
174
175/** Thread local init for pcre2
176 *
177 */
178static int fr_pcre2_tls_init(void)
179{
180 fr_pcre2_tls_t *tls;
181
182 if (unlikely(fr_pcre2_tls != NULL)) return 0;
183
184 fr_pcre2_tls = tls = talloc_zero(NULL, fr_pcre2_tls_t);
185 if (!tls) return -1;
186 talloc_set_destructor(tls, _pcre2_tls_free);
187
188 tls->gcontext = pcre2_general_context_create(_pcre2_talloc, _pcre2_talloc_free, NULL);
189 if (!tls->gcontext) {
190 fr_strerror_const("Failed allocating general context");
191 return -1;
192 }
193
194 tls->ccontext = pcre2_compile_context_create(tls->gcontext);
195 if (!tls->ccontext) {
196 fr_strerror_const("Failed allocating compile context");
197 error:
198 fr_pcre2_tls = NULL;
199 _pcre2_tls_free(tls);
200 return -1;
201 }
202
203#ifdef FR_PCRE2_HAVE_MAX_PATTERN_LENGTH
204 /*
205 * Cap memory usage. Patterns over this limit will fail
206 * with an error in pcre2_compile() or regex_compile().
207 */
208 pcre2_set_max_pattern_length(tls->ccontext, FR_PCRE2_MAX_PATTERN_LENGTH);
209#endif
210
211 tls->mcontext = pcre2_match_context_create(tls->gcontext);
212 if (!tls->mcontext) {
213 fr_strerror_const("Failed allocating match context");
214 goto error;
215 }
216
217#ifdef PCRE2_CONFIG_JIT
218 pcre2_config(PCRE2_CONFIG_JIT, &tls->do_jit);
219 if (tls->do_jit) {
220 tls->jit_stack = pcre2_jit_stack_create(FR_PCRE_JIT_STACK_MIN, FR_PCRE_JIT_STACK_MAX, tls->gcontext);
221 if (!tls->jit_stack) {
222 fr_strerror_const("Failed allocating JIT stack");
223 goto error;
224 }
225 pcre2_jit_stack_assign(tls->mcontext, NULL, tls->jit_stack);
226 }
227#endif
228
229 /*
230 * Free on thread exit
231 */
232 fr_atexit_thread_local(fr_pcre2_tls, _pcre2_tls_free_on_exit, tls);
233 fr_pcre2_tls = tls; /* Assign to thread local storage */
234
235 return 0;
236}
237
238/** Free regex_t structure
239 *
240 * Calls libpcre specific free functions for the expression and study.
241 *
242 * @param preg to free.
243 */
244static int _regex_free(regex_t *preg)
245{
246 if (preg->compiled) pcre2_code_free(preg->compiled);
247
248 return 0;
249}
250
251/** Wrapper around pcre2_compile
252 *
253 * Allows the rest of the code to do compilations using one function signature.
254 *
255 * @note Compiled expression must be freed with talloc_free.
256 *
257 * @param[out] out Where to write out a pointer to the structure containing
258 * the compiled expression.
259 * @param[in] pattern to compile.
260 * @param[in] len of pattern.
261 * @param[in] flags controlling matching. May be NULL.
262 * @param[in] subcaptures Whether to compile the regular expression to store subcapture
263 * data.
264 * @param[in] runtime If false run the pattern through the PCRE JIT (if available)
265 * to convert it to machine code. This trades startup time (longer)
266 * for runtime performance (better).
267 * @return
268 * - >= 1 on success.
269 * - <= 0 on error. Negative value is offset of parse error.
270 */
271ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **out, char const *pattern, size_t len,
272 fr_regex_flags_t const *flags, bool subcaptures, bool runtime)
273{
274 int ret;
275 PCRE2_SIZE offset;
276 uint32_t cflags = 0;
277 regex_t *preg;
278
279 /*
280 * Check inputs
281 */
282 *out = NULL;
283
284 /*
285 * Thread local initialisation
286 */
287 if (unlikely(!fr_pcre2_tls) && (fr_pcre2_tls_init() < 0)) return -1;
288
289 if (len == 0) {
290 fr_strerror_const("Empty expression");
291 return 0;
292 }
293
294 /*
295 * Options
296 */
297 if (flags) {
298 /* flags->global implemented by substitution function */
299 if (flags->ignore_case) cflags |= PCRE2_CASELESS;
300 if (flags->multiline) cflags |= PCRE2_MULTILINE;
301 if (flags->dot_all) cflags |= PCRE2_DOTALL;
302 if (flags->unicode) cflags |= PCRE2_UTF;
303 if (flags->extended) cflags |= PCRE2_EXTENDED;
304 }
305
306 if (!subcaptures) cflags |= PCRE2_NO_AUTO_CAPTURE;
307
308 preg = talloc_zero(ctx, regex_t);
309 talloc_set_destructor(preg, _regex_free);
310
311 preg->compiled = pcre2_compile((PCRE2_SPTR8)pattern, len,
312 cflags, &ret, &offset, fr_pcre2_tls->ccontext);
313 if (!preg->compiled) {
314 PCRE2_UCHAR errbuff[128];
315
316 pcre2_get_error_message(ret, errbuff, sizeof(errbuff));
317 fr_strerror_printf("%s", (char *)errbuff);
318 talloc_free(preg);
319
320 return -(ssize_t)offset;
321 }
322
323 if (!runtime) {
324 preg->precompiled = true;
325
326#ifdef PCRE2_CONFIG_JIT
327 /*
328 * This is expensive, so only do it for
329 * expressions that are going to be
330 * evaluated repeatedly.
331 */
332 if (fr_pcre2_tls->do_jit) {
333 ret = pcre2_jit_compile(preg->compiled, PCRE2_JIT_COMPLETE);
334 if (ret < 0) {
335 PCRE2_UCHAR errbuff[128];
336
337 pcre2_get_error_message(ret, errbuff, sizeof(errbuff));
338 fr_strerror_printf("Pattern JIT failed: %s", (char *)errbuff);
339 talloc_free(preg);
340
341 return 0;
342 }
343 preg->jitd = true;
344 }
345#endif
346 }
347
348 *out = preg;
349
350 return len;
351}
352
353/** Wrapper around pcre2_exec
354 *
355 * @param[in] preg The compiled expression.
356 * @param[in] subject to match.
357 * @param[in] len Length of subject.
358 * @param[in] regmatch Array of match pointers.
359 * @return
360 * - -1 on failure.
361 * - 0 on no match.
362 * - 1 on match.
363 */
364int regex_exec(regex_t *preg, char const *subject, size_t len, fr_regmatch_t *regmatch)
365{
366 int ret;
367 uint32_t options = 0;
368
369 char *our_subject = NULL;
370 bool dup_subject = true;
371 pcre2_match_data *match_data;
372
373 /*
374 * Thread local initialisation
375 */
376 if (unlikely(!fr_pcre2_tls) && (fr_pcre2_tls_init() < 0)) return -1;
377
378 if (regmatch) {
379#ifdef PCRE2_COPY_MATCHED_SUBJECT
380 /*
381 * This is apparently only supported for pcre2_match
382 * NOT pcre2_jit_match.
383 */
384# ifdef PCRE2_CONFIG_JIT
385 if (!preg->jitd) {
386# endif
387 dup_subject = false;
388
389 /*
390 * If PCRE2_COPY_MATCHED_SUBJECT is available
391 * and set as an options flag, pcre2_match will
392 * strdup the subject string if pcre2_match is
393 * successful and store a pointer to it in the
394 * regmatch struct.
395 *
396 * The lifetime of the string memory will be
397 * bound to the regmatch struct. This is more
398 * efficient that doing it ourselves, as the
399 * strdup only occurs if the subject matches.
400 */
401 options |= PCRE2_COPY_MATCHED_SUBJECT;
402# ifdef PCRE2_CONFIG_JIT
403 }
404# endif
405#endif
406 if (dup_subject) {
407 /*
408 * We have to dup and operate on the duplicate
409 * of the subject, because pcre2_jit_match and
410 * pcre2_match store a pointer to the subject
411 * in the regmatch structure.
412 */
413 subject = our_subject = talloc_bstrndup(regmatch, subject, len);
414 if (!subject) {
415 fr_strerror_const("Out of memory");
416 return -1;
417 }
418#ifndef NDEBUG
419 regmatch->subject = subject; /* Stored only for tracking memory issues */
420#endif
421 }
422 }
423
424 /*
425 * If we weren't given match data we
426 * need to alloc it else pcre2_match
427 * fails when passed NULL match data.
428 */
429 if (!regmatch) {
430 match_data = pcre2_match_data_create_from_pattern(preg->compiled, fr_pcre2_tls->gcontext);
431 if (!match_data) {
432 fr_strerror_const("Failed allocating temporary match data");
433 return -1;
434 }
435 } else {
436 match_data = regmatch->match_data;
437 }
438
439#ifdef PCRE2_CONFIG_JIT
440 if (preg->jitd) {
441 ret = pcre2_jit_match(preg->compiled, (PCRE2_SPTR8)subject, len, 0, options,
442 match_data, fr_pcre2_tls->mcontext);
443 } else
444#endif
445 {
446 ret = pcre2_match(preg->compiled, (PCRE2_SPTR8)subject, len, 0, options,
447 match_data, fr_pcre2_tls->mcontext);
448 }
449 if (!regmatch) pcre2_match_data_free(match_data);
450 if (ret < 0) {
451 PCRE2_UCHAR errbuff[128];
452
453 if (dup_subject) talloc_free(our_subject);
454
455 if (ret == PCRE2_ERROR_NOMATCH) {
456 if (regmatch) regmatch->used = 0;
457 return 0;
458 }
459
460 pcre2_get_error_message(ret, errbuff, sizeof(errbuff));
461 fr_strerror_printf("regex evaluation failed with code (%i): %s", ret, errbuff);
462
463 return -1;
464 }
465
466 if (regmatch) regmatch->used = ret;
467
468 return 1;
469}
470
471/** Wrapper around pcre2_substitute
472 *
473 * @param[in] ctx to allocate output string in.
474 * @param[out] out Output string with replacements performed.
475 * @param[in] max_out Maximum length of output buffer. If this is 0 then
476 * the output length is unlimited.
477 * @param[in] preg The compiled expression.
478 * @param[in] flags that affect matching.
479 * @param[in] subject to perform replacements on.
480 * @param[in] subject_len the length of the subject.
481 * @param[in] replacement replacement string containing substitution
482 * markers.
483 * @param[in] replacement_len Length of the replacement string.
484 * @param[in] regmatch Array of match pointers.
485 * @return
486 * - >= 0 the length of the output string.
487 * - < 0 on error.
488 */
489int regex_substitute(TALLOC_CTX *ctx, char **out, size_t max_out, regex_t *preg, fr_regex_flags_t const *flags,
490 char const *subject, size_t subject_len,
491 char const *replacement, size_t replacement_len,
492 fr_regmatch_t *regmatch)
493{
494 int ret;
495 uint32_t options = 0;
496 size_t buff_len, actual_len;
497 char *buff;
498
499#ifndef PCRE2_COPY_MATCHED_SUBJECT
500 char *our_subject = NULL;
501#endif
502
503 /*
504 * Thread local initialisation
505 */
506 if (unlikely(!fr_pcre2_tls) && (fr_pcre2_tls_init() < 0)) return -1;
507
508 /*
509 * Internally pcre2_substitute just calls pcre2_match to
510 * generate the match data, so the same hack as the
511 * regex_exec function above is required.
512 */
513 if (regmatch) {
514#ifndef PCRE2_COPY_MATCHED_SUBJECT
515 /*
516 * We have to dup and operate on the duplicate
517 * of the subject, because pcre2_jit_match and
518 * pcre2_match store a pointer to the subject
519 * in the regmatch structure.
520 */
521 subject = our_subject = talloc_bstrndup(regmatch, subject, subject_len);
522 if (!subject) {
523 fr_strerror_const("Out of memory");
524 return -1;
525 }
526#else
527 /*
528 * If PCRE2_COPY_MATCHED_SUBJECT is available
529 * and set as an options flag, pcre2_match will
530 * strdup the subject string if pcre2_match is
531 * successful and store a pointer to it in the
532 * regmatch struct.
533 *
534 * The lifetime of the string memory will be
535 * bound to the regmatch struct. This is more
536 * efficient that doing it ourselves, as the
537 * strdup only occurs if the subject matches.
538 */
539 options |= PCRE2_COPY_MATCHED_SUBJECT;
540#endif
541 }
542
543 /*
544 * Guess (badly) what the length of the output buffer should be
545 */
546 actual_len = buff_len = subject_len + 1; /* +1 for the \0 */
547 buff = talloc_array(ctx, char, buff_len);
548 if (!buff) {
549#ifndef PCRE2_COPY_MATCHED_SUBJECT
550 talloc_free(our_subject);
551#endif
552 fr_strerror_const("Out of memory");
553 return -1;
554 }
555
556 options |= PCRE2_SUBSTITUTE_OVERFLOW_LENGTH;
557 if (flags->global) options |= PCRE2_SUBSTITUTE_GLOBAL;
558
559again:
560 /*
561 * actual_len input value should be the size of the
562 * buffer including space for '\0'.
563 * If input buffer is too small, then actual_len will be set
564 * to the buffer space needed including space for '\0'.
565 * If input buffer is the correct size, then actual_len
566 * will be set to the size of the string written to buff
567 * without the terminating '\0'.
568 */
569 ret = pcre2_substitute(preg->compiled,
570 (PCRE2_SPTR8)subject, (PCRE2_SIZE)subject_len, 0,
571 options, NULL, fr_pcre2_tls->mcontext,
572 (PCRE2_UCHAR const *)replacement, replacement_len, (PCRE2_UCHAR *)buff, &actual_len);
573
574 if (ret < 0) {
575 PCRE2_UCHAR errbuff[128];
576
577#ifndef PCRE2_COPY_MATCHED_SUBJECT
578 talloc_free(our_subject);
579#endif
581
582 if (ret == PCRE2_ERROR_NOMEMORY) {
583 if ((max_out > 0) && (actual_len > max_out)) {
584 fr_strerror_printf("String length with substitutions (%zu) "
585 "exceeds max string length (%zu)", actual_len - 1, max_out - 1);
586 return -1;
587 }
588
589 /*
590 * Check that actual_len != buff_len as that'd be
591 * an actual error.
592 */
593 if (actual_len == buff_len) {
594 fr_strerror_const("libpcre2 out of memory");
595 return -1;
596 }
597 buff_len = actual_len; /* The length we get passed back includes the \0 */
598 buff = talloc_array(ctx, char, buff_len);
599 if (!buff) {
600 fr_strerror_const("Out of memory");
601 return -1;
602 }
603 goto again;
604 }
605
606 if (ret == PCRE2_ERROR_NOMATCH) {
607 if (regmatch) regmatch->used = 0;
608 return 0;
609 }
610
611 pcre2_get_error_message(ret, errbuff, sizeof(errbuff));
612 fr_strerror_printf("regex evaluation failed with code (%i): %s", ret, errbuff);
613 return -1;
614 }
615
616 /*
617 * Trim the replacement buffer to the correct length
618 *
619 * buff_len includes \0.
620 * ...and as pcre2_substitute just succeeded actual_len does not include \0.
621 */
622 if (actual_len < (buff_len - 1)) {
623 buff = talloc_bstr_realloc(ctx, buff, actual_len);
624 if (!buff) {
625 fr_strerror_const("reallocing pcre2_substitute result buffer failed");
626 return -1;
627 }
628 }
629
630 if (regmatch) regmatch->used = ret;
631 *out = buff;
632
633 return 1;
634}
635
636
637/** Returns the number of subcapture groups
638 *
639 * @return
640 * - >0 The number of subcaptures contained within the pattern
641 * - 0 if the number of subcaptures can't be determined.
642 */
643uint32_t regex_subcapture_count(regex_t const *preg)
644{
646
647 if (pcre2_pattern_info(preg->compiled, PCRE2_INFO_CAPTURECOUNT, &count) != 0) {
648 fr_strerror_const("Error determining subcapture group count");
649 return 0;
650 }
651
652 return count + 1;
653}
654
655/** Free libpcre2's matchdata
656 *
657 * @note Don't call directly, will be called if talloc_free is called on a #regmatch_t.
658 */
659static int _pcre2_match_data_free(fr_regmatch_t *regmatch)
660{
661 pcre2_match_data_free(regmatch->match_data);
662 return 0;
663}
664
665/** Allocate vectors to fill with match data
666 *
667 * @param[in] ctx to allocate match vectors in.
668 * @param[in] count The number of vectors to allocate.
669 * @return
670 * - NULL on error.
671 * - Array of match vectors.
672 */
673fr_regmatch_t *regex_match_data_alloc(TALLOC_CTX *ctx, uint32_t count)
674{
675 fr_regmatch_t *regmatch;
676
677 /*
678 * Thread local initialisation
679 */
680 if (unlikely(!fr_pcre2_tls) && (fr_pcre2_tls_init() < 0)) return NULL;
681
682 regmatch = talloc(ctx, fr_regmatch_t);
683 if (!regmatch) {
684 oom:
685 fr_strerror_const("Out of memory");
686 return NULL;
687 }
688
689 regmatch->match_data = pcre2_match_data_create(count, fr_pcre2_tls->gcontext);
690 if (!regmatch->match_data) {
691 talloc_free(regmatch);
692 goto oom;
693 }
694 talloc_set_type(regmatch->match_data, pcre2_match_data);
695
696 talloc_set_destructor(regmatch, _pcre2_match_data_free);
697
698 return regmatch;
699}
700
701/*
702 *######################################
703 *# FUNCTIONS FOR POSIX-REGEX #
704 *######################################
705 */
706# else
707/*
708 * Wrapper functions for POSIX like, and extended regular
709 * expressions. These use the system regex library.
710 */
711
712/** Free heap allocated regex_t structure
713 *
714 * Heap allocation of regex_t is needed so regex_compile has the same signature with
715 * POSIX or libpcre.
716 *
717 * @param preg to free.
718 */
719static int _regex_free(regex_t *preg)
720{
721 regfree(preg);
722
723 return 0;
724}
725
726/** Binary safe wrapper around regcomp
727 *
728 * If we have the BSD extensions we don't need to do any special work
729 * if we don't have the BSD extensions we need to check to see if the
730 * regular expression contains any \0 bytes.
731 *
732 * If it does we fail and print the appropriate error message.
733 *
734 * @note Compiled expression must be freed with talloc_free.
735 *
736 * @param[in] ctx To allocate memory in.
737 * @param[out] out Where to write out a pointer
738 * to the structure containing the compiled expression.
739 * @param[in] pattern to compile.
740 * @param[in] len of pattern.
741 * @param[in] flags controlling matching. May be NULL.
742 * @param[in] subcaptures Whether to compile the regular expression
743 * to store subcapture data.
744 * @param[in] runtime Whether the compilation is being done at runtime.
745 * @return
746 * - >= 1 on success.
747 * - <= 0 on error. Negative value is offset of parse error.
748 * With POSIX regex we only give the correct offset for embedded \0 errors.
749 */
750ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **out, char const *pattern, size_t len,
751 fr_regex_flags_t const *flags, bool subcaptures, UNUSED bool runtime)
752{
753 int ret;
754 int cflags = REG_EXTENDED;
755 regex_t *preg;
756
757 if (len == 0) {
758 fr_strerror_const("Empty expression");
759 return 0;
760 }
761
762 /*
763 * Options
764 */
765 if (flags) {
766 if (flags->global) {
767 fr_strerror_const("g - Global matching/substitution not supported with posix-regex");
768 return 0;
769 }
770 if (flags->dot_all) {
771 fr_strerror_const("s - Single line matching is not supported with posix-regex");
772 return 0;
773 }
774 if (flags->unicode) {
775 fr_strerror_const("u - Unicode matching not supported with posix-regex");
776 return 0;
777 }
778 if (flags->extended) {
779 fr_strerror_const("x - Whitespace and comments not supported with posix-regex");
780 return 0;
781 }
782
783 if (flags->ignore_case) cflags |= REG_ICASE;
784 if (flags->multiline) cflags |= REG_NEWLINE;
785 }
786
787
788 if (!subcaptures) cflags |= REG_NOSUB;
789
790#ifndef HAVE_REGNCOMP
791 {
792 char const *p;
793
794 p = pattern;
795 p += strlen(pattern);
796
797 if ((size_t)(p - pattern) != len) {
798 fr_strerror_printf("Found null in pattern at offset %zu. Pattern unsafe for compilation",
799 (p - pattern));
800 return -(p - pattern);
801 }
802
803 preg = talloc_zero(ctx, regex_t);
804 if (!preg) return 0;
805
806 ret = regcomp(preg, pattern, cflags);
807 }
808#else
809 preg = talloc_zero(ctx, regex_t);
810 if (!preg) return 0;
811 ret = regncomp(preg, pattern, len, cflags);
812#endif
813 if (ret != 0) {
814 char errbuf[128];
815
816 regerror(ret, preg, errbuf, sizeof(errbuf));
817 fr_strerror_printf("%s", errbuf);
818
819 talloc_free(preg);
820
821 return 0; /* POSIX expressions don't give us the failure offset */
822 }
823
824 talloc_set_destructor(preg, _regex_free);
825 *out = preg;
826
827 return len;
828}
829
830/** Binary safe wrapper around regexec
831 *
832 * If we have the BSD extensions we don't need to do any special work
833 * If we don't have the BSD extensions we need to check to see if the
834 * value to be compared contains any \0 bytes.
835 *
836 * If it does, we fail and print the appropriate error message.
837 *
838 * @param[in] preg The compiled expression.
839 * @param[in] subject to match.
840 * @param[in] regmatch Match result structure.
841 * @return
842 * - -1 on failure.
843 * - 0 on no match.
844 * - 1 on match.
845 */
846int regex_exec(regex_t *preg, char const *subject, size_t len, fr_regmatch_t *regmatch)
847{
848 int ret;
849 size_t matches;
850
851 /*
852 * Disable capturing
853 */
854 if (!regmatch) {
855 matches = 0;
856 } else {
857 matches = regmatch->allocd;
858
859 /*
860 * Reset the match result structure
861 */
862 memset(regmatch->match_data, 0, sizeof(regmatch->match_data[0]) * matches);
863 regmatch->used = 0;
864 }
865
866#ifndef HAVE_REGNEXEC
867 {
868 char const *p;
869
870 p = subject;
871 p += strlen(subject);
872
873 if ((size_t)(p - subject) != len) {
874 fr_strerror_printf("Found null in subject at offset %zu. String unsafe for evaluation",
875 (p - subject));
876 if (regmatch) regmatch->used = 0;
877 return -1;
878 }
879 ret = regexec(preg, subject, matches, regmatch ? regmatch->match_data : NULL, 0);
880 }
881#else
882 ret = regnexec(preg, subject, len, matches, regmatch ? regmatch->match_data : NULL, 0);
883#endif
884 if (ret != 0) {
885 if (ret != REG_NOMATCH) {
886 char errbuf[128];
887
888 regerror(ret, preg, errbuf, sizeof(errbuf));
889
890 fr_strerror_printf("regex evaluation failed: %s", errbuf);
891 return -1;
892 }
893 return 0;
894 }
895
896 /*
897 * Update regmatch->count to be the maximum number of
898 * groups that *could* have been populated as we don't
899 * have the number of matches.
900 */
901 if (regmatch) {
902 regmatch->used = preg->re_nsub + 1;
903
904 if (regmatch->subject) talloc_const_free(regmatch->subject);
905 regmatch->subject = talloc_bstrndup(regmatch, subject, len);
906 if (!regmatch->subject) {
907 fr_strerror_const("Out of memory");
908 return -1;
909 }
910 }
911 return 1;
912}
913
914/** Returns the number of subcapture groups
915 *
916 * @return
917 * - 0 we can't determine this for POSIX regular expressions.
918 */
919uint32_t regex_subcapture_count(UNUSED regex_t const *preg)
920{
921 return 0;
922}
923# endif
924
925# if defined(HAVE_REGEX_POSIX)
926/** Allocate vectors to fill with match data
927 *
928 * @param[in] ctx to allocate match vectors in.
929 * @param[in] count The number of vectors to allocate.
930 * @return
931 * - NULL on error.
932 * - Array of match vectors.
933 */
934fr_regmatch_t *regex_match_data_alloc(TALLOC_CTX *ctx, uint32_t count)
935{
936 fr_regmatch_t *regmatch;
937
938 /*
939 * Pre-allocate space for the match structure
940 * and for a 128b subject string.
941 */
942 regmatch = talloc_zero_pooled_object(ctx, fr_regmatch_t, 2, (sizeof(regmatch_t) * count) + 128);
943 if (unlikely(!regmatch)) {
944 error:
945 fr_strerror_const("Out of memory");
946 talloc_free(regmatch);
947 return NULL;
948 }
949 regmatch->match_data = talloc_array(regmatch, regmatch_t, count);
950 if (unlikely(!regmatch->match_data)) goto error;
951
952 regmatch->allocd = count;
953 regmatch->used = 0;
954 regmatch->subject = NULL;
955
956 return regmatch;
957}
958# endif
959
960/*
961 *########################################
962 *# UNIVERSAL FUNCTIONS #
963 *########################################
964 */
965
966/** Parse a string containing one or more regex flags
967 *
968 * @param[out] err May be NULL. If not NULL will be set to:
969 * - 0 on success.
970 * - -1 on unknown flag.
971 * - -2 on duplicate.
972 * @param[out] out Flag structure to populate. Must be initialised to zero
973 * if this is the first call to regex_flags_parse.
974 * @param[in] in Flag string to parse.
975 * @param[in] terminals Terminal characters. If parsing ends before the buffer
976 * is exhausted, and is pointing to one of these chars
977 * it's not considered an error.
978 * @param[in] err_on_dup Error if the flag is already set.
979 * @return
980 * - > 0 on success. The number of flag bytes parsed.
981 * - <= 0 on failure. Negative offset of first unrecognised flag.
982 */
983fr_slen_t regex_flags_parse(int *err, fr_regex_flags_t *out, fr_sbuff_t *in,
984 fr_sbuff_term_t const *terminals, bool err_on_dup)
985{
986 fr_sbuff_t our_in = FR_SBUFF(in);
987
988 if (err) *err = 0;
989
990 while (fr_sbuff_extend(&our_in)) {
991 switch (*our_in.p) {
992#define DO_REGEX_FLAG(_f, _c) \
993 case _c: \
994 if (err_on_dup && out->_f) { \
995 fr_strerror_printf("Duplicate regex flag '%c'", *our_in.p); \
996 if (err) *err = -2; \
997 FR_SBUFF_ERROR_RETURN(&our_in); \
998 } \
999 out->_f = 1; \
1000 break
1001
1002 DO_REGEX_FLAG(global, 'g');
1003 DO_REGEX_FLAG(ignore_case, 'i');
1004 DO_REGEX_FLAG(multiline, 'm');
1005 DO_REGEX_FLAG(dot_all, 's');
1006 DO_REGEX_FLAG(unicode, 'u');
1007 DO_REGEX_FLAG(extended, 'x');
1008#undef DO_REGEX_FLAG
1009
1010 default:
1011 if (fr_sbuff_is_terminal(&our_in, terminals)) FR_SBUFF_SET_RETURN(in, &our_in);
1012
1013 fr_strerror_printf("Unsupported regex flag '%c'", *our_in.p);
1014 if (err) *err = -1;
1015 FR_SBUFF_ERROR_RETURN(&our_in);
1016 }
1017 fr_sbuff_advance(&our_in, 1);
1018 }
1019 FR_SBUFF_SET_RETURN(in, &our_in);
1020}
1021
1022/** Print the flags
1023 *
1024 * @param[out] sbuff where to write flags.
1025 * @param[in] flags to print.
1026 * @return
1027 * - The number of bytes written to the out buffer.
1028 * - A number >= outlen if truncation has occurred.
1029 */
1030ssize_t regex_flags_print(fr_sbuff_t *sbuff, fr_regex_flags_t const *flags)
1031{
1032 fr_sbuff_t our_sbuff = FR_SBUFF(sbuff);
1033
1034#define DO_REGEX_FLAG(_f, _c) \
1035 if (flags->_f) FR_SBUFF_IN_CHAR_RETURN(&our_sbuff, _c)
1036
1037 DO_REGEX_FLAG(global, 'g');
1038 DO_REGEX_FLAG(ignore_case, 'i');
1039 DO_REGEX_FLAG(multiline, 'm');
1040 DO_REGEX_FLAG(dot_all, 's');
1041 DO_REGEX_FLAG(unicode, 'u');
1042 DO_REGEX_FLAG(extended, 'x');
1043#undef DO_REGEX_FLAG
1044
1045 FR_SBUFF_SET_RETURN(sbuff, &our_sbuff);
1046}
1047#endif
1048
1049/** Compare two boxes using an operator
1050 *
1051 * @todo - allow /foo/i on the RHS
1052 *
1053 * However, this involves allocating intermediate sbuffs for the
1054 * unescaped RHS, and all kinds of extra work. It's not overly hard,
1055 * but it's something we wish to avoid for now.
1056 *
1057 * @param[in] op to use in comparison. MUST be T_OP_REG_EQ or T_OP_REG_NE
1058 * @param[in] a Value to compare, MUST be FR_TYPE_STRING
1059 * @param[in] b uncompiled regex as FR_TYPE_STRING
1060 * @return
1061 * - 1 if true
1062 * - 0 if false
1063 * - -1 on failure.
1064 */
1066{
1067 int rcode;
1068 TALLOC_CTX *ctx = NULL;
1069 size_t lhs_len;
1070 char const *lhs;
1071 regex_t *regex = NULL;
1072
1073 if (!((op == T_OP_REG_EQ) || (op == T_OP_REG_NE))) {
1074 fr_strerror_const("Invalid operator for regex comparison");
1075 return -1;
1076 }
1077
1078 if (b->type != FR_TYPE_STRING) {
1079 fr_strerror_const("RHS must be regular expression");
1080 return -1;
1081 }
1082
1083 ctx = talloc_init_const("regex_cmp_op");
1084 if (!ctx) return -1;
1085
1086 if ((a->type != FR_TYPE_STRING) && (a->type != FR_TYPE_OCTETS)) {
1087 fr_slen_t slen;
1088 char *p;
1089
1090 slen = fr_value_box_aprint(ctx, &p, a, NULL); /* no escaping */
1091 if (slen < 0) return slen;
1092
1093 lhs = p;
1094 lhs_len = slen;
1095
1096 } else {
1097 lhs = a->vb_strvalue;
1098 lhs_len = a->vb_length;
1099 }
1100
1101 if (regex_compile(ctx, &regex, b->vb_strvalue, b->vb_length, NULL, false, true) < 0) {
1102 talloc_free(ctx);
1103 return -1;
1104 }
1105
1106#ifdef STATIC_ANALYZER
1107 if (!regex) {
1108 talloc_free(ctx);
1109 return -1;
1110 }
1111#endif
1112
1113 rcode = regex_exec(regex, lhs, lhs_len, NULL);
1114 talloc_free(ctx);
1115 if (rcode < 0) return rcode;
1116
1117 /*
1118 * Invert the sense of the rcode for !~
1119 */
1120 if (op == T_OP_REG_NE) rcode = (rcode == 0);
1121
1122 return rcode;
1123}
#define _Thread_local
Definition atexit.h:213
#define fr_atexit_thread_local(_name, _free, _uctx)
Definition atexit.h:224
#define RCSID(id)
Definition build.h:560
#define unlikely(_x)
Definition build.h:455
#define UNUSED
Definition build.h:384
talloc_free(hp)
@ 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:2311
#define fr_sbuff_extend(_sbuff_or_marker)
#define FR_SBUFF_ERROR_RETURN(_sbuff_or_marker)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define SBUFF_CHAR_UNPRINTABLES_EXTENDED
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define SBUFF_CHAR_UNPRINTABLES_LOW
Set of terminal elements.
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:37
return count
Definition module.c:155
char * talloc_bstr_realloc(TALLOC_CTX *ctx, char *in, size_t inlen)
Trim a bstr (char) buffer.
Definition talloc.c:757
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:693
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition talloc.h:209
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:289
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
Definition talloc.h:127
enum fr_token fr_token_t
@ T_OP_REG_EQ
Definition token.h:100
@ T_OP_REG_NE
Definition token.h:101
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:1065
#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_sbuff_err_t char size_t fr_sbuff_t * in
Definition value.h:1061
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 fr_sbuff_err_t char ** out
Definition value.h:1061
static fr_sbuff_err_t char size_t * len
Definition value.h:1061