This commit is contained in:
Mihai Pitu 2013-08-22 14:44:02 +03:00 committed by Felipe Zimmerle
parent 656f7c513c
commit e1cd024c26
17 changed files with 1306 additions and 59 deletions

View File

@ -11,6 +11,7 @@ MAINTAINERCLEANFILES += $(CLEANFILES) \
aclocal.m4 \ aclocal.m4 \
alp2/Makefile.in \ alp2/Makefile.in \
apache2/Makefile.in \ apache2/Makefile.in \
java/Makefile.in \
build/config.guess \ build/config.guess \
build/config.sub \ build/config.sub \
build/depcomp \ build/depcomp \

45
build/ac_prog_javac.m4 Normal file
View File

@ -0,0 +1,45 @@
dnl @synopsis AC_PROG_JAVAC
dnl
dnl AC_PROG_JAVAC tests an existing Java compiler. It uses the
dnl environment variable JAVAC then tests in sequence various common
dnl Java compilers. For political reasons, it starts with the free
dnl ones.
dnl
dnl If you want to force a specific compiler:
dnl
dnl - at the configure.in level, set JAVAC=yourcompiler before calling
dnl AC_PROG_JAVAC
dnl
dnl - at the configure level, setenv JAVAC
dnl
dnl You can use the JAVAC variable in your Makefile.in, with @JAVAC@.
dnl
dnl *Warning*: its success or failure can depend on a proper setting of
dnl the CLASSPATH env. variable.
dnl
dnl TODO: allow to exclude compilers (rationale: most Java programs
dnl cannot compile with some compilers like guavac).
dnl
dnl Note: This is part of the set of autoconf M4 macros for Java
dnl programs. It is VERY IMPORTANT that you download the whole set,
dnl some macros depend on other. Unfortunately, the autoconf archive
dnl does not support the concept of set of macros, so I had to break it
dnl for submission. The general documentation, as well as the sample
dnl configure.in, is included in the AC_PROG_JAVA macro.
dnl
dnl @category Java
dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr>
dnl @version 2000-07-19
dnl @license GPLWithACException
AC_DEFUN([AC_PROG_JAVAC],[
AC_REQUIRE([AC_EXEEXT])dnl
if test "x$JAVAPREFIX" = x; then
test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT javac$EXEEXT)
else
test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT javac$EXEEXT, $JAVAPREFIX)
fi
test "x$JAVAC" = x && AC_MSG_WARN([no acceptable Java compiler found in \$PATH])
AC_PROG_JAVAC_WORKS
AC_PROVIDE([$0])dnl
])

View File

@ -0,0 +1,36 @@
dnl @synopsis AC_PROG_JAVAC_WORKS
dnl
dnl Internal use ONLY.
dnl
dnl Note: This is part of the set of autoconf M4 macros for Java
dnl programs. It is VERY IMPORTANT that you download the whole set,
dnl some macros depend on other. Unfortunately, the autoconf archive
dnl does not support the concept of set of macros, so I had to break it
dnl for submission. The general documentation, as well as the sample
dnl configure.in, is included in the AC_PROG_JAVA macro.
dnl
dnl @category Java
dnl @author Stephane Bortzmeyer <bortzmeyer@pasteur.fr>
dnl @version 2000-07-19
dnl @license GPLWithACException
AC_DEFUN([AC_PROG_JAVAC_WORKS],[
AC_CACHE_CHECK([if $JAVAC works], ac_cv_prog_javac_works, [
JAVA_TEST=Test.java
CLASS_TEST=Test.class
cat << \EOF > $JAVA_TEST
/* [#]line __oline__ "configure" */
public class Test {
}
EOF
if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) >/dev/null 2>&1; then
ac_cv_prog_javac_works=yes
else
AC_MSG_ERROR([The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?)])
echo "configure: failed program was:" >&AC_FD_CC
cat $JAVA_TEST >&AC_FD_CC
fi
rm -f $JAVA_TEST $CLASS_TEST
])
AC_PROVIDE([$0])dnl
])

129
build/ax_jni_include_dir.m4 Normal file
View File

