26 #include <freeradius-devel/libradius.h>
27 #include <freeradius-devel/regex.h>
40 static int _regex_free(regex_t *preg)
42 if (preg->compiled) pcre_free(preg->compiled);
43 #ifdef PCRE_CONFIG_JIT
44 if (preg->extra) pcre_free_study(preg->extra);
46 if (preg->extra) pcre_free(preg->extra);
57 static void *_pcre_malloc(
size_t to_alloc) {
58 return talloc_array(NULL, uint8_t, to_alloc);
61 static void _pcre_free(
void *to_free) {
84 ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **out,
char const *pattern,
size_t len,
85 bool ignore_case,
bool multiline,
bool subcaptures,
bool runtime)
98 pcre_malloc = _pcre_malloc;
99 pcre_free = _pcre_free;
109 if (ignore_case) cflags |= PCRE_CASELESS;
110 if (multiline) cflags |= PCRE_MULTILINE;
111 if (!subcaptures) cflags |= PCRE_NO_AUTO_CAPTURE;
113 preg = talloc_zero(ctx, regex_t);
114 talloc_set_destructor(preg, _regex_free);
116 preg->compiled = pcre_compile(pattern, cflags, &error, &offset, NULL);
117 if (!preg->compiled) {
121 return -(ssize_t)offset;
124 preg->precompiled =
true;
125 preg->extra = pcre_study(preg->compiled, PCRE_STUDY_JIT_COMPILE, &error);
140 {
"PCRE_ERROR_NOMATCH", PCRE_ERROR_NOMATCH },
141 {
"PCRE_ERROR_NULL", PCRE_ERROR_NULL },
142 {
"PCRE_ERROR_BADOPTION", PCRE_ERROR_BADOPTION },
143 {
"PCRE_ERROR_BADMAGIC", PCRE_ERROR_BADMAGIC },
144 {
"PCRE_ERROR_UNKNOWN_OPCODE", PCRE_ERROR_UNKNOWN_OPCODE },
145 {
"PCRE_ERROR_NOMEMORY", PCRE_ERROR_NOMEMORY },
146 {
"PCRE_ERROR_NOSUBSTRING", PCRE_ERROR_NOSUBSTRING },
147 {
"PCRE_ERROR_MATCHLIMIT", PCRE_ERROR_MATCHLIMIT },
148 {
"PCRE_ERROR_CALLOUT", PCRE_ERROR_CALLOUT },
149 {
"PCRE_ERROR_BADUTF8", PCRE_ERROR_BADUTF8 },
150 {
"PCRE_ERROR_BADUTF8_OFFSET", PCRE_ERROR_BADUTF8_OFFSET },
151 {
"PCRE_ERROR_PARTIAL", PCRE_ERROR_PARTIAL },
152 {
"PCRE_ERROR_BADPARTIAL", PCRE_ERROR_BADPARTIAL },
153 {
"PCRE_ERROR_INTERNAL", PCRE_ERROR_INTERNAL },
154 {
"PCRE_ERROR_BADCOUNT", PCRE_ERROR_BADCOUNT },
155 {
"PCRE_ERROR_DFA_UITEM", PCRE_ERROR_DFA_UITEM },
156 {
"PCRE_ERROR_DFA_UCOND", PCRE_ERROR_DFA_UCOND },
157 {
"PCRE_ERROR_DFA_UMLIMIT", PCRE_ERROR_DFA_UMLIMIT },
158 {
"PCRE_ERROR_DFA_WSSIZE", PCRE_ERROR_DFA_WSSIZE },
159 {
"PCRE_ERROR_DFA_RECURSE", PCRE_ERROR_DFA_RECURSE },
160 {
"PCRE_ERROR_RECURSIONLIMIT", PCRE_ERROR_RECURSIONLIMIT },
161 {
"PCRE_ERROR_NULLWSLIMIT", PCRE_ERROR_NULLWSLIMIT },
162 {
"PCRE_ERROR_BADNEWLINE", PCRE_ERROR_BADNEWLINE },
178 int regex_exec(regex_t *preg,
char const *subject,
size_t len, regmatch_t pmatch[],
size_t *nmatch)
190 if (!pmatch || !nmatch) {
192 if (nmatch) *nmatch = 0;
198 ret = pcre_exec(preg->compiled, preg->extra, subject, len, 0, 0, (
int *)pmatch, matches * 3);
200 if (ret == PCRE_ERROR_NOMATCH)
return 0;
203 fr_int2str(regex_pcre_error_str, ret,
"<INVALID>"));
211 if (nmatch && (ret > 0)) *nmatch = ret;
227 static int _regex_free(regex_t *preg)
259 ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **out,
char const *pattern,
size_t len,
260 bool ignore_case,
bool multiline,
bool subcaptures,
UNUSED bool runtime)
263 int cflags = REG_EXTENDED;
271 if (ignore_case) cflags |= REG_ICASE;
272 if (multiline) cflags |= REG_NEWLINE;
273 if (!subcaptures) cflags |= REG_NOSUB;
275 #ifndef HAVE_REGNCOMP
280 p += strlen(pattern);
282 if ((
size_t)(p - pattern) != len) {
283 fr_strerror_printf(
"Found null in pattern at offset %zu. Pattern unsafe for compilation",
285 return -(p - pattern);
288 preg = talloc_zero(ctx, regex_t);
291 ret = regcomp(preg, pattern, cflags);
294 preg = talloc_zero(ctx, regex_t);
296 ret = regncomp(preg, pattern, len, cflags);
301 regerror(ret, preg, errbuf,
sizeof(errbuf));
309 talloc_set_destructor(preg, _regex_free);
332 int regex_exec(regex_t *preg,
char const *subject,
size_t len, regmatch_t pmatch[],
size_t *nmatch)
340 if (!pmatch || !nmatch) {
342 if (nmatch) *nmatch = 0;
347 memset(pmatch, 0,
sizeof(pmatch[0]) * matches);
350 #ifndef HAVE_REGNEXEC
355 p += strlen(subject);
357 if ((
size_t)(p - subject) != len) {
358 fr_strerror_printf(
"Found null in subject at offset %zu. String unsafe for evaluation",
362 ret = regexec(preg, subject, matches, pmatch, 0);
365 ret = regnexec(preg, subject, len, matches, pmatch, 0);
368 if (ret != REG_NOMATCH) {
371 regerror(ret, preg, errbuf,
sizeof(errbuf));
374 if (nmatch) *nmatch = 0;
385 if (nmatch && (*nmatch > preg->re_nsub)) *nmatch = preg->re_nsub + 1;
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)