1336 lines
52 KiB
Diff
1336 lines
52 KiB
Diff
From 828ab48764b82d0226e860c73c5dac5b11f77385 Mon Sep 17 00:00:00 2001
|
|
From: dmiller <dmiller@e0a8ed71-7df4-0310-8962-fdc924857419>
|
|
Date: Sat, 24 Jun 2023 01:53:07 +0000
|
|
Subject: [PATCH] Upgrade libpcre to PCRE2 10.42. Windows/macOS builds not
|
|
completed.
|
|
|
|
Conflict: Remove pcre2 source code modification, which can be replaced by pcre2-devel dependency
|
|
Reference: https://github.com/nmap/nmap/commit/828ab48764b82d0226e860c73c5dac5b11f77385
|
|
---
|
|
checklibs.sh | 10 +-
|
|
configure | 92 +++------
|
|
configure.ac | 23 +--
|
|
nmap.cc | 6 +-
|
|
nmap_config.h.in | 2 -
|
|
nping/nping_config.h.in | 2 -
|
|
nse_pcrelib.cc | 400 ----------------------------------------
|
|
nse_pcrelib.h | 9 -
|
|
nselib/pcre.luadoc | 135 --------------
|
|
service_scan.cc | 180 ++++++++++--------
|
|
service_scan.h | 33 ++--
|
|
11 files changed, 156 insertions(+), 736 deletions(-)
|
|
delete mode 100644 nse_pcrelib.cc
|
|
delete mode 100644 nse_pcrelib.h
|
|
delete mode 100644 nselib/pcre.luadoc
|
|
|
|
diff --git a/checklibs.sh b/checklibs.sh
|
|
index 2048e2a..26e9d8a 100644
|
|
--- a/checklibs.sh
|
|
+++ b/checklibs.sh
|
|
@@ -11,13 +11,13 @@ trim_version() {
|
|
}
|
|
|
|
check_libpcre() {
|
|
- PCRE_SOURCE="https://sourceforge.net/projects/pcre/files/latest/download"
|
|
+ PCRE_SOURCE="https://github.com/PCRE2Project/pcre2/releases/latest"
|
|
PCRE_MAJOR=""
|
|
PCRE_MINOR=""
|
|
- eval $(grep '^PCRE_MAJOR=' $NDIR/libpcre/configure)
|
|
- eval $(grep '^PCRE_MINOR=' $NDIR/libpcre/configure)
|
|
- PCRE_VERSION="$PCRE_MAJOR.$PCRE_MINOR"
|
|
- PCRE_LATEST=$(curl -s -I $PCRE_SOURCE | perl -lne 'if(/pcre-(\d+.\d+).zip/){print $1}' | newest)
|
|
+ eval $(grep '^PCRE2_MAJOR=' $NDIR/libpcre/configure)
|
|
+ eval $(grep '^PCRE2_MINOR=' $NDIR/libpcre/configure)
|
|
+ PCRE_VERSION="$PCRE2_MAJOR.$PCRE2_MINOR"
|
|
+ PCRE_LATEST=$(curl -s -I $PCRE_SOURCE | tee tmp.txt | perl -lne 'if(m|^Location:.*/tag/pcre2-(\d+.\d+)[\r\n]*$|){print $1;exit(0)}')
|
|
if [ "$PCRE_VERSION" != "$PCRE_LATEST" ]; then
|
|
echo "Newer version of libpcre available"
|
|
echo " Current:" $PCRE_VERSION
|
|
diff --git a/configure b/configure
|
|
index d1d2f19..12764ee 100755
|
|
--- a/configure
|
|
+++ b/configure
|
|
@@ -1451,8 +1451,8 @@ Optional Packages:
|
|
[DIR]/lib/ and [DIR]/include/openssl/)
|
|
--with-libpcap=DIR Look for pcap in DIR/include and DIR/libs.
|
|
--with-libpcap=included Always use version included with Nmap
|
|
- --with-libpcre=DIR Use an existing (compiled) pcre lib from DIR/include
|
|
- and DIR/lib.
|
|
+ --with-libpcre=DIR Use an existing (compiled) pcre2 lib from
|
|
+ DIR/include and DIR/lib.
|
|
--with-libpcre=included Always use the version included with Nmap
|
|
--with-libz=DIR Use specific copy of libz
|
|
--with-libz=included Always use version included with Nmap
|
|
@@ -6437,58 +6437,19 @@ fi
|
|
|
|
# If they didn't specify it, we try to find it
|
|
if test $have_pcre != yes -a $requested_included_pcre != yes ; then
|
|
- ac_fn_c_check_header_mongrel "$LINENO" "pcre.h" "ac_cv_header_pcre_h" "$ac_includes_default"
|
|
-if test "x$ac_cv_header_pcre_h" = xyes; then :
|
|
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcre_version in -lpcre" >&5
|
|
-$as_echo_n "checking for pcre_version in -lpcre... " >&6; }
|
|
-if ${ac_cv_lib_pcre_pcre_version+:} false; then :
|
|
- $as_echo_n "(cached) " >&6
|
|
-else
|
|
- ac_check_lib_save_LIBS=$LIBS
|
|
-LIBS="-lpcre $LIBS"
|
|
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
-/* end confdefs.h. */
|
|
+ ac_fn_c_check_header_compile "$LINENO" "pcre2.h" "ac_cv_header_pcre2_h" "
|
|
+#define PCRE2_CODE_UNIT_WIDTH 8
|
|
|
|
-/* Override any GCC internal prototype to avoid an error.
|
|
- Use char because int might match the return type of a GCC
|
|
- builtin and then its argument prototype would still apply. */
|
|
-#ifdef __cplusplus
|
|
-extern "C"
|
|
-#endif
|
|
-char pcre_version ();
|
|
-int
|
|
-main ()
|
|
-{
|
|
-return pcre_version ();
|
|
- ;
|
|
- return 0;
|
|
-}
|
|
-_ACEOF
|
|
-if ac_fn_c_try_link "$LINENO"; then :
|
|
- ac_cv_lib_pcre_pcre_version=yes
|
|
-else
|
|
- ac_cv_lib_pcre_pcre_version=no
|
|
-fi
|
|
-rm -f core conftest.err conftest.$ac_objext \
|
|
- conftest$ac_exeext conftest.$ac_ext
|
|
-LIBS=$ac_check_lib_save_LIBS
|
|
-fi
|
|
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcre_pcre_version" >&5
|
|
-$as_echo "$ac_cv_lib_pcre_pcre_version" >&6; }
|
|
-if test "x$ac_cv_lib_pcre_pcre_version" = xyes; then :
|
|
- have_pcre=yes
|
|
-fi
|
|
|
|
-else
|
|
- ac_fn_c_check_header_mongrel "$LINENO" "pcre/pcre.h" "ac_cv_header_pcre_pcre_h" "$ac_includes_default"
|
|
-if test "x$ac_cv_header_pcre_pcre_h" = xyes; then :
|
|
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcre_version in -lpcre" >&5
|
|
-$as_echo_n "checking for pcre_version in -lpcre... " >&6; }
|
|
-if ${ac_cv_lib_pcre_pcre_version+:} false; then :
|
|
+"
|
|
+if test "x$ac_cv_header_pcre2_h" = xyes; then :
|
|
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcre2_compile_8 in -lpcre2-8" >&5
|
|
+$as_echo_n "checking for pcre2_compile_8 in -lpcre2-8... " >&6; }
|
|
+if ${ac_cv_lib_pcre2_8_pcre2_compile_8+:} false; then :
|
|
$as_echo_n "(cached) " >&6
|
|
else
|
|
ac_check_lib_save_LIBS=$LIBS
|
|
-LIBS="-lpcre $LIBS"
|
|
+LIBS="-lpcre2-8 $LIBS"
|
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
/* end confdefs.h. */
|
|
|
|
@@ -6498,35 +6459,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
#ifdef __cplusplus
|
|
extern "C"
|
|
#endif
|
|
-char pcre_version ();
|
|
+char pcre2_compile_8 ();
|
|
int
|
|
main ()
|
|
{
|
|
-return pcre_version ();
|
|
+return pcre2_compile_8 ();
|
|
;
|
|
return 0;
|
|
}
|
|
_ACEOF
|
|
if ac_fn_c_try_link "$LINENO"; then :
|
|
- ac_cv_lib_pcre_pcre_version=yes
|
|
+ ac_cv_lib_pcre2_8_pcre2_compile_8=yes
|
|
else
|
|
- ac_cv_lib_pcre_pcre_version=no
|
|
+ ac_cv_lib_pcre2_8_pcre2_compile_8=no
|
|
fi
|
|
rm -f core conftest.err conftest.$ac_objext \
|
|
conftest$ac_exeext conftest.$ac_ext
|
|
LIBS=$ac_check_lib_save_LIBS
|
|
fi
|
|
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcre_pcre_version" >&5
|
|
-$as_echo "$ac_cv_lib_pcre_pcre_version" >&6; }
|
|
-if test "x$ac_cv_lib_pcre_pcre_version" = xyes; then :
|
|
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcre2_8_pcre2_compile_8" >&5
|
|
+$as_echo "$ac_cv_lib_pcre2_8_pcre2_compile_8" >&6; }
|
|
+if test "x$ac_cv_lib_pcre2_8_pcre2_compile_8" = xyes; then :
|
|
have_pcre=yes
|
|
fi
|
|
|
|
-
|
|
-fi
|
|
-
|
|
-
|
|
-
|
|
fi
|
|
|
|
|
|
@@ -6536,8 +6492,8 @@ fi
|
|
if test $have_pcre != yes ; then
|
|
subdirs="$subdirs libpcre"
|
|
|
|
- CPPFLAGS="-I\$(top_srcdir)/$LIBPCREDIR $CPPFLAGS"
|
|
- LIBPCRE_LIBS="$LIBPCREDIR/libpcre.a"
|
|
+ CPPFLAGS="-I\$(top_srcdir)/$LIBPCREDIR/src $CPPFLAGS"
|
|
+ LIBPCRE_LIBS="$LIBPCREDIR/.libs/libpcre2-8.a"
|
|
PCRE_BUILD="build-pcre"
|
|
PCRE_CLEAN="clean-pcre"
|
|
PCRE_DIST_CLEAN="distclean-pcre"
|
|
@@ -6546,19 +6502,19 @@ $as_echo "#define PCRE_INCLUDED 1" >>confdefs.h
|
|
|
|
else
|
|
# We only need to check for and use this if we are NOT using included pcre
|
|
- for ac_header in pcre/pcre.h
|
|
+ for ac_header in pcre2.h
|
|
do :
|
|
- ac_fn_c_check_header_mongrel "$LINENO" "pcre/pcre.h" "ac_cv_header_pcre_pcre_h" "$ac_includes_default"
|
|
-if test "x$ac_cv_header_pcre_pcre_h" = xyes; then :
|
|
+ ac_fn_c_check_header_mongrel "$LINENO" "pcre2.h" "ac_cv_header_pcre2_h" "$ac_includes_default"
|
|
+if test "x$ac_cv_header_pcre2_h" = xyes; then :
|
|
cat >>confdefs.h <<_ACEOF
|
|
-#define HAVE_PCRE_PCRE_H 1
|
|
+#define HAVE_PCRE2_H 1
|
|
_ACEOF
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
- LIBPCRE_LIBS="-lpcre"
|
|
+ LIBPCRE_LIBS="-lpcre2-8"
|
|
PCRE_BUILD=""
|
|
PCRE_CLEAN=""
|
|
PCRE_DIST_CLEAN=""
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 7835d9b..c25fb04 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -510,7 +510,7 @@ LIBPCREDIR=libpcre
|
|
|
|
# First we test whether they specified libpcre explicitly
|
|
AC_ARG_WITH(libpcre,
|
|
-AC_HELP_STRING([--with-libpcre=DIR], [Use an existing (compiled) pcre lib from DIR/include and DIR/lib.])
|
|
+AC_HELP_STRING([--with-libpcre=DIR], [Use an existing (compiled) pcre2 lib from DIR/include and DIR/lib.])
|
|
AC_HELP_STRING([--with-libpcre=included], [Always use the version included with Nmap]),
|
|
[ case "$with_libpcre" in
|
|
yes)
|
|
@@ -528,27 +528,28 @@ AC_HELP_STRING([--with-libpcre=included], [Always use the version included with
|
|
|
|
# If they didn't specify it, we try to find it
|
|
if test $have_pcre != yes -a $requested_included_pcre != yes ; then
|
|
- AC_CHECK_HEADER(pcre.h,
|
|
- AC_CHECK_LIB(pcre, pcre_version, [have_pcre=yes ]),
|
|
- [AC_CHECK_HEADER(pcre/pcre.h,
|
|
- [AC_CHECK_LIB(pcre, pcre_version, [have_pcre=yes])]
|
|
- )]
|
|
+ AC_CHECK_HEADER(pcre2.h,
|
|
+ AC_CHECK_LIB(pcre2-8, pcre2_compile_8, [have_pcre=yes ]),
|
|
+ [],
|
|
+ [
|
|
+#define PCRE2_CODE_UNIT_WIDTH 8
|
|
+ ]
|
|
)
|
|
fi
|
|
|
|
# If we still don't have it, we use our own
|
|
if test $have_pcre != yes ; then
|
|
AC_CONFIG_SUBDIRS( libpcre )
|
|
- CPPFLAGS="-I\$(top_srcdir)/$LIBPCREDIR $CPPFLAGS"
|
|
- LIBPCRE_LIBS="$LIBPCREDIR/libpcre.a"
|
|
+ CPPFLAGS="-I\$(top_srcdir)/$LIBPCREDIR/src $CPPFLAGS"
|
|
+ LIBPCRE_LIBS="$LIBPCREDIR/.libs/libpcre2-8.a"
|
|
PCRE_BUILD="build-pcre"
|
|
PCRE_CLEAN="clean-pcre"
|
|
PCRE_DIST_CLEAN="distclean-pcre"
|
|
- AC_DEFINE(PCRE_INCLUDED, 1, [Using included libpcre])
|
|
+ AC_DEFINE(PCRE_INCLUDED, 1, [Using included libpcre2])
|
|
else
|
|
# We only need to check for and use this if we are NOT using included pcre
|
|
- AC_CHECK_HEADERS(pcre/pcre.h)
|
|
- LIBPCRE_LIBS="-lpcre"
|
|
+ AC_CHECK_HEADERS(pcre2.h)
|
|
+ LIBPCRE_LIBS="-lpcre2-8"
|
|
PCRE_BUILD=""
|
|
PCRE_CLEAN=""
|
|
PCRE_DIST_CLEAN=""
|
|
diff --git a/nmap.cc b/nmap.cc
|
|
index e4c65e7..96f0230 100644
|
|
--- a/nmap.cc
|
|
+++ b/nmap.cc
|
|
@@ -2803,10 +2803,12 @@ static void display_nmap_version() {
|
|
without.push_back("libz");
|
|
#endif
|
|
|
|
+ char pcre2_version[255];
|
|
+ pcre2_config(PCRE2_CONFIG_VERSION, pcre2_version);
|
|
#ifdef PCRE_INCLUDED
|
|
- with.push_back(std::string("nmap-libpcre-") + get_word_or_quote(pcre_version(), 0));
|
|
+ with.push_back(std::string("nmap-libpcre2-") + get_word_or_quote(pcre2_version, 0));
|
|
#else
|
|
- with.push_back(std::string("libpcre-") + get_word_or_quote(pcre_version(), 0));
|
|
+ with.push_back(std::string("libpcre2-") + get_word_or_quote(pcre2_version, 0));
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
diff --git a/nmap_config.h.in b/nmap_config.h.in
|
|
index 67dbeda..1dae65a 100644
|
|
--- a/nmap_config.h.in
|
|
+++ b/nmap_config.h.in
|
|
@@ -103,8 +103,6 @@
|
|
|
|
#undef HAVE_TERMIOS_H
|
|
|
|
-#undef HAVE_PCRE_PCRE_H
|
|
-
|
|
#undef BSD_NETWORKING
|
|
|
|
#undef IN_ADDR_DEEPSTRUCT
|
|
diff --git a/nping/nping_config.h.in b/nping/nping_config.h.in
|
|
index 98638cb..9b6f971 100644
|
|
--- a/nping/nping_config.h.in
|
|
+++ b/nping/nping_config.h.in
|
|
@@ -101,8 +101,6 @@
|
|
|
|
#undef HAVE_TERMIOS_H
|
|
|
|
-#undef HAVE_PCRE_PCRE_H
|
|
-
|
|
#undef BSD_NETWORKING
|
|
|
|
#undef IN_ADDR_DEEPSTRUCT
|
|
diff --git a/nse_pcrelib.cc b/nse_pcrelib.cc
|
|
deleted file mode 100644
|
|
index 436697e..0000000
|
|
--- a/nse_pcrelib.cc
|
|
+++ /dev/null
|
|
@@ -1,400 +0,0 @@
|
|
-/* lrexlib.c - PCRE regular expression library */
|
|
-/* Reuben Thomas nov00-18dec04 */
|
|
-/* Shmuel Zeigerman may04-18dec04 */
|
|
-
|
|
-
|
|
-#include <stdio.h>
|
|
-#include <stdlib.h>
|
|
-#include <string.h>
|
|
-
|
|
-#include "nse_lua.h"
|
|
-
|
|
-#include <locale.h>
|
|
-
|
|
-#include <nbase.h>
|
|
-
|
|
-#ifdef HAVE_PCRE_PCRE_H
|
|
-# include <pcre/pcre.h>
|
|
-#else
|
|
-# include <pcre.h>
|
|
-#endif
|
|
-
|
|
-#include "nse_pcrelib.h"
|
|
-
|
|
-static int get_startoffset(lua_State *L, int stackpos, size_t len)
|
|
-{
|
|
- int startoffset = luaL_optinteger(L, stackpos, 1);
|
|
- if(startoffset > 0)
|
|
- startoffset--;
|
|
- else if(startoffset < 0) {
|
|
- startoffset += (int) len;
|
|
- if(startoffset < 0)
|
|
- startoffset = 0;
|
|
- }
|
|
- return startoffset;
|
|
-}
|
|
-
|
|
-static int udata_tostring (lua_State *L, const char* type_handle,
|
|
- const char* type_name)
|
|
-{
|
|
- char buf[256];
|
|
- void *udata = luaL_checkudata(L, 1, type_handle);
|
|
-
|
|
- if(udata) {
|
|
- (void)Snprintf(buf, 255, "%s (%p)", type_name, udata);
|
|
- lua_pushstring(L, buf);
|
|
- }
|
|
- else {
|
|
- (void)Snprintf(buf, 255, "must be userdata of type '%s'", type_name);
|
|
- (void)luaL_argerror(L, 1, buf);
|
|
- }
|
|
-
|
|
- free(udata);
|
|
- return 1;
|
|
-}
|
|
-
|
|
-typedef struct { const char* key; lua_Integer val; } flags_pair;
|
|
-
|
|
-static int get_flags (lua_State *L, const flags_pair *arr)
|
|
-{
|
|
- const flags_pair *p;
|
|
- lua_newtable(L);
|
|
- for(p=arr; p->key != NULL; p++) {
|
|
- lua_pushstring(L, p->key);
|
|
- lua_pushinteger(L, p->val);
|
|
- lua_rawset(L, -3);
|
|
- }
|
|
- return 1;
|
|
-}
|
|
-
|
|
-const char pcre_handle[] = "pcre_regex_handle";
|
|
-const char pcre_typename[] = "pcre_regex";
|
|
-
|
|
-typedef struct {
|
|
- pcre *pr;
|
|
- pcre_extra *extra;
|
|
- int *match;
|
|
- int ncapt;
|
|
- const unsigned char *tables;
|
|
-} pcre2; /* a better name is needed */
|
|
-
|
|
-static const unsigned char *Lpcre_maketables(lua_State *L, int stackpos)
|
|
-{
|
|
- const unsigned char *tables;
|
|
- char old_locale[256];
|
|
- char *locale = strdup(luaL_checkstring(L, stackpos));
|
|
-
|
|
- if(locale == NULL)
|
|
- luaL_error(L, "cannot set locale");
|
|
-
|
|
- strncpy(old_locale, setlocale(LC_CTYPE, NULL), 255); /* store the locale */
|
|
-
|
|
- if(setlocale(LC_CTYPE, locale) == NULL) /* set new locale */
|
|
- luaL_error(L, "cannot set locale");
|
|
-
|
|
- tables = pcre_maketables(); /* make tables with new locale */
|
|
- (void)setlocale(LC_CTYPE, old_locale); /* restore the old locale */
|
|
-
|
|
- free(locale);
|
|
- return tables;
|
|
-}
|
|
-
|
|
-static int Lpcre_comp(lua_State *L)
|
|
-{
|
|
- char buf[256];
|
|
- const char *error;
|
|
- int erroffset;
|
|
- pcre2 *ud;
|
|
- const char *pattern = luaL_checkstring(L, 1);
|
|
- int cflags = luaL_optinteger(L, 2, 0);
|
|
- const unsigned char *tables = NULL;
|
|
-
|
|
- if(lua_gettop(L) > 2 && !lua_isnil(L, 3))
|
|
- tables = Lpcre_maketables(L, 3);
|
|
- if(tables == NULL)
|
|
- luaL_error(L, "PCRE compilation failed");
|
|
-
|
|
- ud = (pcre2*)lua_newuserdata(L, sizeof(pcre2));
|
|
- luaL_getmetatable(L, pcre_handle);
|
|
- (void)lua_setmetatable(L, -2);
|
|
- ud->match = NULL;
|
|
- ud->extra = NULL;
|
|
- ud->tables = tables; /* keep this for eventual freeing */
|
|
-
|
|
- ud->pr = pcre_compile(pattern, cflags, &error, &erroffset, tables);
|
|
- if(!ud->pr) {
|
|
- (void)Snprintf(buf, 255, "%s (pattern offset: %d)", error, erroffset+1);
|
|
- /* show offset 1-based as it's common in Lua */
|
|
- luaL_error(L, buf);
|
|
- }
|
|
-
|
|
- ud->extra = pcre_study(ud->pr, 0, &error);
|
|
- if(error) luaL_error(L, error);
|
|
-
|
|
- pcre_fullinfo(ud->pr, ud->extra, PCRE_INFO_CAPTURECOUNT, &ud->ncapt);
|
|
- /* need (2 ints per capture, plus one for substring match) * 3/2 */
|
|
- ud->match = (int *) safe_malloc((ud->ncapt + 1) * 3 * sizeof(int));
|
|
-
|
|
- return 1;
|
|
-}
|
|
-
|
|
-static void Lpcre_getargs(lua_State *L, pcre2 **pud, const char **text,
|
|
- size_t *text_len)
|
|
-{
|
|
- *pud = (pcre2 *)luaL_checkudata(L, 1, pcre_handle);
|
|
- if(*pud == NULL)
|
|
- (void)luaL_argerror(L, 1, ("compiled regexp expected"));
|
|
- *text = luaL_checklstring(L, 2, text_len);
|
|
-}
|
|
-
|
|
-typedef void (*Lpcre_push_matches) (lua_State *L, const char *text, pcre2 *ud);
|
|
-
|
|
-static void Lpcre_push_substrings (lua_State *L, const char *text, pcre2 *ud)
|
|
-{
|
|
- unsigned int i, j;
|
|
- unsigned int namecount;
|
|
- unsigned char *name_table;
|
|
- int name_entry_size;
|
|
- unsigned char *tabptr;
|
|
- const int *match = ud->match;
|
|
-
|
|
- lua_newtable(L);
|
|
- for (i = 1; i <= (unsigned) ud->ncapt; i++) {
|
|
- j = i * 2;
|
|
- if (match[j] >= 0)
|
|
- lua_pushlstring(L, text + match[j], (size_t)(match[j + 1] - match[j]));
|
|
- else
|
|
- lua_pushboolean(L, 0);
|
|
- lua_rawseti(L, -2, i);
|
|
- }
|
|
-
|
|
- /* now do named subpatterns - NJG */
|
|
- (void)pcre_fullinfo(ud->pr, ud->extra, PCRE_INFO_NAMECOUNT, &namecount);
|
|
- if (namecount <= 0)
|
|
- return;
|
|
- (void)pcre_fullinfo(ud->pr, ud->extra, PCRE_INFO_NAMETABLE, &name_table);
|
|
- (void)pcre_fullinfo(ud->pr, ud->extra, PCRE_INFO_NAMEENTRYSIZE, &name_entry_size);
|
|
- tabptr = name_table;
|
|
- for (i = 0; i < namecount; i++) {
|
|
- unsigned int n = (tabptr[0] << 8) | tabptr[1]; /* number of the capturing parenthesis */
|
|
- if (n > 0 && n <= (unsigned) ud->ncapt) { /* check range */
|
|
- unsigned int j = n * 2;
|
|
- lua_pushstring(L, (char*)tabptr + 2); /* name of the capture, zero terminated */
|
|
- if (match[j] >= 0)
|
|
- lua_pushlstring(L, text + match[j], match[j + 1] - match[j]);
|
|
- else
|
|
- lua_pushboolean(L, 0);
|
|
- lua_rawset(L, -3);
|
|
- }
|
|
- tabptr += name_entry_size;
|
|
- }
|
|
-}
|
|
-
|
|
-static void Lpcre_push_offsets (lua_State *L, const char *text, pcre2 * ud)
|
|
-{
|
|
- unsigned int i, j, k;
|
|
- if(text) {
|
|
- /* suppress compiler warning */
|
|
- }
|
|
- lua_newtable(L);
|
|
- for (i=1, j=1; i <= (unsigned) ud->ncapt; i++) {
|
|
- k = i * 2;
|
|
- if (ud->match[k] >= 0) {
|
|
- lua_pushinteger(L, ud->match[k] + 1);
|
|
- lua_rawseti(L, -2, j++);
|
|
- lua_pushinteger(L, ud->match[k+1]);
|
|
- lua_rawseti(L, -2, j++);
|
|
- }
|
|
- else {
|
|
- lua_pushboolean(L, 0);
|
|
- lua_rawseti(L, -2, j++);
|
|
- lua_pushboolean(L, 0);
|
|
- lua_rawseti(L, -2, j++);
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
-static int Lpcre_match_generic(lua_State *L, Lpcre_push_matches push_matches)
|
|
-{
|
|
- int res;
|
|
- const char *text;
|
|
- pcre2 *ud;
|
|
- size_t elen;
|
|
- int startoffset;
|
|
- int eflags = luaL_optinteger(L, 4, 0);
|
|
-
|
|
- Lpcre_getargs(L, &ud, &text, &elen);
|
|
- startoffset = get_startoffset(L, 3, elen);
|
|
-
|
|
- res = pcre_exec(ud->pr, ud->extra, text, (int)elen, startoffset, eflags,
|
|
- ud->match, (ud->ncapt + 1) * 3);
|
|
- if (res >= 0) {
|
|
- lua_pushinteger(L, (lua_Number) ud->match[0] + 1);
|
|
- lua_pushinteger(L, (lua_Number) ud->match[1]);
|
|
- (*push_matches)(L, text, ud);
|
|
- return 3;
|
|
- }
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int Lpcre_match(lua_State *L)
|
|
-{
|
|
- return Lpcre_match_generic(L, Lpcre_push_substrings);
|
|
-}
|
|
-
|
|
-static int Lpcre_exec(lua_State *L)
|
|
-{
|
|
- return Lpcre_match_generic(L, Lpcre_push_offsets);
|
|
-}
|
|
-
|
|
-static int Lpcre_gmatch(lua_State *L)
|
|
-{
|
|
- int res;
|
|
- size_t len;
|
|
- int nmatch = 0, limit = 0;
|
|
- const char *text;
|
|
- pcre2 *ud;
|
|
- int maxmatch = luaL_optinteger(L, 4, 0);
|
|
- int eflags = luaL_optinteger(L, 5, 0);
|
|
- int startoffset = 0;
|
|
- Lpcre_getargs(L, &ud, &text, &len);
|
|
- luaL_checktype(L, 3, LUA_TFUNCTION);
|
|
-
|
|
- if(maxmatch > 0) /* this must be stated in the docs */
|
|
- limit = 1;
|
|
-
|
|
- while (!limit || nmatch < maxmatch) {
|
|
- res = pcre_exec(ud->pr, ud->extra, text, (int)len, startoffset, eflags,
|
|
- ud->match, (ud->ncapt + 1) * 3);
|
|
- if (res >= 0) {
|
|
- nmatch++;
|
|
- lua_pushvalue(L, 3);
|
|
- lua_pushlstring(L, text + ud->match[0], ud->match[1] - ud->match[0]);
|
|
- Lpcre_push_substrings(L, text, ud);
|
|
- lua_call(L, 2, 1);
|
|
- if(lua_toboolean(L, -1))
|
|
- break;
|
|
- lua_pop(L, 1);
|
|
- startoffset = ud->match[1];
|
|
- } else
|
|
- break;
|
|
- }
|
|
- lua_pushinteger(L, nmatch);
|
|
- return 1;
|
|
-}
|
|
-
|
|
-static int Lpcre_gc (lua_State *L)
|
|
-{
|
|
- pcre2 *ud = (pcre2 *)luaL_checkudata(L, 1, pcre_handle);
|
|
- if (ud) {
|
|
- if(ud->pr) pcre_free(ud->pr);
|
|
- if(ud->extra) pcre_free(ud->extra);
|
|
- if(ud->tables) pcre_free((void *)ud->tables);
|
|
- if(ud->match) free(ud->match);
|
|
- }
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int Lpcre_tostring (lua_State *L) {
|
|
- return udata_tostring(L, pcre_handle, pcre_typename);
|
|
-}
|
|
-
|
|
-static int Lpcre_vers (lua_State *L)
|
|
-{
|
|
- lua_pushstring(L, pcre_version());
|
|
- return 1;
|
|
-}
|
|
-
|
|
-static flags_pair pcre_flags[] =
|
|
-{
|
|
- { "CASELESS", PCRE_CASELESS },
|
|
- { "MULTILINE", PCRE_MULTILINE },
|
|
- { "DOTALL", PCRE_DOTALL },
|
|
- { "EXTENDED", PCRE_EXTENDED },
|
|
- { "ANCHORED", PCRE_ANCHORED },
|
|
- { "DOLLAR_ENDONLY", PCRE_DOLLAR_ENDONLY },
|
|
- { "EXTRA", PCRE_EXTRA },
|
|
- { "NOTBOL", PCRE_NOTBOL },
|
|
- { "NOTEOL", PCRE_NOTEOL },
|
|
- { "UNGREEDY", PCRE_UNGREEDY },
|
|
- { "NOTEMPTY", PCRE_NOTEMPTY },
|
|
- { "UTF8", PCRE_UTF8 },
|
|
-#if PCRE_MAJOR >= 4
|
|
- { "NO_AUTO_CAPTURE", PCRE_NO_AUTO_CAPTURE },
|
|
- { "NO_UTF8_CHECK", PCRE_NO_UTF8_CHECK },
|
|
-#endif
|
|
-#ifdef PCRE_AUTO_CALLOUT
|
|
- { "AUTO_CALLOUT", PCRE_AUTO_CALLOUT },
|
|
-#endif
|
|
-#ifdef PCRE_PARTIAL
|
|
- { "PARTIAL", PCRE_PARTIAL },
|
|
-#endif
|
|
-#ifdef PCRE_DFA_SHORTEST
|
|
- { "DFA_SHORTEST", PCRE_DFA_SHORTEST },
|
|
-#endif
|
|
-#ifdef PCRE_DFA_RESTART
|
|
- { "DFA_RESTART", PCRE_DFA_RESTART },
|
|
-#endif
|
|
-#ifdef PCRE_FIRSTLINE
|
|
- { "FIRSTLINE", PCRE_FIRSTLINE },
|
|
-#endif
|
|
-#ifdef PCRE_DUPNAMES
|
|
- { "DUPNAMES", PCRE_DUPNAMES },
|
|
-#endif
|
|
-#ifdef PCRE_NEWLINE_CR
|
|
- { "NEWLINE_CR", PCRE_NEWLINE_CR },
|
|
-#endif
|
|
-#ifdef PCRE_NEWLINE_LF
|
|
- { "NEWLINE_LF", PCRE_NEWLINE_LF },
|
|
-#endif
|
|
-#ifdef PCRE_NEWLINE_CRLF
|
|
- { "NEWLINE_CRLF", PCRE_NEWLINE_CRLF },
|
|
-#endif
|
|
-#ifdef PCRE_NEWLINE_ANY
|
|
- { "NEWLINE_ANY", PCRE_NEWLINE_ANY },
|
|
-#endif
|
|
-#ifdef PCRE_NEWLINE_ANYCRLF
|
|
- { "NEWLINE_ANYCRLF", PCRE_NEWLINE_ANYCRLF },
|
|
-#endif
|
|
-#ifdef PCRE_BSR_ANYCRLF
|
|
- { "BSR_ANYCRLF", PCRE_BSR_ANYCRLF },
|
|
-#endif
|
|
-#ifdef PCRE_BSR_UNICODE
|
|
- { "BSR_UNICODE", PCRE_BSR_UNICODE },
|
|
-#endif
|
|
- { NULL, 0 }
|
|
-};
|
|
-
|
|
-static int Lpcre_get_flags (lua_State *L) {
|
|
- return get_flags(L, pcre_flags);
|
|
-}
|
|
-
|
|
-static const luaL_Reg pcremeta[] = {
|
|
- {"exec", Lpcre_exec},
|
|
- {"match", Lpcre_match},
|
|
- {"gmatch", Lpcre_gmatch},
|
|
- {"__gc", Lpcre_gc},
|
|
- {"__tostring", Lpcre_tostring},
|
|
- {NULL, NULL}
|
|
-};
|
|
-
|
|
-/* Open the library */
|
|
-static const luaL_Reg pcrelib[] = {
|
|
- {"new", Lpcre_comp},
|
|
- {"flags", Lpcre_get_flags},
|
|
- {"version", Lpcre_vers},
|
|
- {NULL, NULL}
|
|
-};
|
|
-
|
|
-LUALIB_API int luaopen_pcrelib(lua_State *L)
|
|
-{
|
|
- luaL_newmetatable(L, pcre_handle);
|
|
- lua_pushliteral(L, "__index");
|
|
- luaL_newlib(L, pcremeta);
|
|
- lua_rawset(L, -3);
|
|
- lua_pop(L, 1);
|
|
-
|
|
- luaL_newlib(L, pcrelib);
|
|
-
|
|
- return 1;
|
|
-}
|
|
diff --git a/nse_pcrelib.h b/nse_pcrelib.h
|
|
deleted file mode 100644
|
|
index 512d2a8..0000000
|
|
--- a/nse_pcrelib.h
|
|
+++ /dev/null
|
|
@@ -1,9 +0,0 @@
|
|
-#ifndef NSE_PCRELIB
|
|
-#define NSE_PCRELIB
|
|
-
|
|
-#define NSE_PCRELIBNAME "pcre"
|
|
-
|
|
-LUALIB_API int luaopen_pcrelib (lua_State *L);
|
|
-
|
|
-#endif
|
|
-
|
|
diff --git a/nselib/pcre.luadoc b/nselib/pcre.luadoc
|
|
deleted file mode 100644
|
|
index c442a96..0000000
|
|
--- a/nselib/pcre.luadoc
|
|
+++ /dev/null
|
|
@@ -1,135 +0,0 @@
|
|
----
|
|
--- Perl Compatible Regular Expressions.
|
|
---
|
|
--- One of Lua's quirks is its string patterns. While they have great performance
|
|
--- and are tightly integrated into the Lua interpreter, they are very different
|
|
--- in syntax and not as powerful as standard regular expressions. So we have
|
|
--- integrated Perl compatible regular expressions into Lua using PCRE and a
|
|
--- modified version of the Lua PCRE library written by Reuben Thomas and Shmuel
|
|
--- Zeigerman. These are the same sort of regular expressions used by Nmap
|
|
--- version detection. The main modification to their library is that the NSE
|
|
--- version only supports PCRE expressions instead of both PCRE and POSIX
|
|
--- patterns. In order to maintain a high script execution speed, the library
|
|
--- interfacing with PCRE is kept very thin. It is not integrated as seamlessly
|
|
--- as the Lua string pattern API. This allows script authors to decide when to
|
|
--- use PCRE expressions versus Lua patterns. The use of PCRE involves a
|
|
--- separate pattern compilation step, which saves execution time when patterns
|
|
--- are reused. Compiled patterns can be cached in the NSE registry and reused
|
|
--- by other scripts.
|
|
---
|
|
--- The documentation for this module is derived from that supplied by the PCRE
|
|
--- Lua lib.
|
|
---
|
|
--- Warning: PCRE has a history of security vulnerabilities allowing attackers
|
|
--- who are able to compile arbitrary regular expressions to execute arbitrary
|
|
--- code. More such vulnerabilities may be discovered in the future. These have
|
|
--- never affected Nmap because it doesn't give attackers any control over the
|
|
--- regular expressions it uses. Similarly, NSE scripts should never build
|
|
--- regular expressions with untrusted network input. Matching hardcoded regular
|
|
--- expressions against the untrusted input is fine.
|
|
--- @author Reuben Thomas
|
|
--- @author Shmuel Zeigerman
|
|
-
|
|
-module "pcre"
|
|
-
|
|
---- Returns a compiled regular expression.
|
|
---
|
|
--- The resulting compiled regular expression is ready to be matched against
|
|
--- strings. Compiled regular expressions are subject to Lua's garbage
|
|
--- collection.
|
|
---
|
|
--- The compilation flags are set bitwise. If you want to set the 3rd
|
|
--- (corresponding to the number 4) and the 1st (corresponding to 1) bit for
|
|
--- example you would pass the number 5 as a second argument. The compilation
|
|
--- flags accepted are those of the PCRE C library. These include flags for case
|
|
--- insensitive matching (<code>1</code>), matching line beginnings
|
|
--- (<code>^</code>) and endings (<code>$</code>) even in multiline strings
|
|
--- (i.e. strings containing newlines) (<code>2</code>) and a flag for matching
|
|
--- across line boundaries (<code>4</code>). No compilation flags yield a
|
|
--- default value of <code>0</code>.
|
|
--- @param pattern a string describing the pattern, such as <code>"^foo$"</code>.
|
|
--- @param flags a number describing which compilation flags are set.
|
|
--- @param locale a string describing the locale which should be used to compile
|
|
--- the regular expression (optional). The value is a string which is passed to
|
|
--- the C standard library function <code>setlocale</code>. For more
|
|
--- information on this argument refer to the documentation of
|
|
--- <code>setlocale</code>.
|
|
--- @usage local regex = pcre.new("pcre-pattern",0,"C")
|
|
-function new(pattern, flags, locale)
|
|
-
|
|
---- Returns a table of the available PCRE option flags (numbers) keyed by their
|
|
--- names (strings).
|
|
---
|
|
--- Possible names of the available strings can be retrieved from the
|
|
--- documentation of the PCRE library used to link against Nmap. The key is the
|
|
--- option name in the manual minus the <code>PCRE_</code> prefix.
|
|
--- <code>PCRE_CASELESS</code> becomes <code>CASELESS</code> for example.
|
|
-function flags()
|
|
-
|
|
---- Returns the version of the PCRE library in use as a string.
|
|
---
|
|
--- For example <code>"6.4 05-Sep-2005"</code>.
|
|
-function version()
|
|
-
|
|
---- Matches a string against a compiled regular expression.
|
|
---
|
|
--- Returns the start point and the end point of the first match of the compiled
|
|
--- regular expression in the string.
|
|
--- @param string the string to match against.
|
|
--- @param start where to start the match in the string (optional).
|
|
--- @param flags execution flags (optional).
|
|
--- @return <code>nil</code> if no match, otherwise the start point of the first
|
|
--- match.
|
|
--- @return the end point of the first match.
|
|
--- @return a table which contains false in the positions where the pattern did
|
|
--- not match. If named sub-patterns were used, the table also contains substring
|
|
--- matches keyed by their sub-pattern name.
|
|
--- @usage
|
|
--- i, j = regex:match("string to be searched", 0, 0)
|
|
--- if (i) then ... end
|
|
-function match(string, start, flags)
|
|
-
|
|
---- Matches a string against a compiled regular expression, returning positions
|
|
--- of substring matches.
|
|
---
|
|
--- This function is like <code>match</code> except that a table returned as a
|
|
--- third result contains offsets of substring matches rather than substring
|
|
--- matches themselves. That table will not contain string keys, even if named
|
|
--- sub-patterns are used. For example, if the whole match is at offsets 10, 20
|
|
--- and substring matches are at offsets 12, 14 and 16, 19 then the function
|
|
--- returns <code>10, 20, {12,14,16,19}</code>.
|
|
--- @param string the string to match against.
|
|
--- @param start where to start the match in the string (optional).
|
|
--- @param flags execution flags (optional).
|
|
--- @return <code>nil</code> if no match, otherwise the start point of the match
|
|
--- of the whole string.
|
|
--- @return the end point of the match of the whole string.
|
|
--- @return a table containing a list of substring match start and end positions.
|
|
--- @usage
|
|
--- i, j, substrings = regex:exec("string to be searched", 0, 0)
|
|
--- if (i) then ... end
|
|
-function exec(string, start, flags)
|
|
-
|
|
---- Matches a string against a regular expression multiple times.
|
|
---
|
|
--- Tries to match the regular expression pcre_obj against string up to
|
|
--- <code>n</code> times (or as many as possible if <code>n</code> is not given
|
|
--- or is not a positive number), subject to the execution flags
|
|
--- <code>ef</code>. Each time there is a match, <code>func</code> is called as
|
|
--- <code>func(m, t)</code>, where <code>m</code> is the matched string and
|
|
--- <code>t</code> is a table of substring matches. This table contains false in
|
|
--- the positions where the corresponding sub-pattern did not match. If named
|
|
--- sub-patterns are used then the table also contains substring matches keyed
|
|
--- by their correspondent sub-pattern names (strings). If <code>func</code>
|
|
--- returns a true value, then <code>gmatch</code> immediately returns;
|
|
--- <code>gmatch</code> returns the number of matches made.
|
|
--- @param string the string to match against.
|
|
--- @param func the function to call for each match.
|
|
--- @param n the maximum number of matches to do (optional).
|
|
--- @param ef execution flags (optional).
|
|
--- @return the number of matches made.
|
|
--- @usage
|
|
--- local t = {}
|
|
--- local function match(m) t[#t + 1] = m end
|
|
--- local n = regex:gmatch("string to be searched", match)
|
|
-function pcre_obj:gmatch(string, func, n, ef)
|
|
diff --git a/service_scan.cc b/service_scan.cc
|
|
index cf13d8b..473b3a6 100644
|
|
--- a/service_scan.cc
|
|
+++ b/service_scan.cc
|
|
@@ -250,7 +250,7 @@ ServiceProbeMatch::ServiceProbeMatch() {
|
|
product_template = version_template = info_template = NULL;
|
|
hostname_template = ostype_template = devicetype_template = NULL;
|
|
regex_compiled = NULL;
|
|
- regex_extra = NULL;
|
|
+ match_data = NULL;
|
|
isInitialized = false;
|
|
matchops_ignorecase = false;
|
|
matchops_dotall = false;
|
|
@@ -269,8 +269,21 @@ ServiceProbeMatch::~ServiceProbeMatch() {
|
|
if (devicetype_template) free(devicetype_template);
|
|
for (it = cpe_templates.begin(); it != cpe_templates.end(); it++)
|
|
free(*it);
|
|
- if (regex_compiled) pcre_free(regex_compiled);
|
|
- if (regex_extra) pcre_free(regex_extra);
|
|
+ if (regex_compiled)
|
|
+ {
|
|
+ pcre2_code_free(regex_compiled);
|
|
+ regex_compiled=NULL;
|
|
+ }
|
|
+ if (match_data)
|
|
+ {
|
|
+ pcre2_match_data_free(match_data);
|
|
+ match_data=NULL;
|
|
+ }
|
|
+ if (match_context)
|
|
+ {
|
|
+ pcre2_match_context_free(match_context);
|
|
+ match_context=NULL;
|
|
+ }
|
|
isInitialized = false;
|
|
}
|
|
|
|
@@ -350,9 +363,9 @@ void ServiceProbeMatch::InitMatch(const char *matchtext, int lineno) {
|
|
char *tmptemplate;
|
|
char modestr[4];
|
|
char flags[4];
|
|
- int pcre_compile_ops = 0;
|
|
- const char *pcre_errptr = NULL;
|
|
- int pcre_erroffset = 0;
|
|
+ int pcre2_compile_ops = 0;
|
|
+ int pcre2_errcode;
|
|
+ PCRE2_SIZE pcre2_erroffset;
|
|
char **curr_tmp = NULL;
|
|
|
|
if (isInitialized) fatal("Sorry ... %s does not yet support reinitializion", __func__);
|
|
@@ -405,41 +418,42 @@ void ServiceProbeMatch::InitMatch(const char *matchtext, int lineno) {
|
|
|
|
// Next we compile and study the regular expression to match
|
|
if (matchops_ignorecase)
|
|
- pcre_compile_ops |= PCRE_CASELESS;
|
|
+ pcre2_compile_ops |= PCRE2_CASELESS;
|
|
|
|
if (matchops_dotall)
|
|
- pcre_compile_ops |= PCRE_DOTALL;
|
|
+ pcre2_compile_ops |= PCRE2_DOTALL;
|
|
|
|
- regex_compiled = pcre_compile(matchstr, pcre_compile_ops, &pcre_errptr,
|
|
- &pcre_erroffset, NULL);
|
|
+ regex_compiled = pcre2_compile((PCRE2_SPTR)matchstr,PCRE2_ZERO_TERMINATED, pcre2_compile_ops, &pcre2_errcode,
|
|
+ &pcre2_erroffset, NULL);
|
|
|
|
if (regex_compiled == NULL)
|
|
- fatal("%s: illegal regexp on line %d of nmap-service-probes (at regexp offset %d): %s\n", __func__, lineno, pcre_erroffset, pcre_errptr);
|
|
+ fatal("%s: illegal regexp on line %d of nmap-service-probes (at regexp offset %ld): %d\n", __func__, lineno, pcre2_erroffset, pcre2_errcode);
|
|
|
|
- // Now study the regexp for greater efficiency
|
|
- regex_extra = pcre_study(regex_compiled, 0
|
|
-#ifdef PCRE_STUDY_EXTRA_NEEDED
|
|
- | PCRE_STUDY_EXTRA_NEEDED
|
|
-#endif
|
|
- , &pcre_errptr);
|
|
- if (pcre_errptr != NULL)
|
|
- fatal("%s: failed to pcre_study regexp on line %d of nmap-service-probes: %s\n", __func__, lineno, pcre_errptr);
|
|
+ // creates a new match data block for holding the result of a match
|
|
+ match_data = pcre2_match_data_create_from_pattern(
|
|
+ regex_compiled,NULL
|
|
+ );
|
|
|
|
- if (!regex_extra) {
|
|
- regex_extra = (pcre_extra *) pcre_malloc(sizeof(pcre_extra));
|
|
- memset(regex_extra, 0, sizeof(pcre_extra));
|
|
+ if (!match_data) {
|
|
+ fatal("%s: failed to allocate match_data\n", __func__);
|
|
}
|
|
|
|
+ match_context = pcre2_match_context_create(NULL);
|
|
+
|
|
+ if (!match_context) {
|
|
+ fatal("%s: failed to allocate match_context\n", __func__);
|
|
+ }
|
|
// Set some limits to avoid evil match cases.
|
|
// These are flexible; if they cause problems, increase them.
|
|
-#ifdef PCRE_ERROR_MATCHLIMIT
|
|
- regex_extra->match_limit = 100000; // 100K
|
|
-#endif
|
|
-#ifdef PCRE_ERROR_RECURSIONLIMIT
|
|
- regex_extra->match_limit_recursion = 10000; // 10K
|
|
+ pcre2_set_match_limit(match_context, 100000);
|
|
+#ifdef pcre2_set_depth_limit
|
|
+ // Changed name in PCRE2 10.30. PCRE2 uses macro definitions for function
|
|
+ // names, so we don't have to add this to configure.ac.
|
|
+ pcre2_set_depth_limit(match_context, 10000);
|
|
+#else
|
|
+ pcre2_set_recursion_limit(match_context, 10000);
|
|
#endif
|
|
|
|
-
|
|
/* OK! Now we look for any templates of the form ?/.../
|
|
* where ? is either p, v, i, h, o, or d. / is any
|
|
* delimiter character and ... is a template */
|
|
@@ -509,34 +523,29 @@ const struct MatchDetails *ServiceProbeMatch::testMatch(const u8 *buf, int bufle
|
|
static char devicetype[32];
|
|
static char cpe_a[80], cpe_h[80], cpe_o[80];
|
|
char *bufc = (char *) buf;
|
|
- int ovector[150]; // allows 50 substring matches (including the overall match)
|
|
assert(isInitialized);
|
|
|
|
// Clear out the output struct
|
|
memset(&MD_return, 0, sizeof(MD_return));
|
|
MD_return.isSoft = isSoft;
|
|
|
|
- rc = pcre_exec(regex_compiled, regex_extra, bufc, buflen, 0, 0, ovector, sizeof(ovector) / sizeof(*ovector));
|
|
+ rc = pcre2_match(regex_compiled, (PCRE2_SPTR8)bufc, buflen, 0, 0, match_data, match_context);
|
|
if (rc < 0) {
|
|
-#ifdef PCRE_ERROR_MATCHLIMIT // earlier PCRE versions lack this
|
|
- if (rc == PCRE_ERROR_MATCHLIMIT) {
|
|
+ if (rc == PCRE2_ERROR_MATCHLIMIT) {
|
|
if (o.debugging || o.verbose > 1)
|
|
error("Warning: Hit PCRE_ERROR_MATCHLIMIT when probing for service %s with the regex '%s'", servicename, matchstr);
|
|
} else
|
|
-#endif // PCRE_ERROR_MATCHLIMIT
|
|
-#ifdef PCRE_ERROR_RECURSIONLIMIT
|
|
- if (rc == PCRE_ERROR_RECURSIONLIMIT) {
|
|
+ if (rc == PCRE2_ERROR_RECURSIONLIMIT) {
|
|
if (o.debugging || o.verbose > 1)
|
|
error("Warning: Hit PCRE_ERROR_RECURSIONLIMIT when probing for service %s with the regex '%s'", servicename, matchstr);
|
|
} else
|
|
-#endif // PCRE_ERROR_RECURSIONLIMIT
|
|
- if (rc != PCRE_ERROR_NOMATCH) {
|
|
+ if (rc != PCRE2_ERROR_NOMATCH) {
|
|
fatal("Unexpected PCRE error (%d) when probing for service %s with the regex '%s'", rc, servicename, matchstr);
|
|
}
|
|
} else {
|
|
// Yeah! Match apparently succeeded.
|
|
// Now lets get the version number if available
|
|
- getVersionStr(buf, buflen, ovector, rc, product, sizeof(product), version, sizeof(version), info, sizeof(info),
|
|
+ getVersionStr(buf, buflen, product, sizeof(product), version, sizeof(version), info, sizeof(info),
|
|
hostname, sizeof(hostname), ostype, sizeof(ostype), devicetype, sizeof(devicetype),
|
|
cpe_a, sizeof(cpe_a), cpe_h, sizeof(cpe_h), cpe_o, sizeof(cpe_o));
|
|
if (*product) MD_return.product = product;
|
|
@@ -685,18 +694,17 @@ static char *transform_cpe(const char *s) {
|
|
// This function does the substitution of a placeholder like $2 or $P(4). It
|
|
// returns a newly allocated string, or NULL if it fails. tmplvar is a template
|
|
// variable, such as "$P(2)". We set *tmplvarend to the character after the
|
|
-// variable. subject, subjectlen, ovector, and nummatches mean the same as in
|
|
+// variable. subject, subjectlen, and match_data mean the same as in
|
|
// dotmplsubst().
|
|
static char *substvar(char *tmplvar, char **tmplvarend,
|
|
- const u8 *subject, int subjectlen, int *ovector,
|
|
- int nummatches) {
|
|
+ const u8 *subject, size_t subjectlen, pcre2_match_data *match_data
|
|
+ ) {
|
|
char substcommand[16];
|
|
char *p = NULL;
|
|
char *p_end;
|
|
- int subnum = 0;
|
|
- int offstart, offend;
|
|
+ u8 subnum = 0;
|
|
+ PCRE2_SIZE offstart, offend;
|
|
int rc;
|
|
- int i;
|
|
struct substargs command_args;
|
|
char *result;
|
|
size_t n, len;
|
|
@@ -728,6 +736,8 @@ static char *substvar(char *tmplvar, char **tmplvarend,
|
|
}
|
|
|
|
if (tmplvarend) *tmplvarend = tmplvar;
|
|
+ u32 nummatches = pcre2_get_ovector_count(match_data);
|
|
+ PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
|
|
|
|
strbuf_init(&result, &n, &len);
|
|
if (!*substcommand) {
|
|
@@ -735,9 +745,10 @@ static char *substvar(char *tmplvar, char **tmplvarend,
|
|
if (subnum > 9 || subnum <= 0) return NULL;
|
|
if (subnum >= nummatches) return NULL;
|
|
offstart = ovector[subnum * 2];
|
|
+ if (offstart == PCRE2_UNSET) return NULL;
|
|
offend = ovector[subnum * 2 + 1];
|
|
- assert(offstart >= 0 && offstart <= subjectlen);
|
|
- assert(offend >= 0 && offend <= subjectlen);
|
|
+ assert(offstart <= subjectlen);
|
|
+ assert(offend != PCRE2_UNSET && offend <= subjectlen);
|
|
// A plain-jane copy
|
|
strbuf_append(&result, &n, &len, (const char *) subject + offstart, offend - offstart);
|
|
} else if (strcmp(substcommand, "P") == 0) {
|
|
@@ -749,13 +760,14 @@ static char *substvar(char *tmplvar, char **tmplvarend,
|
|
if (subnum > 9 || subnum <= 0) return NULL;
|
|
if (subnum >= nummatches) return NULL;
|
|
offstart = ovector[subnum * 2];
|
|
+ if (offstart == PCRE2_UNSET) return NULL;
|
|
offend = ovector[subnum * 2 + 1];
|
|
- assert(offstart >= 0 && offstart <= subjectlen);
|
|
- assert(offend >= 0 && offend <= subjectlen);
|
|
+ assert(offstart <= subjectlen);
|
|
+ assert(offend != PCRE2_UNSET && offend <= subjectlen);
|
|
// This filter only includes printable characters. It is particularly
|
|
// useful for collapsing unicode text that looks like
|
|
// "W\0O\0R\0K\0G\0R\0O\0U\0P\0"
|
|
- for(i=offstart; i < offend; i++) {
|
|
+ for(PCRE2_SIZE i=offstart; i < offend; i++) {
|
|
if (isprint((int) subject[i]))
|
|
strbuf_append(&result, &n, &len, (const char *) subject + i, 1);
|
|
}
|
|
@@ -772,14 +784,15 @@ static char *substvar(char *tmplvar, char **tmplvarend,
|
|
if (subnum > 9 || subnum <= 0) return NULL;
|
|
if (subnum >= nummatches) return NULL;
|
|
offstart = ovector[subnum * 2];
|
|
+ if (offstart == PCRE2_UNSET) return NULL;
|
|
offend = ovector[subnum * 2 + 1];
|
|
- assert(offstart >= 0 && offstart <= subjectlen);
|
|
- assert(offend >= 0 && offend <= subjectlen);
|
|
+ assert(offstart <= subjectlen);
|
|
+ assert(offend != PCRE2_UNSET && offend <= subjectlen);
|
|
findstr = command_args.str_args[1];
|
|
findstrlen = command_args.str_args_len[1];
|
|
replstr = command_args.str_args[2];
|
|
replstrlen = command_args.str_args_len[2];
|
|
- for(i=offstart; i < offend; ) {
|
|
+ for(PCRE2_SIZE i=offstart; i < offend; ) {
|
|
if (memcmp(subject + i, findstr, findstrlen) != 0) {
|
|
strbuf_append(&result, &n, &len, (const char *) subject + i, 1); // no match
|
|
i++;
|
|
@@ -805,8 +818,9 @@ static char *substvar(char *tmplvar, char **tmplvarend,
|
|
if (subnum > 9 || subnum <= 0) return NULL;
|
|
if (subnum >= nummatches) return NULL;
|
|
offstart = ovector[subnum * 2];
|
|
+ if (offstart == PCRE2_UNSET) return NULL;
|
|
offend = ovector[subnum * 2 + 1];
|
|
- assert(offstart >= 0 && offstart <= subjectlen);
|
|
+ assert(offend != PCRE2_UNSET && offstart <= subjectlen);
|
|
|
|
// overflow
|
|
if (offend - offstart > 8) {
|
|
@@ -824,11 +838,11 @@ static char *substvar(char *tmplvar, char **tmplvarend,
|
|
break;
|
|
}
|
|
if (bigendian) {
|
|
- for(i=offstart; i < offend; i++) {
|
|
+ for(PCRE2_SIZE i=offstart; i < offend; i++) {
|
|
val = (val<<8) + subject[i];
|
|
}
|
|
} else {
|
|
- for(i=offend - 1; i > offstart - 1; i--) {
|
|
+ for(PCRE2_SIZE i=offend - 1; i > offstart - 1; i--) {
|
|
val = (val<<8) + subject[i];
|
|
}
|
|
}
|
|
@@ -847,16 +861,16 @@ static char *substvar(char *tmplvar, char **tmplvarend,
|
|
|
|
// This function takes a template string (tmpl) which can have
|
|
// placeholders in it such as $1 for substring matches in a regexp
|
|
-// that was run against subject, and subjectlen, with the 'nummatches'
|
|
-// matches in ovector. The NUL-terminated newly composted string is
|
|
+// that was run against subject, and subjectlen, with the
|
|
+// matches in match_data. The NUL-terminated newly composted string is
|
|
// placed into 'newstr', as long as it doesn't exceed 'newstrlen'
|
|
// bytes. Trailing whitespace and commas are removed. Returns zero for success
|
|
//
|
|
// The transform argument is a function pointer. If not NULL, the given
|
|
// function is applied to all substitutions before they are inserted
|
|
// into the result string.
|
|
-static int dotmplsubst(const u8 *subject, int subjectlen,
|
|
- int *ovector, int nummatches, char *tmpl, char *newstr,
|
|
+static int dotmplsubst(const u8 *subject, size_t subjectlen,
|
|
+ pcre2_match_data *match_data, char *tmpl, char *newstr,
|
|
int newstrlen,
|
|
char *(*transform)(const char *) = NULL) {
|
|
int newlen;
|
|
@@ -895,7 +909,7 @@ static int dotmplsubst(const u8 *subject, int subjectlen,
|
|
dst += newlen;
|
|
}
|
|
srcstart = srcend;
|
|
- subst = substvar(srcstart, &srcend, subject, subjectlen, ovector, nummatches);
|
|
+ subst = substvar(srcstart, &srcend, subject, subjectlen, match_data);
|
|
if (subst == NULL)
|
|
return -1;
|
|
/* Apply transformation if requested. */
|
|
@@ -937,14 +951,14 @@ static int dotmplsubst(const u8 *subject, int subjectlen,
|
|
// for a string, that string will have zero length after the function
|
|
// call (assuming the corresponding length passed in is at least 1)
|
|
|
|
-int ServiceProbeMatch::getVersionStr(const u8 *subject, int subjectlen,
|
|
- int *ovector, int nummatches, char *product, int productlen,
|
|
- char *version, int versionlen, char *info, int infolen,
|
|
- char *hostname, int hostnamelen, char *ostype, int ostypelen,
|
|
- char *devicetype, int devicetypelen,
|
|
- char *cpe_a, int cpe_alen,
|
|
- char *cpe_h, int cpe_hlen,
|
|
- char *cpe_o, int cpe_olen) const {
|
|
+int ServiceProbeMatch::getVersionStr(const u8 *subject, size_t subjectlen,
|
|
+ char *product, size_t productlen,
|
|
+ char *version, size_t versionlen, char *info, size_t infolen,
|
|
+ char *hostname, size_t hostnamelen, char *ostype, size_t ostypelen,
|
|
+ char *devicetype, size_t devicetypelen,
|
|
+ char *cpe_a, size_t cpe_alen,
|
|
+ char *cpe_h, size_t cpe_hlen,
|
|
+ char *cpe_o, size_t cpe_olen) const {
|
|
|
|
int rc;
|
|
assert(productlen >= 0 && versionlen >= 0 && infolen >= 0 &&
|
|
@@ -963,9 +977,9 @@ int ServiceProbeMatch::getVersionStr(const u8 *subject, int subjectlen,
|
|
|
|
// Now lets get this started! We begin with the product name
|
|
if (product_template) {
|
|
- rc = dotmplsubst(subject, subjectlen, ovector, nummatches, product_template, product, productlen);
|
|
+ rc = dotmplsubst(subject, subjectlen, match_data, product_template, product, productlen);
|
|
if (rc != 0) {
|
|
- error("Warning: Servicescan failed to fill product_template (subjectlen: %d, productlen: %d). Capture exceeds length? Match string was line %d: p/%s/%s/%s", subjectlen, productlen, deflineno,
|
|
+ error("Warning: Servicescan failed to fill product_template (subjectlen: %lu, productlen: %lu). Capture exceeds length? Match string was line %d: p/%s/%s/%s", subjectlen, productlen, deflineno,
|
|
(product_template)? product_template : "",
|
|
(version_template)? version_template : "",
|
|
(info_template)? info_template : "");
|
|
@@ -975,9 +989,9 @@ int ServiceProbeMatch::getVersionStr(const u8 *subject, int subjectlen,
|
|
}
|
|
|
|
if (version_template) {
|
|
- rc = dotmplsubst(subject, subjectlen, ovector, nummatches, version_template, version, versionlen);
|
|
+ rc = dotmplsubst(subject, subjectlen, match_data, version_template, version, versionlen);
|
|
if (rc != 0) {
|
|
- error("Warning: Servicescan failed to fill version_template (subjectlen: %d, versionlen: %d). Capture exceeds length? Match string was line %d: v/%s/%s/%s", subjectlen, versionlen, deflineno,
|
|
+ error("Warning: Servicescan failed to fill version_template (subjectlen: %lu, versionlen: %lu). Capture exceeds length? Match string was line %d: v/%s/%s/%s", subjectlen, versionlen, deflineno,
|
|
(product_template)? product_template : "",
|
|
(version_template)? version_template : "",
|
|
(info_template)? info_template : "");
|
|
@@ -987,9 +1001,9 @@ int ServiceProbeMatch::getVersionStr(const u8 *subject, int subjectlen,
|
|
}
|
|
|
|
if (info_template) {
|
|
- rc = dotmplsubst(subject, subjectlen, ovector, nummatches, info_template, info, infolen);
|
|
+ rc = dotmplsubst(subject, subjectlen, match_data, info_template, info, infolen);
|
|
if (rc != 0) {
|
|
- error("Warning: Servicescan failed to fill info_template (subjectlen: %d, infolen: %d). Capture exceeds length? Match string was line %d: i/%s/%s/%s", subjectlen, infolen, deflineno,
|
|
+ error("Warning: Servicescan failed to fill info_template (subjectlen: %lu, infolen: %lu). Capture exceeds length? Match string was line %d: i/%s/%s/%s", subjectlen, infolen, deflineno,
|
|
(product_template)? product_template : "",
|
|
(version_template)? version_template : "",
|
|
(info_template)? info_template : "");
|
|
@@ -999,9 +1013,9 @@ int ServiceProbeMatch::getVersionStr(const u8 *subject, int subjectlen,
|
|
}
|
|
|
|
if (hostname_template) {
|
|
- rc = dotmplsubst(subject, subjectlen, ovector, nummatches, hostname_template, hostname, hostnamelen);
|
|
+ rc = dotmplsubst(subject, subjectlen, match_data, hostname_template, hostname, hostnamelen);
|
|
if (rc != 0) {
|
|
- error("Warning: Servicescan failed to fill hostname_template (subjectlen: %d, hostnamelen: %d). Capture exceeds length? Match string was line %d: h/%s/", subjectlen, hostnamelen, deflineno,
|
|
+ error("Warning: Servicescan failed to fill hostname_template (subjectlen: %lu, hostnamelen: %lu). Capture exceeds length? Match string was line %d: h/%s/", subjectlen, hostnamelen, deflineno,
|
|
(hostname_template)? hostname_template : "");
|
|
if (hostnamelen > 0) *hostname = '\0';
|
|
retval = -1;
|
|
@@ -1009,9 +1023,9 @@ int ServiceProbeMatch::getVersionStr(const u8 *subject, int subjectlen,
|
|
}
|
|
|
|
if (ostype_template) {
|
|
- rc = dotmplsubst(subject, subjectlen, ovector, nummatches, ostype_template, ostype, ostypelen);
|
|
+ rc = dotmplsubst(subject, subjectlen, match_data, ostype_template, ostype, ostypelen);
|
|
if (rc != 0) {
|
|
- error("Warning: Servicescan failed to fill ostype_template (subjectlen: %d, ostypelen: %d). Capture exceeds length? Match string was line %d: o/%s/", subjectlen, ostypelen, deflineno,
|
|
+ error("Warning: Servicescan failed to fill ostype_template (subjectlen: %lu, ostypelen: %lu). Capture exceeds length? Match string was line %d: o/%s/", subjectlen, ostypelen, deflineno,
|
|
(ostype_template)? ostype_template : "");
|
|
if (ostypelen > 0) *ostype = '\0';
|
|
retval = -1;
|
|
@@ -1019,9 +1033,9 @@ int ServiceProbeMatch::getVersionStr(const u8 *subject, int subjectlen,
|
|
}
|
|
|
|
if (devicetype_template) {
|
|
- rc = dotmplsubst(subject, subjectlen, ovector, nummatches, devicetype_template, devicetype, devicetypelen);
|
|
+ rc = dotmplsubst(subject, subjectlen, match_data, devicetype_template, devicetype, devicetypelen);
|
|
if (rc != 0) {
|
|
- error("Warning: Servicescan failed to fill devicetype_template (subjectlen: %d, devicetypelen: %d). Too long? Match string was line %d: d/%s/", subjectlen, devicetypelen, deflineno,
|
|
+ error("Warning: Servicescan failed to fill devicetype_template (subjectlen: %lu, devicetypelen: %lu). Too long? Match string was line %d: d/%s/", subjectlen, devicetypelen, deflineno,
|
|
(devicetype_template)? devicetype_template : "");
|
|
if (devicetypelen > 0) *devicetype = '\0';
|
|
retval = -1;
|
|
@@ -1032,7 +1046,7 @@ int ServiceProbeMatch::getVersionStr(const u8 *subject, int subjectlen,
|
|
store in cpe_a, cpe_h, or cpe_o as appropriate. */
|
|
for (unsigned int i = 0; i < cpe_templates.size(); i++) {
|
|
char *cpe;
|
|
- int cpelen;
|
|
+ size_t cpelen;
|
|
int part;
|
|
|
|
part = cpe_get_part(cpe_templates[i]);
|
|
@@ -1055,9 +1069,9 @@ int ServiceProbeMatch::getVersionStr(const u8 *subject, int subjectlen,
|
|
continue;
|
|
break;
|
|
}
|
|
- rc = dotmplsubst(subject, subjectlen, ovector, nummatches, cpe_templates[i], cpe, cpelen, transform_cpe);
|
|
+ rc = dotmplsubst(subject, subjectlen, match_data, cpe_templates[i], cpe, cpelen, transform_cpe);
|
|
if (rc != 0) {
|
|
- error("Warning: Servicescan failed to fill cpe_%c (subjectlen: %d, cpelen: %d). Too long? Match string was line %d: %s", part, subjectlen, cpelen, deflineno,
|
|
+ error("Warning: Servicescan failed to fill cpe_%c (subjectlen: %lu, cpelen: %lu). Too long? Match string was line %d: %s", part, subjectlen, cpelen, deflineno,
|
|
(cpe_templates[i])? cpe_templates[i] : "");
|
|
if (cpelen > 0) *cpe = '\0';
|
|
retval = -1;
|
|
diff --git a/service_scan.h b/service_scan.h
|
|
index 7723d81..8ebdee7 100644
|
|
--- a/service_scan.h
|
|
+++ b/service_scan.h
|
|
@@ -69,16 +69,8 @@
|
|
|
|
#include <vector>
|
|
|
|
-#ifdef HAVE_CONFIG_H
|
|
-/* Needed for HAVE_PCRE_PCRE_H below */
|
|
-#include "nmap_config.h"
|
|
-#endif /* HAVE_CONFIG_H */
|
|
-
|
|
-#ifdef HAVE_PCRE_PCRE_H
|
|
-# include <pcre/pcre.h>
|
|
-#else
|
|
-# include <pcre.h>
|
|
-#endif
|
|
+#define PCRE2_CODE_UNIT_WIDTH 8
|
|
+#include <pcre2.h>
|
|
|
|
#undef NDEBUG
|
|
#include <assert.h>
|
|
@@ -155,8 +147,9 @@ class ServiceProbeMatch {
|
|
bool isInitialized; // Has InitMatch yet been called?
|
|
const char *servicename;
|
|
char *matchstr; // Regular expression text
|
|
- pcre *regex_compiled;
|
|
- pcre_extra *regex_extra;
|
|
+ pcre2_code *regex_compiled;
|
|
+ pcre2_match_data *match_data;
|
|
+ pcre2_match_context *match_context;
|
|
bool matchops_ignorecase;
|
|
bool matchops_dotall;
|
|
bool isSoft; // is this a soft match? ("softmatch" keyword in nmap-service-probes)
|
|
@@ -179,14 +172,14 @@ class ServiceProbeMatch {
|
|
// are sufficient). Returns zero for success. If no template is available
|
|
// for a string, that string will have zero length after the function
|
|
// call (assuming the corresponding length passed in is at least 1)
|
|
- int getVersionStr(const u8 *subject, int subjectlen, int *ovector,
|
|
- int nummatches, char *product, int productlen,
|
|
- char *version, int versionlen, char *info, int infolen,
|
|
- char *hostname, int hostnamelen, char *ostype, int ostypelen,
|
|
- char *devicetype, int devicetypelen,
|
|
- char *cpe_a, int cpe_alen,
|
|
- char *cpe_h, int cpe_hlen,
|
|
- char *cpe_o, int cpe_olen) const;
|
|
+ int getVersionStr(const u8 *subject, size_t subjectlen,
|
|
+ char *product, size_t productlen,
|
|
+ char *version, size_t versionlen, char *info, size_t infolen,
|
|
+ char *hostname, size_t hostnamelen, char *ostype, size_t ostypelen,
|
|
+ char *devicetype, size_t devicetypelen,
|
|
+ char *cpe_a, size_t cpe_alen,
|
|
+ char *cpe_h, size_t cpe_hlen,
|
|
+ char *cpe_o, size_t cpe_olen) const;
|
|
};
|
|
|
|
|