printf "%s\n" "#define HAVE_BINSAFE_REGEX 1" >>confdefs.h
fi
- fi
-
- if test "x$REGEX" != "xyes"; then
-
-
-ac_safe=`echo "pcre.h" | sed 'y%./+-%__pm%'`
-
-if test "x" = "x"; then
- sm_pkg=`echo "${ac_safe}" | sed 's/.h//;s/^lib//'`
-else
- sm_pkg=""
-fi
-
-old_CPPFLAGS="$CPPFLAGS"
-smart_include_dir="/usr/local/include /opt/include /usr/local/${sm_pkg}/include /opt/homebrew/include /opt/homebrew/opt/${sm_pkg}/include"
-
-_smart_try_dir=
-_smart_include_dir=
-
-for _prefix in $smart_prefix ""; do
-for _dir in $smart_try_dir; do
- _smart_try_dir="${_smart_try_dir} ${_dir}/${_prefix}"
-done
-
-for _dir in $smart_include_dir; do
- _smart_include_dir="${_smart_include_dir} ${_dir}/${_prefix}"
-done
-done
-
-if test "x$_smart_try_dir" != "x"; then
-for try in $_smart_try_dir; do
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcre.h in $try" >&5
-printf %s "checking for pcre.h in $try... " >&6; }
- CPPFLAGS="-isystem $try $old_CPPFLAGS"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-
- #include <pcre.h>
-
-int
-main (void)
-{
-
- int a = 1;
-
-
- ;
- return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
- smart_include="-isystem $try"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- break
-
-else case e in #(
- e)
- smart_include=
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-done
-CPPFLAGS="$old_CPPFLAGS"
-fi
-
-if test "x$smart_include" = "x"; then
-for _prefix in $smart_prefix; do
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/pcre.h" >&5
-printf %s "checking for ${_prefix}/pcre.h... " >&6; }
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-
- #include <pcre.h>
-
-int
-main (void)
-{
-
- int a = 1;
-
-
- ;
- return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
- smart_include="-isystem ${_prefix}/"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- break
-
-else case e in #(
- e)
- smart_include=
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-done
-fi
-
-if test "x$smart_include" = "x"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcre.h" >&5
-printf %s "checking for pcre.h... " >&6; }
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-
- #include <pcre.h>
-
-int
-main (void)
-{
-
- int a = 1;
-
-
- ;
- return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
- smart_include=" "
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- break
-
-else case e in #(
- e)
- smart_include=
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-if test "x$smart_include" = "x"; then
-for try in $_smart_include_dir; do
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcre.h in $try" >&5
-printf %s "checking for pcre.h in $try... " >&6; }
- CPPFLAGS="-isystem $try $old_CPPFLAGS"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-
- #include <pcre.h>
-
-int
-main (void)
-{
-
- int a = 1;
-
-
- ;
- return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
- smart_include="-isystem $try"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- break
-
-else case e in #(
- e)
- smart_include=
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-done
-CPPFLAGS="$old_CPPFLAGS"
-fi
-
-if test "x$smart_include" != "x"; then
-eval "ac_cv_header_$ac_safe=yes"
-CPPFLAGS="$smart_include $old_CPPFLAGS"
-SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
-fi
-
-smart_prefix=
-
- if test "x$ac_cv_header_pcre_h" = "xyes"; then
- smart_try_dir=$pcre_lib_dir
-
-
-sm_lib_safe=`echo "pcre" | sed 'y%./+-%__p_%'`
-sm_func_safe=`echo "pcre_compile" | sed 'y%./+-%__p_%'`
-
-if test "x" = "x"; then
- sm_pkg="${sm_lib_safe}"
-else
- sm_pkg=""
-fi
-
-old_LIBS="$LIBS"
-old_CPPFLAGS="$CPPFLAGS"
-smart_lib=
-smart_ldflags=
-smart_lib_dir="/usr/local/lib /opt/lib /usr/local/${sm_pkg}/lib /opt/homebrew/lib /opt/homebrew/opt/${sm_pkg}/lib"
-
-if test "x$smart_try_dir" != "x"; then
-for try in $smart_try_dir; do
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcre_compile in -lpcre in $try" >&5
-printf %s "checking for pcre_compile in -lpcre in $try... " >&6; }
- LIBS="-lpcre $old_LIBS"
- CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-extern char pcre_compile();
-int
-main (void)
-{
-pcre_compile()
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-
- smart_lib="-lpcre"
- smart_ldflags="-L$try -Wl,-rpath,$try"
- smart_ld_found="$try"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- break
-
-else case e in #(
- e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; } ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-done
-LIBS="$old_LIBS"
-CPPFLAGS="$old_CPPFLAGS"
-fi
-
-if test "x$smart_lib" = "x"; then
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcre_compile in -lpcre" >&5
-printf %s "checking for pcre_compile in -lpcre... " >&6; }
-LIBS="-lpcre $old_LIBS"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-extern char pcre_compile();
-int
-main (void)
-{
-pcre_compile()
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-
- smart_lib="-lpcre"
- smart_ld_found=""
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-
-else case e in #(
- e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; } ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS="$old_LIBS"
-fi
-
-if test "x$smart_lib" = "x"; then
-for try in $smart_lib_dir; do
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcre_compile in -lpcre in $try" >&5
-printf %s "checking for pcre_compile in -lpcre in $try... " >&6; }
- LIBS="-lpcre $old_LIBS"
- CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-extern char pcre_compile();
-int
-main (void)
-{
-pcre_compile()
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-
- smart_lib="-lpcre"
- smart_ldflags="-L$try -Wl,-rpath,$try"
- smart_ld_found="$try"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- break
-
-else case e in #(
- e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; } ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-done
-LIBS="$old_LIBS"
-CPPFLAGS="$old_CPPFLAGS"
-fi
-
-if test "x$smart_lib" != "x"; then
-eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
-LIBS="$smart_ldflags $smart_lib $old_LIBS"
-SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
-SMART_LD_FOUND="$smart_ld_found"
-fi
-
- if test "x$ac_cv_lib_pcre_pcre_compile" = "xyes"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking libpcre library and header version consistency" >&5
-printf %s "checking libpcre library and header version consistency... " >&6; }
- if test "$cross_compiling" = yes
-then :
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cross-compiling (assuming yes)" >&5
-printf "%s\n" "cross-compiling (assuming yes)" >&6; }
-
-
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
- #include <stdio.h>
- #include <pcre.h>
- #include <stdlib.h>
- #define XSTRINGIFY(x) #x
- #define STRINGIFY(x) XSTRINGIFY(x)
-
-int
-main (void)
-{
-
- char const *p = pcre_version();
- char *q;
- unsigned long ver;
-
- printf("library: %s header: %u.%u %s... ", p, PCRE_MAJOR, PCRE_MINOR, STRINGIFY(PCRE_DATE));
-
- ver = strtoul(p, &q, 10);
- if (*q != '.') return 1;
- if (ver != PCRE_MAJOR) return 65;
- p = ++q;
-
- ver = strtoul(p, &q, 10);
- if (ver != PCRE_MINOR) return 1;
-
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"
-then :
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- REGEX=yes
-
-printf "%s\n" "#define HAVE_REGEX_PCRE 1" >>confdefs.h
-
-
-printf "%s\n" "#define HAVE_BINSAFE_REGEX 1" >>confdefs.h
-
-
-else case e in #(
- e)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
-as_fn_error $? "libpcre library version does not match header version
-See 'config.log' for more details" "$LINENO" 5; }
- ;;
-esac
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
-esac
-fi
-
- fi
- fi
fi
fi
smart_try_dir=$pcre_include_dir
dnl #
- dnl # Prefer libpcre2 over libpcre
+ dnl # Check for libpcre2
dnl #
FR_SMART_CHECK_INCLUDE(pcre2.h,[#define PCRE2_CODE_UNIT_WIDTH (8)])
if test "x$ac_cv_header_pcre2_h" = "xyes"; then
AC_DEFINE(HAVE_BINSAFE_REGEX, 1, [Define if we have a binary safe regular expression library])
fi
fi
-
- dnl #
- dnl # Fallback to libpcre
- dnl #
- if test "x$REGEX" != "xyes"; then
- FR_SMART_CHECK_INCLUDE(pcre.h)
- if test "x$ac_cv_header_pcre_h" = "xyes"; then
- smart_try_dir=$pcre_lib_dir
- FR_SMART_CHECK_LIB(pcre, pcre_compile)
- if test "x$ac_cv_lib_pcre_pcre_compile" = "xyes"; then
- AC_MSG_CHECKING([libpcre library and header version consistency])
- AC_RUN_IFELSE(
- [AC_LANG_PROGRAM(
- [[
- #include <stdio.h>
- #include <pcre.h>
- #include <stdlib.h>
- #define XSTRINGIFY(x) #x
- #define STRINGIFY(x) XSTRINGIFY(x)
- ]],
- [[
- char const *p = pcre_version();
- char *q;
- unsigned long ver;
-
- printf("library: %s header: %u.%u %s... ", p, PCRE_MAJOR, PCRE_MINOR, STRINGIFY(PCRE_DATE));
-
- ver = strtoul(p, &q, 10);
- if (*q != '.') return 1;
- if (ver != PCRE_MAJOR) return 65;
- p = ++q;
-
- ver = strtoul(p, &q, 10);
- if (ver != PCRE_MINOR) return 1;
- ]]
- )],
- [
- AC_MSG_RESULT(yes)
- REGEX=yes
- AC_DEFINE(HAVE_REGEX_PCRE, [1], [define this if we have libpcre])
- AC_DEFINE(HAVE_BINSAFE_REGEX, 1, [Define if we have a binary safe regular expression library])
- ],
- [
- AC_MSG_RESULT(no)
- AC_MSG_FAILURE([libpcre library version does not match header version])
- ],
- [
- AC_MSG_RESULT([cross-compiling (assuming yes)])
- ]
- )
- fi
- fi
- fi
fi
dnl #
/* Define if we have any regular expression library */
#undef HAVE_REGEX
-/* define this if we have libpcre */
-#undef HAVE_REGEX_PCRE
-
/* define this if we have libpcre2 */
#undef HAVE_REGEX_PCRE2
#endif
);
- dependency_feature_add(cs, "regex-pcre",
-#ifdef HAVE_REGEX_PCRE
- true
-#else
- false
-#endif
- );
-
dependency_feature_add(cs, "regex-pcre2",
#ifdef HAVE_REGEX_PCRE2
true
#endif
dependency_feature_add(cs, "regex-binsafe",
-#if defined(HAVE_REGNEXEC) || defined(HAVE_REGEX_PCRE) || defined(HAVE_REGEX_PCRE2)
+#if defined(HAVE_REGNEXEC) || defined(HAVE_REGEX_PCRE2)
true
#else
false
# ifdef HAVE_REGEX_PCRE2
snprintf(buffer, sizeof(buffer), "%i.%i (%s) - retrieved at build time", PCRE2_MAJOR, PCRE2_MINOR, STRINGIFY(PCRE2_DATE));
dependency_version_number_add(cs, "pcre2", buffer);
-# elif defined(HAVE_REGEX_PCRE)
- dependency_version_number_add(cs, "pcre", pcre_version());
# endif
#endif
#define REQUEST_DATA_REGEX (0xadbeef00)
typedef struct {
-#if defined(HAVE_REGEX_PCRE) || defined(HAVE_REGEX_PCRE2)
+#if defined(HAVE_REGEX_PCRE2)
regex_t *preg; //!< Compiled pattern.
#endif
fr_regmatch_t *regmatch; //!< Match vectors.
/*
* Steal runtime pregs, leave precompiled ones
*/
-#if defined(HAVE_REGEX_PCRE) || defined(HAVE_REGEX_PCRE2)
+#if defined(HAVE_REGEX_PCRE2)
if (!(*preg)->precompiled) {
new_rc->preg = talloc_steal(new_rc, *preg);
*preg = NULL;
return 0;
}
-# elif defined(HAVE_REGEX_PCRE)
-/** Extract a subcapture value from the request
- *
- * @note This is the PCRE variant of the function.
- *
- * @param[in] ctx To allocate subcapture buffer in.
- * @param[out] out Where to write the subcapture string.
- * @param[in] request to extract.
- * @param[in] num Subcapture index (0 for entire match).
- * @return
- * - 0 on success.
- * - -1 on notfound.
- */
-int regex_request_to_sub(TALLOC_CTX *ctx, fr_value_box_t *out, request_t *request, uint32_t num)
-{
- fr_regcapture_t *rc;
- char const *p;
- int ret;
-
- rc = request_data_reference(request, request, REQUEST_DATA_REGEX);
- if (!rc) {
- RDEBUG4("No subcapture data found");
- return -1;
- }
-
- ret = pcre_get_substring(rc->regmatch->subject,
- (int *)rc->regmatch->match_data, (int)rc->regmatch->used, num, &p);
- switch (ret) {
- case PCRE_ERROR_NOMEMORY:
- MEM(NULL);
- break;
-
- /*
- * Not finding a substring is fine
- */
- case PCRE_ERROR_NOSUBSTRING:
- RDEBUG4("%i/%zu Not found", num + 1, rc->regmatch->used);
- return -1;
-
- default:
- if (ret < 0) return -1;
-
- talloc_set_type(p, char);
- talloc_steal(ctx, p);
-
- fr_value_box_init(out, FR_TYPE_STRING, NULL, false);
- fr_value_box_bstrndup_shallow(out, NULL, p, talloc_array_length(p) - 1, false);
- fr_value_box_mark_safe_for(out, rc->safe_for);
- fr_value_box_set_secret(out, rc->secret);
-
- RDEBUG4("%i/%zu Found: %pV (%zu)", num + 1, rc->regmatch->used, out, out->vb_length);
- break;
- }
-
- return 0;
-}
-
-/** Extract a named subcapture value from the request
- *
- * @note This is the PCRE variant of the function.
- *
- * @param[in] ctx To allocate subcapture buffer in.
- * @param[out] out Where to write the subcapture string.
- * @param[in] request to extract.
- * @param[in] name of subcapture.
- * @return
- * - 0 on success.
- * - -1 on notfound.
- */
-int regex_request_to_sub_named(TALLOC_CTX *ctx, fr_value_box_t *out, request_t *request, char const *name)
-{
- fr_regcapture_t *rc;
- void *rd;
- char const *p;
- int ret;
-
- rd = request_data_reference(request, request, REQUEST_DATA_REGEX);
- if (!rd) {
- RDEBUG4("No subcapture data found");
- return -1;
- }
-
- rc = talloc_get_type_abort(rd, fr_regcapture_t);
- ret = pcre_get_named_substring(rc->preg->compiled, rc->regmatch->subject,
- (int *)rc->regmatch->match_data, (int)rc->regmatch->used, name, &p);
- switch (ret) {
- case PCRE_ERROR_NOMEMORY:
- MEM(NULL);
- break;
-
- /*
- * Not finding a substring is fine
- */
- case PCRE_ERROR_NOSUBSTRING:
- RDEBUG4("No named capture group \"%s\"", name);
- return -1;
-
- default:
- if (ret < 0) return -1;
-
- talloc_set_type(p, char);
- talloc_steal(ctx, p);
-
- fr_value_box_init(out, FR_TYPE_STRING, NULL, false);
- fr_value_box_bstrndup_shallow(out, NULL, p, talloc_array_length(p) - 1, false);
- fr_value_box_mark_safe_for(out, rc->safe_for);
- fr_value_box_set_secret(out, rc->secret);
-
- RDEBUG4("Found \"%s\": %pV (%zu)", name, out, out->vb_length);
-
- break;
- }
-
- return 0;
-}
# else
/** Extract a subcapture value from the request
*
/*
* Named capture groups only supported by PCRE.
*/
-# if defined(HAVE_REGEX_PCRE2) || defined(HAVE_REGEX_PCRE)
+# if defined(HAVE_REGEX_PCRE2)
int regex_request_to_sub_named(TALLOC_CTX *ctx, fr_value_box_t *out, request_t *request, char const *name) CC_HINT(nonnull);
# endif
#endif
#include <freeradius-devel/util/regex.h>
#include <freeradius-devel/util/atexit.h>
-#if defined(HAVE_REGEX_PCRE) || (defined(HAVE_REGEX_PCRE2) && defined(PCRE2_CONFIG_JIT))
+#if defined(HAVE_REGEX_PCRE2) && defined(PCRE2_CONFIG_JIT)
#ifndef FR_PCRE_JIT_STACK_MIN
# define FR_PCRE_JIT_STACK_MIN (128 * 1024)
#endif
return regmatch;
}
-/*
- *######################################
- *# FUNCTIONS FOR LIBPCRE #
- *######################################
- */
-#elif defined(HAVE_REGEX_PCRE)
-/*
- * Wrapper functions for libpcre. Much more powerful, and guaranteed
- * to be binary safe but require libpcre.
- */
-#if (PCRE_MAJOR >= 8) && (PCRE_MINOR >= 32) && defined(PCRE_CONFIG_JIT)
-# define HAVE_PCRE_JIT_EXEC 1
-#endif
-
-/** Thread local storage for PCRE
- *
- */
-typedef struct {
- TALLOC_CTX *alloc_ctx; //!< Context used for any allocations.
-#ifdef HAVE_PCRE_JIT_EXEC
- pcre_jit_stack *jit_stack;
-#endif
-} fr_pcre_tls_t;
-
-static _Thread_local fr_pcre_tls_t *fr_pcre_tls;
-static bool fr_pcre_study_flags;
-
-/*
- * Replace the libpcre memory allocation and freeing functions
- * with talloc wrappers. This allows us to use the subcapture copy
- * functions and just reparent the memory allocated.
- */
-static void *_pcre_talloc(size_t to_alloc)
-{
- return talloc_array(fr_pcre_tls->alloc_ctx, uint8_t, to_alloc);
-}
-
-static void _pcre_talloc_free(void *to_free)
-{
- talloc_free(to_free);
-}
-
-static int _pcre_globals_reset(UNUSED void *uctx)
-{
- pcre_malloc = NULL;
- pcre_free = NULL;
- return 0;
-}
-
-static int _pcre_globals_configure(UNUSED void *uctx)
-{
-#ifdef PCRE_CONFIG_JIT
- int *do_jit = 0;
-
- /*
- * If the headers are from >= 8.20
- * check at runtime to see if this version
- * of the libpcre library was compiled with
- * JIT support.
- */
- pcre_config(PCRE_CONFIG_JIT, &do_jit);
-
- if (do_jit) fr_pcre_study_flags |= PCRE_STUDY_JIT_COMPILE;
-#endif
- pcre_malloc = _pcre_talloc; /* pcre_malloc is a global provided by libpcre */
- pcre_free = _pcre_talloc_free; /* pcre_free is a global provided by libpcre */
-
- return 0;
-}
-
-/** Free thread local data
- *
- * @param[in] tls Thread local data to free.
- */
-static int _pcre_tls_free(fr_pcre_tls_t *tls)
-{
-#ifdef HAVE_PCRE_JIT_EXEC
- if (tls->jit_stack) pcre_jit_stack_free(tls->jit_stack);
-#endif
- return 0;
-}
-
-static int _pcre_tls_free_on_exit(void *arg)
-{
- return talloc_free(arg);
-}
-
-/** Performs thread local storage initialisation for libpcre
- *
- */
-static inline CC_HINT(always_inline) int pcre_tls_init(void)
-{
- fr_pcre_tls_t *tls;
-
- if (fr_pcre_tls) return 0;
-
- tls = talloc_zero(NULL, fr_pcre_tls_t);
- if (unlikely(!tls)) return -1;
- talloc_set_destructor(tls, _pcre_tls_free);
-
- /*
- * Need to set this first so that the alloc
- * functions can access alloc_ctx.
- */
- fr_atexit_thread_local(fr_pcre_tls, _pcre_tls_free_on_exit, tls);
-
-#ifdef HAVE_PCRE_JIT_EXEC
- /*
- * Starts at 128K, max is 512K per thread.
- */
- tls->jit_stack = pcre_jit_stack_alloc(FR_PCRE_JIT_STACK_MIN, FR_PCRE_JIT_STACK_MAX);
-#endif
-
- return 0;
-}
-
-/** Free regex_t structure
- *
- * Calls libpcre specific free functions for the expression and study.
- *
- * @param preg to free.
- */
-static int _regex_free(regex_t *preg)
-{
- if (preg->compiled) pcre_free(preg->compiled);
-#ifdef PCRE_CONFIG_JIT
- if (preg->extra) pcre_free_study(preg->extra);
-#else
- if (preg->extra) pcre_free(preg->extra);
-#endif
-
- return 0;
-}
-
-/** Wrapper around pcre_compile
- *
- * Allows the rest of the code to do compilations using one function signature.
- *
- * @note Compiled expression must be freed with talloc_free.
- *
- * @param[out] out Where to write out a pointer to the structure containing
- * the compiled expression.
- * @param[in] pattern to compile.
- * @param[in] len of pattern.
- * @param[in] flags controlling matching. May be NULL.
- * @param[in] subcaptures Whether to compile the regular expression to store subcapture
- * data.
- * @param[in] runtime If false run the pattern through the PCRE JIT to convert it
- * to machine code. This trades startup time (longer) for
- * runtime performance (better).
- * @return
- * - >= 1 on success.
- * - <= 0 on error. Negative value is offset of parse error.
- */
-ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **out, char const *pattern, size_t len,
- fr_regex_flags_t const *flags, bool subcaptures, bool runtime)
-{
- char const *error;
- int offset;
- int cflags = 0;
- int ret;
- regex_t *preg;
-
- fr_atexit_global_once_ret(&ret, _pcre_globals_configure, _pcre_globals_reset, NULL);
- if (unlikely(ret < 0)) return -1;
-
-
- if (unlikely(pcre_tls_init() < 0)) return -1;
-
- /*
- * Check inputs
- */
- *out = NULL;
-
- if (len == 0) {
- fr_strerror_const("Empty expression");
- return 0;
- }
-
- /*
- * Options
- */
- if (flags) {
- if (flags->global) {
- fr_strerror_const("g - Global matching/substitution not supported with libpcre");
- return 0;
- }
- if (flags->ignore_case) cflags |= PCRE_CASELESS;
- if (flags->multiline) cflags |= PCRE_MULTILINE;
- if (flags->dot_all) cflags |= PCRE_DOTALL;
- if (flags->unicode) cflags |= PCRE_UTF8;
- if (flags->extended) cflags |= PCRE_EXTENDED;
- }
-
- if (!subcaptures) cflags |= PCRE_NO_AUTO_CAPTURE;
-
- preg = talloc_zero(ctx, regex_t);
- if (unlikely(preg == NULL)) {
- fr_strerror_const("Out of memory");
- return 0;
- }
- talloc_set_destructor(preg, _regex_free);
-
- preg->compiled = pcre_compile(pattern, cflags, &error, &offset, NULL);
- if (!preg->compiled) {
- fr_strerror_printf("%s", error);
- talloc_free(preg);
-
- return -(ssize_t)offset;
- }
-
- if (!runtime) {
- preg->precompiled = true;
- preg->extra = pcre_study(preg->compiled, fr_pcre_study_flags, &error);
- if (error) {
- fr_strerror_printf("Pattern study failed: %s", error);
- talloc_free(preg);
-
- return 0;
- }
-
-#ifdef PCRE_INFO_JIT
- /*
- * Check to see if the JIT was successful.
- *
- * Not all platforms have JIT support, the pattern
- * may not be jitable, or JIT support may have been
- * disabled.
- */
- if (fr_pcre_study_flags & PCRE_STUDY_JIT_COMPILE) {
- int jitd = 0;
-
- pcre_fullinfo(preg->compiled, preg->extra, PCRE_INFO_JIT, &jitd);
- if (jitd) preg->jitd = true;
- }
-#endif
- }
-
- *out = preg;
-
- return len;
-}
-
-static fr_table_num_ordered_t const regex_pcre_error_str[] = {
- { L("PCRE_ERROR_NOMATCH"), PCRE_ERROR_NOMATCH },
- { L("PCRE_ERROR_NULL"), PCRE_ERROR_NULL },
- { L("PCRE_ERROR_BADOPTION"), PCRE_ERROR_BADOPTION },
- { L("PCRE_ERROR_BADMAGIC"), PCRE_ERROR_BADMAGIC },
- { L("PCRE_ERROR_UNKNOWN_OPCODE"), PCRE_ERROR_UNKNOWN_OPCODE },
- { L("PCRE_ERROR_NOMEMORY"), PCRE_ERROR_NOMEMORY },
- { L("PCRE_ERROR_NOSUBSTRING"), PCRE_ERROR_NOSUBSTRING },
- { L("PCRE_ERROR_MATCHLIMIT"), PCRE_ERROR_MATCHLIMIT },
- { L("PCRE_ERROR_CALLOUT"), PCRE_ERROR_CALLOUT },
- { L("PCRE_ERROR_BADUTF8"), PCRE_ERROR_BADUTF8 },
- { L("PCRE_ERROR_BADUTF8_OFFSET"), PCRE_ERROR_BADUTF8_OFFSET },
- { L("PCRE_ERROR_PARTIAL"), PCRE_ERROR_PARTIAL },
- { L("PCRE_ERROR_BADPARTIAL"), PCRE_ERROR_BADPARTIAL },
- { L("PCRE_ERROR_INTERNAL"), PCRE_ERROR_INTERNAL },
- { L("PCRE_ERROR_BADCOUNT"), PCRE_ERROR_BADCOUNT },
- { L("PCRE_ERROR_DFA_UITEM"), PCRE_ERROR_DFA_UITEM },
- { L("PCRE_ERROR_DFA_UCOND"), PCRE_ERROR_DFA_UCOND },
- { L("PCRE_ERROR_DFA_UMLIMIT"), PCRE_ERROR_DFA_UMLIMIT },
- { L("PCRE_ERROR_DFA_WSSIZE"), PCRE_ERROR_DFA_WSSIZE },
- { L("PCRE_ERROR_DFA_RECURSE"), PCRE_ERROR_DFA_RECURSE },
- { L("PCRE_ERROR_RECURSIONLIMIT"), PCRE_ERROR_RECURSIONLIMIT },
- { L("PCRE_ERROR_NULLWSLIMIT"), PCRE_ERROR_NULLWSLIMIT },
- { L("PCRE_ERROR_BADNEWLINE"), PCRE_ERROR_BADNEWLINE },
- { L("PCRE_ERROR_BADOFFSET"), PCRE_ERROR_BADOFFSET },
- { L("PCRE_ERROR_SHORTUTF8"), PCRE_ERROR_SHORTUTF8 },
- { L("PCRE_ERROR_RECURSELOOP"), PCRE_ERROR_RECURSELOOP },
- { L("PCRE_ERROR_JIT_STACKLIMIT"), PCRE_ERROR_JIT_STACKLIMIT },
- { L("PCRE_ERROR_BADMODE"), PCRE_ERROR_BADMODE },
- { L("PCRE_ERROR_BADENDIANNESS"), PCRE_ERROR_BADENDIANNESS },
- { L("PCRE_ERROR_DFA_BADRESTART"), PCRE_ERROR_DFA_BADRESTART },
- { L("PCRE_ERROR_JIT_BADOPTION"), PCRE_ERROR_JIT_BADOPTION },
- { L("PCRE_ERROR_BADLENGTH"), PCRE_ERROR_BADLENGTH },
-#ifdef PCRE_ERROR_UNSET
- { L("PCRE_ERROR_UNSET"), PCRE_ERROR_UNSET },
-#endif
-};
-static size_t regex_pcre_error_str_len = NUM_ELEMENTS(regex_pcre_error_str);
-
-/** Wrapper around pcre_exec
- *
- * @param[in] preg The compiled expression.
- * @param[in] subject to match.
- * @param[in] len Length of subject.
- * @param[in] regmatch Match result structure.
- * @return
- * - -1 on failure.
- * - 0 on no match.
- * - 1 on match.
- */
-int regex_exec(regex_t *preg, char const *subject, size_t len, fr_regmatch_t *regmatch)
-{
- int ret;
- size_t matches;
-
- if (unlikely(pcre_tls_init() < 0)) return -1;
-
- /*
- * Disable capturing
- */
- if (!regmatch) {
- matches = 0;
- } else {
- matches = regmatch->allocd;
-
- /*
- * Reset the match result structure
- */
- memset(regmatch->match_data, 0, sizeof(regmatch->match_data[0]) * matches);
- regmatch->used = 0;
- }
-
-#ifdef HAVE_PCRE_JIT_EXEC
- if (preg->jitd) {
- ret = pcre_jit_exec(preg->compiled, preg->extra, subject, len, 0, 0,
- regmatch ? (int *)regmatch->match_data : NULL, matches * 3, fr_pcre_tls->jit_stack);
- } else
-#endif
- {
- ret = pcre_exec(preg->compiled, preg->extra, subject, len, 0, 0,
- regmatch ? (int *)regmatch->match_data : NULL, matches * 3);
- }
- if (ret < 0) {
- if (ret == PCRE_ERROR_NOMATCH) return 0;
-
- fr_strerror_printf("regex evaluation failed with code (%i): %s", ret,
- fr_table_str_by_value(regex_pcre_error_str, ret, "<INVALID>"));
- return -1;
- }
- /*
- * 0 signifies more offsets than we provided space for,
- * so don't touch nmatches.
- */
- if (regmatch && (ret > 0)) {
- regmatch->used = ret;
-
- if (regmatch->subject) talloc_const_free(regmatch->subject);
- regmatch->subject = talloc_bstrndup(regmatch, subject, len);
- if (!regmatch->subject) {
- fr_strerror_const("Out of memory");
- return -1;
- }
- }
-
- return 1;
-}
-
-/** Returns the number of subcapture groups
- *
- * @return
- * - >0 The number of subcaptures contained within the pattern
- * - 0 if the number of subcaptures can't be determined.
- */
-uint32_t regex_subcapture_count(regex_t const *preg)
-{
- int count;
-
- if (pcre_fullinfo(preg->compiled, preg->extra, PCRE_INFO_CAPTURECOUNT, &count) != 0) {
- fr_strerror_const("Error determining subcapture group count");
- return 0;
- }
-
- return (uint32_t)count + 1;
-}
/*
*######################################
*# FUNCTIONS FOR POSIX-REGEX #
}
# endif
-# if defined(HAVE_REGEX_POSIX) || defined(HAVE_REGEX_PCRE)
+# if defined(HAVE_REGEX_POSIX)
/** Allocate vectors to fill with match data
*
* @param[in] ctx to allocate match vectors in.
///< or compiled for one off evaluation.
bool jitd; //!< Whether JIT data is available.
} regex_t;
-/*
- *######################################
- *# STRUCTURES FOR LIBPCRE #
- *######################################
- */
-# elif defined(HAVE_REGEX_PCRE)
-# include <pcre.h>
-/*
- * Versions older then 8.20 didn't have the JIT functionality
- * so, gracefully degrade.
- */
-# ifndef PCRE_STUDY_JIT_COMPILE
-# define PCRE_STUDY_JIT_COMPILE 0
-# endif
-/*
- * libpcre defines its matches as an array of ints which is a
- * multiple of three.
- */
-typedef struct {
- int a;
- int b;
- int c;
-} regmatch_t;
-
-/** Emulates the functionality of the pcre2_match_data struct
- *
- */
-typedef struct {
- regmatch_t *match_data; //!< Slots for matches.
- size_t allocd; //!< Number of slots allocated for match data.
- size_t used; //!< Number of slots filled with match data.
- char const *subject; //!< A local copy of the subject.
-} fr_regmatch_t;
-
-/** Bundles compiled regular expression structures together
- *
- */
-typedef struct {
- pcre *compiled; //!< Compiled regular expression.
- pcre_extra *extra; //!< Result of studying a regular expression.
- uint32_t subcaptures; //!< Number of subcaptures contained within the expression.
-
- bool precompiled; //!< Whether this regex was precompiled, or compiled for one off evaluation.
- bool jitd; //!< Whether JIT data is available.
-} regex_t;
/*
*######################################
*# STRUCTURES FOR POSIX-REGEX #
endif
#
-# Some tests require PCRE or PCRE2
+# Some tests require PCRE2
#
-ifeq "$(AC_HAVE_REGEX_PCRE)$(AC_HAVE_REGEX_PCRE2)" ""
+ifeq "$(AC_HAVE_REGEX_PCRE2)" ""
FILES := $(filter-out if-regex-match-named,$(FILES))
endif