@ -0,0 +1,129 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_JNI_INCLUDE_DIR
#
# DESCRIPTION
#
# AX_JNI_INCLUDE_DIR finds include directories needed for compiling
# programs using the JNI interface.
#
# JNI include directories are usually in the java distribution This is
# deduced from the value of JAVAC. When this macro completes, a list of
# directories is left in the variable JNI_INCLUDE_DIRS.
#
# Example usage follows:
#
# AX_JNI_INCLUDE_DIR
#
# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
# do
# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR"
# done
#
# If you want to force a specific compiler:
#
# - at the configure.in level, set JAVAC=yourcompiler before calling
# AX_JNI_INCLUDE_DIR
#
# - at the configure level, setenv JAVAC
#
# Note: This macro can work with the autoconf M4 macros for Java programs.
# This particular macro is not part of the original set of macros.
#
# LICENSE
#
# Copyright (c) 2008 Don Anderson <dda@sleepycat.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
# TSK: This has been modifed to not error out if JNI things cannot be resolved
# and to support scenarios whereby JAVAC is set to a location, but it is not
# on the path.
#serial 7
AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
AC_DEFUN([AX_JNI_INCLUDE_DIR],[
JNI_INCLUDE_DIRS=""
test "x$JAVAC" = x && AC_MSG_ERROR(['\$JAVAC' undefined])
AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])
if test "x$_ACJNI_JAVAC" = xno; then
AS_ECHO(["$JAVAC could not be found in path -- cannot resolve to JNI headers"])
else
_ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC")
_JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`
case "$host_os" in
darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
_JINC="$_JTOPDIR/Headers";;
*) _JINC="$_JTOPDIR/include";;
esac
_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
_AS_ECHO_LOG([_JINC=$_JINC])
# On Mac OS X 10.6.4, jni.h is a symlink:
# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
# -> ../../CurrentJDK/Headers/jni.h.
if test -f "$_JINC/jni.h" || test -L "$_JINC/jni.h"; then
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JINC"
else
_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
if test -f "$_JTOPDIR/include/jni.h"; then
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include"
else
AS_ECHO(["cannot find java include files"])
fi
fi
if test "x$JNI_INCLUDE_DIRS" != x; then
# get the likely subdirectories for system specific java includes
case "$host_os" in
bsdi*) _JNI_INC_SUBDIRS="bsdos";;
linux*) _JNI_INC_SUBDIRS="linux genunix";;
osf*) _JNI_INC_SUBDIRS="alpha";;
solaris*) _JNI_INC_SUBDIRS="solaris";;
mingw*) _JNI_INC_SUBDIRS="win32";;
cygwin*) _JNI_INC_SUBDIRS="win32";;
*) _JNI_INC_SUBDIRS="genunix";;
esac
# add any subdirectories that are present
for JINCSUBDIR in $_JNI_INC_SUBDIRS
do
if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
fi
done
fi
fi
])
# _ACJNI_FOLLOW_SYMLINKS <path>
# Follows symbolic links on <path>,
# finally setting variable _ACJNI_FOLLOWED
# ----------------------------------------
AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[
# find the include directory relative to the javac executable
_cur="$1"
while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do
AC_MSG_CHECKING([symlink for $_cur])
_slink=`ls -ld "$_cur" | sed 's/.* -> //'`
case "$_slink" in
/*) _cur="$_slink";;
# 'X' avoids triggering unwanted echo options.
*) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";;
esac
AC_MSG_RESULT([$_cur])
done
_ACJNI_FOLLOWED="$_cur"
])# _ACJNI

View File

@ -17,6 +17,7 @@ AC_PREFIX_DEFAULT([/usr/local/modsecurity])
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
LT_PREREQ([2.2]) LT_PREREQ([2.2])
LT_INIT([dlopen]) LT_INIT([dlopen])
@ -28,12 +29,16 @@ AC_PROG_INSTALL
AC_PROG_LN_S AC_PROG_LN_S
AC_PROG_MAKE_SET AC_PROG_MAKE_SET
AC_PROG_GREP AC_PROG_GREP
AC_PROG_CXX
AC_PATH_PROGS(PERL, [perl perl5], ) AC_PATH_PROGS(PERL, [perl perl5], )
AC_PATH_PROGS(ENV_CMD, [env printenv], ) AC_PATH_PROGS(ENV_CMD, [env printenv], )
# Checks for header files. # Checks for header files.
AC_HEADER_STDC AC_HEADER_STDC
AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h sys/utsname.h]) AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h sys/utsname.h])
AC_CHECK_HEADER([jni.h])
# Checks for typedefs, structures, and compiler characteristics. # Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST AC_C_CONST
@ -190,6 +195,46 @@ if test "$build_standalone_module" -eq 1; then
fi fi
# Java Module
AC_ARG_ENABLE(java-module,
AS_HELP_STRING([--enable-java-module],
[Enable building java module.]),
[
if test "$enableval" != "no"; then
build_java_module=1
m4_include([build/ax_jni_include_dir.m4])
m4_include([build/ac_prog_javac_works.m4])
m4_include([build/ac_prog_javac.m4])
# Test for java/jni so that we can compile the java bindings
AC_PROG_JAVAC
if test "x$JAVAC" != x; then
AX_JNI_INCLUDE_DIR
for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
do
JNI_CPPFLAGS="$JNI_CPPFLAGS -I$JNI_INCLUDE_DIR"
done
# Export the paths so that the makefile gets them
AC_SUBST(JNI_CPPFLAGS, $JNI_CPPFLAGS)
fi
AM_CONDITIONAL([X_JNI],[test "x$JNI_CPPFLAGS" != x])
AC_SUBST(STANDALONE_CPPFLAGS, "-I../standalone")
else
build_java_module=0
fi
],
[
build_java_module=0
])
AM_CONDITIONAL([BUILD_JAVA_MODULE], [test "$build_java_module" -eq 1])
if test "$build_java_module" -eq 1; then
TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS java"
fi
# Extensions # Extensions
AC_ARG_ENABLE(extentions, AC_ARG_ENABLE(extentions,
AS_HELP_STRING([--enable-extentions], AS_HELP_STRING([--enable-extentions],
@ -753,6 +798,9 @@ if test "$build_standalone_module" -ne 0; then
AC_CONFIG_FILES([standalone/Makefile]) AC_CONFIG_FILES([standalone/Makefile])
AC_CONFIG_FILES([nginx/modsecurity/config]) AC_CONFIG_FILES([nginx/modsecurity/config])
fi fi
if test "$build_java_module" -ne 0; then
AC_CONFIG_FILES([java/Makefile])
fi
if test "$build_extentions" -ne 0; then if test "$build_extentions" -ne 0; then
AC_CONFIG_FILES([ext/Makefile]) AC_CONFIG_FILES([ext/Makefile])
fi fi

90
java/Makefile.am Normal file
View File

@ -0,0 +1,90 @@
pkglibdir = $(prefix)/lib
pkglib_LTLIBRARIES = libModSecurityJNI.la
libModSecurityJNI_la_SOURCES = ../apache2/mod_security2.c \
../apache2/apache2_config.c ../apache2/apache2_io.c ../apache2/apache2_util.c \
../apache2/re.c ../apache2/re_operators.c ../apache2/re_actions.c ../apache2/re_tfns.c \
../apache2/re_variables.c ../apache2/msc_logging.c ../apache2/msc_xml.c \
../apache2/msc_multipart.c ../apache2/modsecurity.c ../apache2/msc_parsers.c \
../apache2/msc_util.c ../apache2/msc_pcre.c ../apache2/persist_dbm.c ../apache2/msc_reqbody.c \
../apache2/msc_geo.c ../apache2/msc_gsb.c ../apache2/msc_unicode.c \
../apache2/acmp.c ../apache2/msc_lua.c ../apache2/msc_release.c \
../apache2/msc_crypt.c ../apache2/msc_tree.c ../apache2/libinjection/libinjection_sqli.c \
../standalone/api.c ../standalone/buckets.c \
../standalone/config.c ../standalone/filters.c \
../standalone/hooks.c ../standalone/regex.c ../standalone/server.c \
org_modsecurity_ModSecurity.c
libModSecurityJNI_la_CFLAGS = @APXS_CFLAGS@ @APR_CFLAGS@ @APU_CFLAGS@ \
@PCRE_CFLAGS@ @LIBXML2_CFLAGS@ @LUA_CFLAGS@ @MODSEC_EXTRA_CFLAGS@ @CURL_CFLAGS@
#libModSecurityJNI_la_CXXFLAGS = @APXS_CFLAGS@ @APR_CFLAGS@ @APU_CFLAGS@ \
# @PCRE_CFLAGS@ @LIBXML2_CFLAGS@ @LUA_CFLAGS@ @MODSEC_EXTRA_CFLAGS@ @CURL_CFLAGS@
libModSecurityJNI_la_CPPFLAGS = @APR_CPPFLAGS@ @PCRE_CPPFLAGS@ @LIBXML2_CPPFLAGS@ @JNI_CPPFLAGS@
libModSecurityJNI_la_LIBADD = @APR_LDADD@ @APU_LDADD@ @PCRE_LDADD@ @LIBXML2_LDADD@ @LUA_LDADD@
if AIX
libModSecurityJNI_la_LDFLAGS = -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if HPUX
libModSecurityJNI_la_LDFLAGS = -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if MACOSX
libModSecurityJNI_la_LDFLAGS = -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if SOLARIS
libModSecurityJNI_la_LDFLAGS = -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if LINUX
libModSecurityJNI_la_LDFLAGS = -no-undefined -module -avoid-version -R @PCRE_LD_PATH@ \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if FREEBSD
libModSecurityJNI_la_LDFLAGS = -no-undefined -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if OPENBSD
libModSecurityJNI_la_LDFLAGS = -no-undefined -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if NETBSD
libModSecurityJNI_la_LDFLAGS = -no-undefined -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if LINUX
install-exec-hook: $(pkglib_LTLIBRARIES)
@echo "Removing unused static libraries..."; \
for m in $(pkglib_LTLIBRARIES); do \
base=`echo $$m | sed 's/\..*//'`; \
rm -f $(DESTDIR)$(pkglibdir)/$$base.*a; \
install -D -m444 $(DESTDIR)$(pkglibdir)/$$base.so $(DESTDIR)$(APXS_MODULES)/$$base.so; \
done
else
install-exec-hook: $(pkglib_LTLIBRARIES)
@echo "Removing unused static libraries..."; \
for m in $(pkglib_LTLIBRARIES); do \
base=`echo $$m | sed 's/\..*//'`; \
rm -f $(DESTDIR)$(pkglibdir)/$$base.*a; \
cp -p $(DESTDIR)$(pkglibdir)/$$base.so $(DESTDIR)$(APXS_MODULES); \
done
endif

View File

@ -164,7 +164,7 @@
<ClCompile Include="..\standalone\hooks.c" /> <ClCompile Include="..\standalone\hooks.c" />
<ClCompile Include="..\standalone\regex.c" /> <ClCompile Include="..\standalone\regex.c" />
<ClCompile Include="..\standalone\server.c" /> <ClCompile Include="..\standalone\server.c" />
<ClCompile Include="org_modsecurity_ModSecurity.cpp" /> <ClCompile Include="org_modsecurity_ModSecurity.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\apache2\acmp.h" /> <ClInclude Include="..\apache2\acmp.h" />

View File

@ -117,7 +117,7 @@
<ClCompile Include="..\standalone\server.c"> <ClCompile Include="..\standalone\server.c">
<Filter>Standalone Sources</Filter> <Filter>Standalone Sources</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="org_modsecurity_ModSecurity.cpp" /> <ClCompile Include="org_modsecurity_ModSecurity.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\apache2\acmp.h"> <ClInclude Include="..\apache2\acmp.h">

Binary file not shown.

32
java/ModSecurityLoader/dist/README.TXT vendored Normal file
View File

@ -0,0 +1,32 @@
========================
BUILD OUTPUT DESCRIPTION
========================
When you build an Java application project that has a main class, the IDE
automatically copies all of the JAR
files on the projects classpath to your projects dist/lib folder. The IDE
also adds each of the JAR files to the Class-Path element in the application
JAR files manifest file (MANIFEST.MF).
To run the project from the command line, go to the dist folder and
type the following:
java -jar "ModSecurityLoader.jar"
To distribute this project, zip up the dist folder (including the lib folder)
and distribute the ZIP file.
Notes:
* If two JAR files on the project classpath have the same name, only the first
JAR file is copied to the lib folder.
* Only JAR files are copied to the lib folder.
If the classpath contains other types of files or folders, these files (folders)
are not copied.
* If a library on the projects classpath also has a Class-Path element
specified in the manifest,the content of the Class-Path element has to be on
the projects runtime path.
* To set a main class in a standard Java project, right-click the project node
in the Projects window and choose Properties. Then click Run and enter the
class name in the Main Class field. Alternatively, you can manually type the
class name in the manifest Main-Class element.

View File

@ -4,30 +4,37 @@ import java.io.File;
public class ModSecurityLoader { public class ModSecurityLoader {
private static final String MODSECURITYLIBSDIR_PATH = "c:\\work\\mod_security\\java\\libs\\"; //directory with ModSecurity native libraries //private static final String MODSECURITYLIBSDIR_PATH = "c:\\work\\mod_security\\java\\libs\\"; //directory with ModSecurity native libraries
static { static {
File modSecDir = new File(MODSECURITYLIBSDIR_PATH); System.out.println("ModSecurity loader static block executed.");
// File modSecDir = new File(MODSECURITYLIBSDIR_PATH);
File[] flibs = modSecDir.listFiles(); // File[] flibs = modSecDir.listFiles();
// loadLib(flibs, "zlib1");
loadLib(flibs, "zlib1"); // loadLib(flibs, "libxml2");
loadLib(flibs, "libxml2"); // loadLib(flibs, "pcre");
loadLib(flibs, "pcre"); // loadLib(flibs, "libapr-1");
loadLib(flibs, "libapr-1"); // loadLib(flibs, "libapriconv-1");
loadLib(flibs, "libapriconv-1"); // loadLib(flibs, "libaprutil-1");
loadLib(flibs, "libaprutil-1"); // loadLib(flibs, "ModSecurityJNI");
loadLib(flibs, "ModSecurityJNI");
//alternative load, this requires native libraries to be in java.library.path, you can set it //alternative load, this requires native libraries to be in java.library.path, you can set it
//by specifying server VM start-up option: -Djava.library.path=path/to/libs/ //by specifying server VM start-up option: -Djava.library.path=path/to/libs/
// System.loadLibrary("zlib1"); try {
// System.loadLibrary("libxml2"); System.loadLibrary("zlib1"); //needed for libxml2 in Windows
// System.loadLibrary("pcre"); } catch(UnsatisfiedLinkError ex) {
// System.loadLibrary("libapr-1"); }
// System.loadLibrary("libapriconv-1"); System.loadLibrary("libxml2");
// System.loadLibrary("libaprutil-1"); System.loadLibrary("pcre");
// System.loadLibrary("ModSecurityJNI"); System.loadLibrary("libapr-1");
try {
System.loadLibrary("libapriconv-1");
} catch(UnsatisfiedLinkError ex) { //needed for libaprutil-1 in Windows
}
System.loadLibrary("libaprutil-1");
System.loadLibrary("ModSecurityJNI");
System.out.println("ModSecurity native libraries loaded.");
} }
private static void loadLib(File[] files, String lib) { private static void loadLib(File[] files, String lib) {

View File

@ -7,10 +7,7 @@ import java.net.UnknownHostException;
import javax.servlet.FilterConfig; import javax.servlet.FilterConfig;
import javax.servlet.ServletException; import javax.servlet.ServletException;
/**
*
* @author Mihai Pitu
*/
public final class ModSecurity { public final class ModSecurity {
//From build/classes: >"c:\Program Files\Java\jdk1.7.0_05\bin\javah.exe" -classpath c:\work\apache-tomcat-7.0.39\lib\servlet-api.jar;. org.modsecurity.ModSecurity //From build/classes: >"c:\Program Files\Java\jdk1.7.0_05\bin\javah.exe" -classpath c:\work\apache-tomcat-7.0.39\lib\servlet-api.jar;. org.modsecurity.ModSecurity
@ -23,14 +20,14 @@ public final class ModSecurity {
static { static {
//ModSecurityLoader calls System.load() for every native library needed by ModSecurity. //ModSecurityLoader calls System.load() for every native library needed by ModSecurity.
try { // try {
Class.forName("org.modsecurity.loader.ModSecurityLoader"); // Class.forName("org.modsecurity.loader.ModSecurityLoader");
System.out.println("ModSecurity libraries loaded."); // System.out.println("ModSecurity libraries loaded.");
} catch (ClassNotFoundException ex) { // } catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(ModSecurity.class.getName()).log(java.util.logging.Level.SEVERE, // java.util.logging.Logger.getLogger(ModSecurity.class.getName()).log(java.util.logging.Level.SEVERE,
"ModSecurityLoader was not found, please make sure that you have \"ModSecurityLoader.jar\" in your server lib folder.", ex); // "ModSecurityLoader was not found, please make sure that you have \"ModSecurityLoader.jar\" in your server lib folder.", ex);
} // }
//If the ModSecurityLoader is not used, native libraries can be loaded here, however this is bad practice since this will raise UnsatisfiedLinkError if //If the ModSecurityLoader is not used, native libraries can be loaded here, however this is bad practice since this will raise UnsatisfiedLinkError if
//ModSecurity is used in multiple webapps. This will also will raise problems when the web-app is redeployed and the server is running. //ModSecurity is used in multiple webapps. This will also will raise problems when the web-app is redeployed and the server is running.
// System.load("c:\\work\\mod_security\\java\\libs\\zlib1.dll"); // System.load("c:\\work\\mod_security\\java\\libs\\zlib1.dll");
@ -40,6 +37,19 @@ public final class ModSecurity {
// System.load("c:\\work\\mod_security\\java\\libs\\libapriconv-1.dll"); // System.load("c:\\work\\mod_security\\java\\libs\\libapriconv-1.dll");
// System.load("c:\\work\\mod_security\\java\\libs\\libaprutil-1.dll"); // System.load("c:\\work\\mod_security\\java\\libs\\libaprutil-1.dll");
// System.load("c:\\work\\mod_security\\java\\Debug\\ModSecurityJNI.dll"); // System.load("c:\\work\\mod_security\\java\\Debug\\ModSecurityJNI.dll");
try {
System.loadLibrary("zlib1"); //needed for libxml2 in Windows
} catch(UnsatisfiedLinkError ex) {
}
System.loadLibrary("libxml2");
System.loadLibrary("pcre");
System.loadLibrary("libapr-1");
try {
System.loadLibrary("libapriconv-1");
} catch(UnsatisfiedLinkError ex) { //needed for libaprutil-1 in Windows
}
System.loadLibrary("libaprutil-1");
System.loadLibrary("ModSecurityJNI");
} }
public ModSecurity(FilterConfig fc, String confFile) throws ServletException { public ModSecurity(FilterConfig fc, String confFile) throws ServletException {

View File

@ -1,7 +1,6 @@
package org.modsecurity; package org.modsecurity;
import java.io.IOException; import java.io.IOException;
import java.net.URLDecoder;
import javax.servlet.Filter; import javax.servlet.Filter;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.FilterConfig; import javax.servlet.FilterConfig;

View File

@ -491,7 +491,7 @@ public class MsHttpServletRequest extends HttpServletRequestWrapper {
*/ */
@Override @Override
public Enumeration getParameterNames() { public Enumeration getParameterNames() {
Hashtable parameterNames = new Hashtable(); Hashtable<Object, Object> parameterNames = new Hashtable<Object, Object>();
for (int i = 0, n = parameters.size(); i < n; i++) { for (int i = 0, n = parameters.size(); i < n; i++) {
Parameter p = (Parameter) parameters.get(i); Parameter p = (Parameter) parameters.get(i);
parameterNames.put(p.name, p.value); parameterNames.put(p.name, p.value);

View File

@ -25,8 +25,8 @@ public class MsHttpServletResponse extends HttpServletResponseWrapper {
private static final int INTERCEPT_OBSERVE_ONLY = 2; private static final int INTERCEPT_OBSERVE_ONLY = 2;
public static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1"; public static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";
private int interceptMode = INTERCEPT_ON; private int interceptMode = INTERCEPT_ON;
private ArrayList headers = new ArrayList(); private ArrayList<Object> headers = new ArrayList<Object>();
private ArrayList cookies = new ArrayList(); private ArrayList<Object> cookies = new ArrayList<Object>();
private int status = -1; private int status = -1;
private boolean committed = false; private boolean committed = false;
private boolean suspended = false; private boolean suspended = false;
@ -593,11 +593,11 @@ final class FastHttpDateFormat {
/** /**
* Formatter cache. * Formatter cache.
*/ */
protected static final HashMap formatCache = new HashMap(); protected static final HashMap<Object, Object> formatCache = new HashMap<Object, Object>();
/** /**
* Parser cache. * Parser cache.
*/ */
protected static final HashMap parseCache = new HashMap(); protected static final HashMap<Object, Object> parseCache = new HashMap<Object, Object>();
// --------------------------------------------------------- Public Methods // --------------------------------------------------------- Public Methods
/** /**
@ -705,7 +705,7 @@ final class FastHttpDateFormat {
/** /**
* Update cache. * Update cache.
*/ */
private static void updateCache(HashMap cache, Object key, private static void updateCache(HashMap<Object, Object> cache, Object key,
Object value) { Object value) {
if (value == null) { if (value == null) {
return; return;

View File

@ -13,7 +13,7 @@
} }
</style> </style>
</head> </head>
<body style="background: #333333;"> <body style="background: #333333;">
<div align="center" style="width:930px; margin:0 auto; box-shadow: 5px 5px 6px #000; background: #FFFFFF;"> <div align="center" style="width:930px; margin:0 auto; box-shadow: 5px 5px 6px #000; background: #FFFFFF;">
<div style="width: 930px;"> <div style="width: 930px;">
@ -39,17 +39,16 @@
</p> </p>
<br /> <br />
<h3>Installation</h3> <h2>Installation</h2>
<p> <p>
First you need to choose whether to download and compile ModSecurity from the project's version control web-site: First you need to choose whether to download and compile ModSecurity from the project's version control web-site:
<a href="https://github.com/SpiderLabs/ModSecurity">github.com/SpiderLabs/ModSecurity</a> or using pre-compiled binaries from <a href="https://github.com/SpiderLabs/ModSecurity">github.com/SpiderLabs/ModSecurity</a> or using pre-compiled binaries from
<a href="https://www.modsecurity.org/">modsecurity.org</a>. We will not discuss how to compile <a href="https://www.modsecurity.org/">modsecurity.org</a>.
the dependent native libraries needed since these steps are described in the README files from ModSecurity's repository.
The native libraries (.so, .dll, etc.) needed for <b>ModSecurity for Java</b> are: The native libraries (.so, .dll, etc.) needed for <b>ModSecurity for Java</b> are:
</p> </p>
<ol> <ol>
<li> <li>
zlib1 zlib1 (Windows only)
</li> </li>
<li> <li>
libxml2 libxml2
@ -61,25 +60,53 @@
libapr-1 libapr-1
</li> </li>
<li> <li>
libapriconv-1 libapriconv-1 (Windows only)
</li> </li>
<li> <li>
libaprutil-1 libaprutil-1
</li> </li>
<li> <li>
ModSecurityJNI ModSecurityJNI (JNI wrapper for mod_security code)
</li> </li>
</ol> </ol>
<p> <p>
These native libraries are loaded by the <span class="code">ModSecurityLoader.jar</span>, which should be placed in your Java server library loader These native libraries are used by the <a class="code" href="../src/java/org/modsecurity/ModSecurityFilter.java">ModSecurityFilter</a>.
(for example, in Tomcat 7: <span class="code">$CATALINA_HOME/lib</span>). You can build or modify the load directory of <span class="code">ModSecurityLoader</span> from
<span class="code">/mod_security/java/ModSecurityLoader/src/</span>. The libraries have to be copied in a directory (for example, <span class="code">c:\work\mod_security\java\libs\</span>),
which should be accessible to <span class="code">ModSecurityLoader.jar</span>.
</p> </p>
<br /> <br />
<h4>Java Web Applications with ModSecurity Filter</h4> <h3>Compile ModSecurity native library</h3>
<p>
Install required packages for compilation. For example, on Debian/Ubuntu like systems (Windows users have a Visual Studio solution):
</p>
<pre class="codecanvas">
sudo apt-get install g++ make automake autoconf libtool
</pre>
<p>
Install required dependent packages:
</p>
<pre class="codecanvas">
sudo apt-get install libxml2 libxml2-dev libxml2-utils libaprutil1 libaprutil1-dev apache2-prefork-dev
</pre>
<p>
Download mod_security source code from <a href="https://github.com/mihaipitu/ModSecurity">GitHub</a>, compile and install:
</p>
<pre class="codecanvas">
cd mod_security/
./autogen.sh
./configure --enable-java-module
make
</pre>
<p>
Copy compiled library in a convenient folder:
</p>
<pre class="codecanvas">
sudo cp ./java/.libs/libModSecurityJNI.so /usr/lib/
</pre>
<br />
<h3>Java Web Applications with ModSecurity Filter</h3>
<p> <p>
ModSecurity for Java uses <a href="http://www.oracle.com/technetwork/java/filters-137243.html">Java Filters</a> in order to ModSecurity for Java uses <a href="http://www.oracle.com/technetwork/java/filters-137243.html">Java Filters</a> in order to
intercept Http requests and responses. <b>ModsecurityTestApp</b> is an example of Java EE Web application using the ModSecurity intercept Http requests and responses. <b>ModsecurityTestApp</b> is an example of Java EE Web application using the ModSecurity
@ -110,15 +137,41 @@
&lt;/filter&gt; &lt;/filter&gt;
</code> </code>
</pre> </pre>
<p> <p>
The ModSecurity Filter makes use of the native libraries written in C/C++ using the JNI technology. The ModSecurity Filter makes use of the native libraries written in C/C++ using the JNI technology.
As stated earlier, the native libraries are loaded by the <span class="code">ModSecurityLoader.jar</span> There are two ways of loading native libraries by Java Web Applications:
which should be loaded by the server at start-up. If you are unable to configure the server to load the <ol>
ModSecurity libraries at startup, you may load them in your web application although this is not <li>
recommended because this will raise <span class="code">UnsatisfiedLinkError</span> if the ModSecurity <h4>Loading native libraries directly in the ModSecurityFilter</h4>
Filter is used in multiple applications within the same server. <p>
</p> Although this is the easier, this is not recommended because the JVM will raise
<span class="code">UnsatisfiedLinkError</span> if the ModSecurity Filter is used in
multiple applications within the same server.
The libraries are loaded in the <a class="code" href="../src/java/org/modsecurity/ModSecurity.java">ModSecurity</a> class using
<span class="code">System.loadLibrary()</span>. In this case the server has to be started with
the following VM options:
</p>
<pre class="codecanvas">
-Djava.library.path=/path/to/libraries/folder/
</pre>
<p>
You can specify multiple folders for the <span class="code">java.library.path</span> variable by using
: (colon) or ; (semi-colon), depending on your environment.
</p>
</li>
<li>
<h4>Loading native libraries when the Web Server starts</h4>
<p>
<a class="code" href="../../ModSecurityLoader/dist/ModSecurityLoader.jar">ModSecurityLoader.jar</a> should be placed
in the Java server library loader folder (for example, in Tomcat 7: <span class="code">$CATALINA_HOME/lib</span>).
You can build or modify the load directory of <span class="code">ModSecurityLoader</span> from
<span class="code">/mod_security/java/ModSecurityLoader/src/</span>.
</p>
</li>
</ol>
<br/> <br/>
<br/> <br/>
<br/> <br/>

View File

@ -0,0 +1,797 @@
#undef inline
#define inline __inline
#include "org_modsecurity_ModSecurity.h"
#include "api.h"
#include <math.h>
#define MODSECURITY_JAVACLASS "org/modsecurity/ModSecurity"
#define SERVLETINPUTSTREAM_JAVACLASS "javax/servlet/ServletInputStream"
#define TOSTRING_MET "toString"
#define STRINGRETURN_SIG "()Ljava/lang/String;"
#define INPUTSTREAM_READ_MET "read"
#define INPUTSTREAM_READ_SIG "([BII)I"
#define MODSECURITY_LOG_MET "log"
#define MODSECURITY_LOG_SIG "(ILjava/lang/String;)V"
#define MODSECURITY__HTTPREQHEADERS_MET "getHttpRequestHeaders"
#define MODSECURITY__HTTPREQHEADERS_SIG "(Ljavax/servlet/http/HttpServletRequest;)[[Ljava/lang/String;"
#define MODSECURITY__HTTPRESHEADERS_MET "getHttpResponseHeaders"
#define MODSECURITY__HTTPRESHEADERS_SIG "(Ljavax/servlet/http/HttpServletResponse;)[[Ljava/lang/String;"
#define MODSECURITY__ISPV6_MET "isIPv6"
#define MODSECURITY__ISPV6_SIG "(Ljava/lang/String;)Z"
#define HTTPTRANSACTION_HTTPREQUEST_MET "getHttpRequest"
#define HTTPTRANSACTION_HTTPREQUEST_SIG "()Ljavax/servlet/http/HttpServletRequest;"
#define HTTPTRANSACTION_MSHTTPREQUEST_MET "getMsHttpRequest"
#define HTTPTRANSACTION_MSHTTPREQUEST_SIG "()Lorg/modsecurity/MsHttpServletRequest;"
#define HTTPTRANSACTION_MSHTTPRESPONSE_MET "getMsHttpResponse"
#define HTTPTRANSACTION_MSHTTPRESPONSE_SIG "()Lorg/modsecurity/MsHttpServletResponse;"
#define HTTPTRANSACTION_TRANSACTIONID_MET "getTransactionID"
#define SERVLETREQUEST_SERVERNAME_MET "getServerName"
#define SERVLETREQUEST_CHARENCODING_MET "getCharacterEncoding"
#define SERVLETREQUEST_CONTENTTYPE_MET "getContentType"
#define SERVLETREQUEST_SERVERPORT_MET "getServerPort"
#define SERVLETREQUEST_SERVERPORT_SIG "()I"
#define SERVLETREQUEST_REMOTEADDR_MET "getRemoteAddr"
#define SERVLETREQUEST_INPUTSTREAM_MET "getInputStream"
#define SERVLETREQUEST_INPUTSTREAM_SIG "()Ljavax/servlet/ServletInputStream;"
#define HTTPSERVLETREQUEST_PATHINFO_MET "getPathInfo"
#define HTTPSERVLETREQUEST_QUERYSTRING_MET "getQueryString"
#define HTTPSERVLETREQUEST_METHOD_MET "getMethod"
#define HTTPSERVLETREQUEST_PROTOCOL_MET "getProtocol"
#define HTTPSERVLETREQUEST_REQUESTURL_MET "getRequestURL"
#define HTTPSERVLETREQUEST_REQUESTURL_SIG "()Ljava/lang/StringBuffer;"
#define MSHTTPSERVLETREQUEST_READBODY_MET "readBody"
#define MSHTTPSERVLETREQUEST_READBODY_SIG "(I)V"
#define MSHTTPSERVLETREQUEST_SETBODY_MET "setBodyBytes"
#define MSHTTPSERVLETREQUEST_SETBODY_SIG "([B)V"
#define SERVLETRESPONSE_CONTENTTYPE_MET "getContentType"
#define SERVLETRESPONSE_CHARENCODING_MET "getCharacterEncoding"
#define MSSERVLETRESPONSE_OUTPUTSTREAM_MET "getByteArrayStream"
#define MSSERVLETRESPONSE_OUTPUTSTREAM_SIG "()Ljava/io/ByteArrayInputStream;"
//typedef struct {
JavaVM *jvm;
jobject modSecurityInstance;
directory_config *config;
//} JavaModSecurityContext;
jmethodID logMethod;
apr_table_t *requests;
apr_pool_t *requestsPool;
char *serverHostname;
#define JAVASERVLET_INSTREAM "MSReqBStr"
#define JAVASERVLET_OUTSTREAM "MSResBStr"
#define JAVASERVLET_TRANSACTION "MSTran"
void storeJavaServletContext(request_rec *r, const char *key, jobject obj)
{
apr_table_setn(r->notes, key, (const char *)obj);
}
void removeJavaServletContext(request_rec *r, const char *key)
{
apr_table_unset(r->notes, key);
}
jobject getJavaServletContext(request_rec *r, const char *key)
{
jobject obj = NULL;
request_rec *rx = NULL;
/* Look in the current request first. */
obj = (jobject)apr_table_get(r->notes, key);
if (obj != NULL)
return obj;
/* If this is a subrequest then look in the main request. */
if (r->main != NULL)
{
obj = (jobject)apr_table_get(r->main->notes, key);
if (obj != NULL)
{
return obj;
}
}
/* If the request was redirected then look in the previous requests. */
rx = r->prev;
while(rx != NULL)
{
obj = (jobject)apr_table_get(rx->notes, key);
if (obj != NULL)
{
return obj;
}
rx = rx->prev;
}
return NULL;
}
apr_sockaddr_t *CopySockAddr(jclass msClass, JNIEnv *env, apr_pool_t *pool, char *addrstr, jstring addrStrJstr)
{
jmethodID isIPv6Met = (*env)->GetStaticMethodID(env, msClass, MODSECURITY__ISPV6_MET, MODSECURITY__ISPV6_SIG);
jboolean isIPv6 = (*env)->CallStaticBooleanMethod(env, msClass, isIPv6Met, addrStrJstr);
apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t));
int adrlen = 16, iplen = 4;
if(isIPv6)
{
adrlen = 46;
iplen = 16;
addr->family = AF_INET6;
}
else
addr->family = AF_INET;
addr->addr_str_len = adrlen;
addr->hostname = (char*) "unknown";
#ifdef WIN32
addr->ipaddr_len = sizeof(IN_ADDR);
#else
addr->ipaddr_len = sizeof(struct in_addr);
#endif
addr->ipaddr_ptr = &addr->sa.sin.sin_addr;
addr->pool = pool;
addr->port = 80;
#ifdef WIN32
memcpy(&addr->sa.sin.sin_addr.S_un.S_addr, addrstr, iplen);
#else
memcpy(&addr->sa.sin.sin_addr.s_addr, addrstr, iplen);
#endif
addr->sa.sin.sin_family = addr->family;
addr->sa.sin.sin_port = 80;
addr->salen = sizeof(addr->sa);
addr->servname = addr->hostname;
return addr;
}
inline char* fromJString(JNIEnv *env, jstring jStr, apr_pool_t *pool)
{
char *str;
if (jStr != NULL)
{
const char *jCStr = (*env)->GetStringUTFChars(env, jStr, NULL);
int len = strlen(jCStr);
str = (char*) apr_palloc(pool, len + 1);
memcpy(str, jCStr, len);
str[len] = '\0'; //null terminate
(*env)->ReleaseStringUTFChars(env, jStr, jCStr); //release java memory
}
else
str = (char*) "";
return str;
}
inline char* fromJStringMethod(JNIEnv *env, jmethodID method, jobject obj, apr_pool_t *pool)
{
jstring jStr = (jstring) (*env)->CallObjectMethod(env, obj, method);
return fromJString(env, jStr, pool);
}
void logSec(void *obj, int level, char *str)
{
JNIEnv *env;
jstring jStr;
if (!(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL)) //get the Enviroment from the JavaVM
{
jStr = (*env)->NewStringUTF(env, str);
(*env)->CallVoidMethod(env, modSecurityInstance, logMethod, level, jStr);
(*jvm)->DetachCurrentThread(jvm);
//in the context of a JVM thread, any leaked local references are automatically cleaned up
//(*env)->ReleaseStringUTFChars(jStr, str);
}
}
apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
{
jobject inputStream = getJavaServletContext(r, JAVASERVLET_INSTREAM); //servlet request input stream
JNIEnv *env;
*readcnt = 0;
if(inputStream == NULL)
{
*is_eos = 1;
return APR_SUCCESS;
}
if (!(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL))
{
//read request body from the servlet input stream using 'read' method
jclass inputStreamClass = (*env)->FindClass(env, SERVLETINPUTSTREAM_JAVACLASS);
jmethodID read = (*env)->GetMethodID(env, inputStreamClass, INPUTSTREAM_READ_MET, INPUTSTREAM_READ_SIG);
jbyteArray byteArrayBuf = (*env)->NewByteArray(env, length);
jint count = (*env)->CallIntMethod(env, inputStream, read, byteArrayBuf, 0, length);
jbyte* bufferPtr = (*env)->GetByteArrayElements(env, byteArrayBuf, NULL);
if (count == -1 || count > length || (*env)->ExceptionCheck(env) == JNI_TRUE) //end of stream
{
*is_eos = 1;
}
else
{
*readcnt = count;
memcpy(buf, bufferPtr, *readcnt);
}
(*env)->ReleaseByteArrayElements(env, byteArrayBuf, bufferPtr, 0);
(*env)->DeleteLocalRef(env, byteArrayBuf);
(*jvm)->DetachCurrentThread(jvm);
}
return APR_SUCCESS;
}
apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
{
jobject httpTransaction;
JNIEnv *env;
jclass httpTransactionClass;
jmethodID getHttpRequest;
jobject httpServletRequest;
jclass httpServletRequestClass;
jmethodID setBodyBytes;
jbyte *jbuf;
int i;
jbyteArray byteArrayBuf;
httpTransaction = getJavaServletContext(r, JAVASERVLET_TRANSACTION);
if(httpTransaction == NULL)
{
return APR_SUCCESS;
}
if (!(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL))
{
httpTransactionClass = (*env)->GetObjectClass(env, httpTransaction);
getHttpRequest = (*env)->GetMethodID(env, httpTransactionClass, HTTPTRANSACTION_MSHTTPREQUEST_MET, HTTPTRANSACTION_MSHTTPREQUEST_SIG);
httpServletRequest = (*env)->CallObjectMethod(env, httpTransaction, getHttpRequest);
httpServletRequestClass = (*env)->GetObjectClass(env, httpServletRequest);
setBodyBytes = (*env)->GetMethodID(env, httpServletRequestClass, MSHTTPSERVLETREQUEST_SETBODY_MET, MSHTTPSERVLETREQUEST_SETBODY_SIG);
jbuf = (jbyte*) apr_palloc(requestsPool, sizeof(jbyte) * length);
for (i = 0; i < length; i++)
jbuf[i] = buf[i];
byteArrayBuf = (*env)->NewByteArray(env, length);
(*env)->SetByteArrayRegion(env, byteArrayBuf, 0, length, jbuf);
//on setBodyBytes we copy buf bytes
(*env)->CallVoidMethod(env, httpServletRequest, setBodyBytes, byteArrayBuf);
//(*env)->ReleaseByteArrayElements(byteArrayBuf, jbuf, NULL);
(*jvm)->DetachCurrentThread(jvm);
}
return APR_SUCCESS;
}
apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
{
jobject inputStream;
JNIEnv *env;
jclass inputStreamClass;
jmethodID read;
jbyteArray byteArrayBuf;
jint count;
jbyte* bufferPtr;
inputStream = getJavaServletContext(r, JAVASERVLET_OUTSTREAM);
*readcnt = 0;
if(inputStream == NULL)
{
*is_eos = 1;
return APR_SUCCESS;
}
if (!(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL))
{
inputStreamClass = (*env)->GetObjectClass(env, inputStream);
read = (*env)->GetMethodID(env, inputStreamClass, INPUTSTREAM_READ_MET, INPUTSTREAM_READ_SIG);
byteArrayBuf = (*env)->NewByteArray(env, length);
count = (*env)->CallIntMethod(env, inputStream, read, byteArrayBuf, 0, length);
bufferPtr = (*env)->GetByteArrayElements(env, byteArrayBuf, NULL);
if (count == -1 || count > length || (*env)->ExceptionCheck(env) == JNI_TRUE) //end of stream
{
*is_eos = 1;
}
else
{
*readcnt = count;
memcpy(buf, bufferPtr, *readcnt);
}
(*env)->ReleaseByteArrayElements(env, byteArrayBuf, bufferPtr, 0);
(*env)->DeleteLocalRef(env, byteArrayBuf);
(*jvm)->DetachCurrentThread(jvm);
}
return APR_SUCCESS;
}
apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int length)
{
JNIEnv *env;
jbyteArray byteArrayBuf;
jclass httpTransactionClass;
jmethodID getHttpResponse;
jobject httpServletResponse;
jbyte *jbuf;
int i;
jmethodID setBodyBytes;
jclass httpServletResponseClass;
jobject httpTransaction = getJavaServletContext(r, JAVASERVLET_TRANSACTION);
if(httpTransaction == NULL)
{
(*jvm)->DetachCurrentThread(jvm);
return APR_SUCCESS;
}
if (!(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL))
{
httpTransactionClass = (*env)->GetObjectClass(env, httpTransaction);
getHttpResponse = (*env)->GetMethodID(env, httpTransactionClass, HTTPTRANSACTION_MSHTTPRESPONSE_MET, HTTPTRANSACTION_MSHTTPRESPONSE_SIG);
httpServletResponse = (*env)->CallObjectMethod(env, httpTransaction, getHttpResponse);
httpServletResponseClass = (*env)->GetObjectClass(env, httpServletResponse);
setBodyBytes = (*env)->GetMethodID(env, httpServletResponseClass, MSHTTPSERVLETREQUEST_SETBODY_MET, MSHTTPSERVLETREQUEST_SETBODY_SIG);
jbuf = (jbyte*) apr_palloc(requestsPool, sizeof(jbyte) * length);
for (i = 0; i < length; i++)
jbuf[i] = buf[i];
byteArrayBuf = (*env)->NewByteArray(env, length);
(*env)->SetByteArrayRegion(env, byteArrayBuf, 0, length, jbuf);
//on setBodyBytes we copy buf bytes
(*env)->CallVoidMethod(env, httpServletResponse, setBodyBytes, byteArrayBuf);
//(*env)->ReleaseByteArrayElements(byteArrayBuf, jbuf, NULL);
(*jvm)->DetachCurrentThread(jvm);
}
return APR_SUCCESS;
}
JNIEXPORT jint JNICALL Java_org_modsecurity_ModSecurity_initialize(JNIEnv *env, jobject obj, jstring serverName)
{
(*env)->GetJavaVM(env, &jvm);
modSecurityInstance = (*env)->NewGlobalRef(env, obj); //Save the ModSecurity object for further use
logMethod = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, obj), MODSECURITY_LOG_MET, MODSECURITY_LOG_SIG); //log method ID
modsecSetLogHook(NULL, logSec);
modsecSetReadBody(ReadBodyCallback);
modsecSetReadResponse(ReadResponseCallback);
modsecSetWriteBody(WriteBodyCallback);
modsecSetWriteResponse(WriteResponseCallback);
modsecInit();
modsecStartConfig();
config = modsecGetDefaultConfig();
modsecFinalizeConfig();
modsecInitProcess();
config = NULL;
//table for requests
apr_pool_create(&requestsPool, NULL);
requests = apr_table_make(requestsPool, 10);
serverHostname = fromJString(env, serverName, requestsPool);
return APR_SUCCESS;
}
JNIEXPORT jint JNICALL Java_org_modsecurity_ModSecurity_destroy(JNIEnv *env, jobject obj)
{
(*env)->DeleteGlobalRef(env, modSecurityInstance);
apr_pool_destroy(requestsPool);
modsecTerminate();
return APR_SUCCESS;
}
inline void setHeaders(JNIEnv *env, jclass httpServletRequestClass, jobject httpServletR, apr_table_t *reqHeaders, apr_pool_t *pool, const char *headersMet, const char *headersSig)
{
jmethodID getHttpHeaders;
jobjectArray headersTable;
jsize size;
int i;
//All headers are returned in a table by a static method from ModSecurity class
getHttpHeaders = (*env)->GetStaticMethodID(env, httpServletRequestClass, headersMet, headersSig);
headersTable = (jobjectArray) (*env)->CallStaticObjectMethod(env, httpServletRequestClass, getHttpHeaders, httpServletR);
size = (*env)->GetArrayLength(env, headersTable);
for (i = 0; i < size; i++)
{
const char *headerName;
const char *headerValue;
jobjectArray row = (jobjectArray) (*env)->GetObjectArrayElement(env, headersTable, i);
jstring headerNameJStr = (jstring) (*env)->GetObjectArrayElement(env, row, 0);
jstring headerValueJStr = (jstring) (*env)->GetObjectArrayElement(env, row, 1);
if (headerNameJStr != NULL && headerValueJStr != NULL)
{
headerName = fromJString(env, headerNameJStr, pool);
//apr_pool_cleanup_register(r->pool, headerName, memCleanup, apr_pool_cleanup_null);
headerValue = fromJString(env, headerValueJStr, pool);
//apr_pool_cleanup_register(r->pool, headerValue, memCleanup, apr_pool_cleanup_null);
apr_table_setn(reqHeaders, headerName, headerValue);
(*env)->DeleteLocalRef(env, headerNameJStr);
(*env)->DeleteLocalRef(env, headerValueJStr);
}
}
}
JNIEXPORT jint JNICALL Java_org_modsecurity_ModSecurity_onRequest(JNIEnv *env, jobject obj, jstring configPath, jobject httpTransaction, jboolean reloadConfig)
{
conn_rec *c;
request_rec *r;
const char *err;
jmethodID getHttpRequest;
jclass httpTransactionClass;
jobject httpServletRequest;
jobject servletRequest;
jclass httpServletRequestClass;
jclass servletRequestClass;
jclass modSecurityClass;
jmethodID readBody;
jmethodID getTransactionID;
jmethodID getInputStream;
const char *reqID;
jobject inputStream;
jmethodID getServerName;
jmethodID getServerPort;
int port;
char *port_str;
jmethodID getPathInfo;
jmethodID getQueryString;
jmethodID getCharacterEncoding;
jmethodID getContentType;
const char *lng;
jmethodID getMethod;
const char* method;
jmethodID getProtocol;
jmethodID getRequestURL;
jobject stringBuffer;
jmethodID toStringBuff;
char *url;
jmethodID getRemoteAddr;
jstring remoteAddrJStr;
char *remoteAddr;
int status;
int len;
if (config == NULL || reloadConfig)
{
const char *path;
config = modsecGetDefaultConfig();
path = fromJString(env, configPath, config->mp); //path to modsecurity.conf
err = modsecProcessConfig(config, path, NULL);
if(err != NULL)
{
logSec(NULL, 0, (char*)err);
return DONE;
}
}
c = modsecNewConnection();
modsecProcessConnection(c);
r = modsecNewRequest(c, config);
r->server->server_hostname = serverHostname;
httpTransactionClass = (*env)->GetObjectClass(env, httpTransaction);
getHttpRequest = (*env)->GetMethodID(env, httpTransactionClass, HTTPTRANSACTION_MSHTTPREQUEST_MET, HTTPTRANSACTION_MSHTTPREQUEST_SIG);
httpServletRequest = (*env)->CallObjectMethod(env, httpTransaction, getHttpRequest);
servletRequest = httpServletRequest; //superclass of HttpServletRequest
httpServletRequestClass = (*env)->GetObjectClass(env, httpServletRequest); //MsHttpServletRequest interface
servletRequestClass = (*env)->GetObjectClass(env, servletRequest); //ServletRequest interface
modSecurityClass = (*env)->GetObjectClass(env, obj); //ModSecurity class
//readBody method reads all bytes from the inputStream or a maximum of 'config->reqbody_limit' bytes
readBody = (*env)->GetMethodID(env, httpServletRequestClass, MSHTTPSERVLETREQUEST_READBODY_MET, MSHTTPSERVLETREQUEST_READBODY_SIG);
(*env)->CallVoidMethod(env, httpServletRequest, readBody, config->reqbody_limit);
if ((*env)->ExceptionCheck(env) == JNI_TRUE) //read body raised an Exception, return to JVM
{
modsecFinishRequest(r);
return DONE;
}
getTransactionID = (*env)->GetMethodID(env, httpTransactionClass, HTTPTRANSACTION_TRANSACTIONID_MET, STRINGRETURN_SIG);
reqID = fromJStringMethod(env, getTransactionID, httpTransaction, r->pool); //fromJString(env, requestID, r->pool); //unique ID of this request
apr_table_setn(requests, reqID, (const char*) r); //store this request for response processing
getInputStream = (*env)->GetMethodID(env, httpServletRequestClass, SERVLETREQUEST_INPUTSTREAM_MET, SERVLETREQUEST_INPUTSTREAM_SIG);
inputStream = (*env)->CallObjectMethod(env, httpServletRequest, getInputStream); //Request body input stream used in the read body callback
storeJavaServletContext(r, JAVASERVLET_INSTREAM, inputStream);
storeJavaServletContext(r, JAVASERVLET_TRANSACTION, httpTransaction);
getServerName = (*env)->GetMethodID(env, servletRequestClass, SERVLETREQUEST_SERVERNAME_MET, STRINGRETURN_SIG);
r->hostname = fromJStringMethod(env, getServerName, servletRequest, r->pool);
getServerPort = (*env)->GetMethodID(env, servletRequestClass, SERVLETREQUEST_SERVERPORT_MET, SERVLETREQUEST_SERVERPORT_SIG);
port = (*env)->CallIntMethod(env, servletRequest, getServerPort); //server port
port_str = apr_itoa(r->pool, port);
getPathInfo = (*env)->GetMethodID(env, httpServletRequestClass, HTTPSERVLETREQUEST_PATHINFO_MET, STRINGRETURN_SIG);
r->path_info = fromJStringMethod(env, getPathInfo, httpServletRequest, r->pool);
getQueryString = (*env)->GetMethodID(env, httpServletRequestClass, HTTPSERVLETREQUEST_QUERYSTRING_MET, STRINGRETURN_SIG);
r->args = fromJStringMethod(env, getQueryString, httpServletRequest, r->pool);
setHeaders(env, httpServletRequestClass, httpServletRequest, r->headers_in, r->pool, MODSECURITY__HTTPREQHEADERS_MET, MODSECURITY__HTTPREQHEADERS_SIG);
getCharacterEncoding = (*env)->GetMethodID(env, servletRequestClass, SERVLETREQUEST_CHARENCODING_MET, STRINGRETURN_SIG);
r->content_encoding = fromJStringMethod(env, getCharacterEncoding, servletRequest, r->pool);
getContentType = (*env)->GetMethodID(env, servletRequestClass, SERVLETREQUEST_CONTENTTYPE_MET, STRINGRETURN_SIG);
r->content_type = fromJStringMethod(env, getContentType, servletRequest, r->pool);
lng = apr_table_get(r->headers_in, "Content-Languages");
if(lng != NULL)
{
r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
*(const char **)apr_array_push(r->content_languages) = lng;
}
getMethod = (*env)->GetMethodID(env, httpServletRequestClass, HTTPSERVLETREQUEST_METHOD_MET, STRINGRETURN_SIG);
method = fromJStringMethod(env, getMethod, httpServletRequest, r->pool);
//#define SETMETHOD(m) if(strcmp(method,#m) == 0){ r->method = method; r->method_number = M_##m; }
r->method = "INVALID";
r->method_number = M_INVALID;
//might be faster with elseif
if (strcmp(method, "OPTIONS") == 0) { r->method = method; r->method_number = M_OPTIONS; }
else if (strcmp(method, "GET") == 0) { r->method = method; r->method_number = M_GET; }
else if (strcmp(method, "POST") == 0) { r->method = method; r->method_number = M_POST; }
else if (strcmp(method, "PUT") == 0) { r->method = method; r->method_number = M_PUT; }
else if (strcmp(method, "DELETE") == 0) { r->method = method; r->method_number = M_DELETE; }
else if (strcmp(method, "TRACE") == 0) { r->method = method; r->method_number = M_TRACE; }
else if (strcmp(method, "CONNECT") == 0) { r->method = method; r->method_number = M_CONNECT; }
else if (strcmp(method, "MOVE") == 0) { r->method = method; r->method_number = M_MOVE; }
else if (strcmp(method, "COPY") == 0) { r->method = method; r->method_number = M_COPY; }
else if (strcmp(method, "PROPFIND") == 0) { r->method = method; r->method_number = M_PROPFIND; }
else if (strcmp(method, "PROPPATCH") == 0) { r->method = method; r->method_number = M_PROPPATCH; }
else if (strcmp(method, "MKCOL") == 0) { r->method = method; r->method_number = M_MKCOL; }
else if (strcmp(method, "LOCK") == 0) { r->method = method; r->method_number = M_LOCK; }
else if (strcmp(method, "UNLOCK") == 0) { r->method = method; r->method_number = M_UNLOCK; }
getProtocol = (*env)->GetMethodID(env, httpServletRequestClass, HTTPSERVLETREQUEST_PROTOCOL_MET, STRINGRETURN_SIG);
r->protocol = fromJStringMethod(env, getProtocol, httpServletRequest, r->pool);
r->request_time = apr_time_now();
r->parsed_uri.scheme = (char*) "http";
r->parsed_uri.path = r->path_info;
r->parsed_uri.hostname = (char *)r->hostname;
r->parsed_uri.is_initialized = 1;
r->parsed_uri.port = port;
r->parsed_uri.port_str = port_str;
r->parsed_uri.query = r->args;
r->parsed_uri.dns_looked_up = 0;
r->parsed_uri.dns_resolved = 0;
r->parsed_uri.password = NULL;
r->parsed_uri.user = NULL;
r->parsed_uri.fragment = NULL;
//the request Url is in a StringBuffer object
getRequestURL = (*env)->GetMethodID(env, httpServletRequestClass, HTTPSERVLETREQUEST_REQUESTURL_MET, HTTPSERVLETREQUEST_REQUESTURL_SIG);
stringBuffer = (*env)->CallObjectMethod(env, httpServletRequest, getRequestURL);
if (stringBuffer != NULL)
{
toStringBuff = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, stringBuffer), TOSTRING_MET, STRINGRETURN_SIG);
url = fromJStringMethod(env, toStringBuff, stringBuffer, r->pool);
if (strcmp(r->args, "") != 0)
{
len = strlen(url) + 1 + strlen(r->args) + 1;
r->unparsed_uri = (char*)apr_palloc(r->pool, len); //unparsed uri with full query
strcpy(r->unparsed_uri, url);
strcat(r->unparsed_uri, "?");
strcat(r->unparsed_uri, r->args);
r->unparsed_uri[len] = 0;
}
else
{
r->unparsed_uri = url;
}
r->uri = r->unparsed_uri;
}
len = strlen(r->method) + 1 + strlen(r->uri) + 1 + strlen(r->protocol) + 1;
r->the_request = (char *)apr_palloc(r->pool, len);
strcpy(r->the_request, r->method);
strcat(r->the_request, " ");
strcat(r->the_request, r->uri);
strcat(r->the_request, " ");
strcat(r->the_request, r->protocol);
r->the_request[len] = 0;
apr_table_setn(r->subprocess_env, "UNIQUE_ID", reqID);
getRemoteAddr = (*env)->GetMethodID(env, servletRequestClass, SERVLETREQUEST_REMOTEADDR_MET, STRINGRETURN_SIG);
remoteAddrJStr = (jstring) (*env)->CallObjectMethod(env, servletRequest, getRemoteAddr);
remoteAddr = fromJString(env, remoteAddrJStr, r->pool);
//apr_pool_cleanup_register(r->pool, remoteAddr, memCleanup, apr_pool_cleanup_null);
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
c->remote_addr = CopySockAddr(modSecurityClass, env, r->pool, remoteAddr, remoteAddrJStr);
c->remote_ip = remoteAddr;
#else
c->client_addr = CopySockAddr(modSecurityClass, env, r->pool, remoteAddr, remoteAddrJStr);
c->client_ip = remoteAddr;
#endif
c->remote_host = NULL;
status = modsecProcessRequest(r);
removeJavaServletContext(r, JAVASERVLET_INSTREAM);
removeJavaServletContext(r, JAVASERVLET_TRANSACTION);
if (status != DECLINED) //Java modsecurityFilter blocks the request, onResponse will not be called, it's safe to finish the request
{
apr_table_unset(requests, reqID);
modsecFinishRequest(r);
}
return status;
}
JNIEXPORT jint JNICALL Java_org_modsecurity_ModSecurity_onResponse(JNIEnv *env, jobject obj, jobject httpTransaction)
{
jclass httpTransactionClass;
jmethodID getTransactionID;
jstring reqIDjStr;
const char *reqID;
request_rec *r;
jmethodID getHttpResponse;
jobject httpServletResponse;
jclass httpServletResponseClass;
jmethodID getOutputStream;
jobject responseStream;
jmethodID getContentType;
jmethodID getCharEncoding;
char *ct;
const char *lng;
int status;
httpTransactionClass = (*env)->GetObjectClass(env, httpTransaction);
getTransactionID = (*env)->GetMethodID(env, httpTransactionClass, HTTPTRANSACTION_TRANSACTIONID_MET, STRINGRETURN_SIG);
reqIDjStr = (jstring) (*env)->CallObjectMethod(env, httpTransaction, getTransactionID);
reqID = (*env)->GetStringUTFChars(env, reqIDjStr, NULL);
r = (request_rec*) apr_table_get(requests, reqID);
apr_table_unset(requests, reqID); //remove this request from the requests table
(*env)->ReleaseStringUTFChars(env, reqIDjStr, reqID);
if (r == NULL)
{
return DONE;
}
getHttpResponse = (*env)->GetMethodID(env, httpTransactionClass, HTTPTRANSACTION_MSHTTPRESPONSE_MET, HTTPTRANSACTION_MSHTTPRESPONSE_SIG);
httpServletResponse = (*env)->CallObjectMethod(env, httpTransaction, getHttpResponse);
httpServletResponseClass = (*env)->GetObjectClass(env, httpServletResponse); //MsHttpServletResponse class
//jclass modSecurityClass = (*env)->GetObjectClass(obj); //ModSecurity class
getOutputStream = (*env)->GetMethodID(env, httpServletResponseClass, MSSERVLETRESPONSE_OUTPUTSTREAM_MET, MSSERVLETRESPONSE_OUTPUTSTREAM_SIG);
responseStream = (*env)->CallObjectMethod(env, httpServletResponse, getOutputStream); //Response output stream used in the read response callback
if ((*env)->ExceptionCheck(env) == JNI_TRUE)
{
modsecFinishRequest(r);
return DONE;
}
storeJavaServletContext(r, JAVASERVLET_TRANSACTION, httpTransaction);
storeJavaServletContext(r, JAVASERVLET_OUTSTREAM, responseStream);
getContentType = (*env)->GetMethodID(env, httpServletResponseClass, SERVLETRESPONSE_CONTENTTYPE_MET, STRINGRETURN_SIG);
ct = fromJStringMethod(env, getContentType, httpServletResponse, r->pool);
if(strcmp(ct, "") == 0)
ct = (char*) "text/html";
r->content_type = ct;
getCharEncoding = (*env)->GetMethodID(env, httpServletResponseClass, SERVLETRESPONSE_CHARENCODING_MET, STRINGRETURN_SIG);
r->content_encoding = fromJStringMethod(env, getCharEncoding, httpServletResponse, r->pool);
setHeaders(env, httpServletResponseClass, httpServletResponse, r->headers_out, r->pool, MODSECURITY__HTTPRESHEADERS_MET, MODSECURITY__HTTPRESHEADERS_SIG);
lng = apr_table_get(r->headers_out, "Content-Languages");
if(lng != NULL)
{
r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
*(const char **)apr_array_push(r->content_languages) = lng;
}
status = modsecProcessResponse(r);
removeJavaServletContext(r, JAVASERVLET_OUTSTREAM);
removeJavaServletContext(r, JAVASERVLET_TRANSACTION);
modsecFinishRequest(r);
return status;
}